Sophon

Observability

Every response from /v1/* carries two correlation headers. If you wire them through your logging and tracing, debugging a streaming chat across three machines stops being a guessing game.

Headers

X-Request-ID: req_3f2a7c8e1b4d5e6f
traceparent:  00-<trace_id>-<parent_id>-<flags>
tracestate:   rojo=00f067aa0ba902b7

Three things they let you do:

  1. Correlate a server-side log line with a specific HTTP exchange the bridge made.
  2. Stitch a distributed trace across iOS → cloud → bridge → agent.
  3. Pass through opaque vendor state (Honeycomb, Sentry, Datadog…) without us inspecting it.

X-Request-ID

Identifies one HTTP exchange. Format when server-generated:

req_<16 lowercase hex>      e.g. req_3f2a7c8e1b4d5e6f

Clients may supply their own value ([A-Za-z0-9._:-]{1,64}); the server echoes it back unchanged.

The recommended pattern: every error your bridge logs should include the X-Request-ID of the failing call. When you file a bug or open a support ticket, paste it. The server has the same id in its logs and can find your exact request in seconds.

const r = await fetch(url, { ... })
if (!r.ok) {
  const reqId = r.headers.get('X-Request-ID')
  log.error({ reqId, status: r.status }, 'sophon POST failed')
}

traceparent (W3C Trace Context)

Format:

<version>-<trace_id>-<parent_id>-<flags>
00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
  • version: always 00 for v1.
  • trace_id: 32 hex chars, identifies the distributed trace.
  • parent_id: 16 hex chars, identifies this server's span inside the trace. Agents stitching their own spans below this use parent_id as their parent reference.
  • flags: 01 = sampled, 00 = not sampled.

If your bridge sends a valid inbound traceparent (you already have a span), the server keeps your trace_id and mints a new parent_id (the server is now a child of your inbound caller). If you don't send one, the server generates a fresh trace with flags=01.

tracestate

Comma-delimited list of opaque vendor state, per the W3C spec. The server passes it through verbatim — never inspects, never rewrites. If you're using Honeycomb / Datadog / Lightstep / a homegrown tracer, this is where their per-vendor context rides along.

OpenTelemetry pass-through

If your bridge already runs an OTel SDK, you get distributed traces for free. The HTTP client should:

  • Inject traceparent / tracestate outbound on every Sophon request.
  • Extract the returned traceparent and attach it as a span link on the outgoing request span.

Most OTel HTTP instrumentations do both automatically. With Pino, Sentry, or a homegrown logger, just thread the X-Request-ID and traceparent into your structured log record and you're done.

Server-side logging hooks

Server logs include the same request_id and trace_id on every line that handled the request. When you ping the team with a bug:

Bridge call to /v1/bridge/createTask returned 500. X-Request-ID: req_3f2a7c8e1b4d5e6f, traceparent: 00-4bf9…-00f0…-01.

…we have everything we need to find the line and the upstream context.

What we don't do

  • We do not sniff your tracestate.
  • We do not persist X-Request-ID beyond the standard log retention window.
  • We do not require traceparent to be present — you're perfectly fine sending none, you just lose the cross-system view.