Judgment Labs Logo
Tracing

Distributed tracing

Keep one trace connected as a request crosses services.

Distributed tracing keeps one live request in a single Judgment trace as it crosses services. It does this by propagating OpenTelemetry context between them. Use Durable work instead when a queue, retry, or human approval wait resumes the work later.

Use the same Judgment project across all services. Give each service a distinct service.name resource attribute when you initialize its tracer, not on individual spans. One trace then shows every hop while the services stay distinguishable.

Set the session ID on the upstream root before injecting the outgoing headers. The SDK includes that ID in Judgment baggage. Tracer.continue_trace() and Tracer.continueTrace() restore the baggage with the trace context, so downstream child spans inherit the same session ID automatically.

Send trace state

Inject the current trace context into the outgoing request:

from judgeval.trace.propagation import inject

headers = {}
inject(headers)
response = httpx.post(DOWNSTREAM_URL, json=payload, headers=headers)
import { propagation } from "judgeval";

const headers: Record<string, string> = {};
propagation.inject(headers);
await fetch(DOWNSTREAM_URL, { method: "POST", headers, body });

Receive trace state

Continue the trace before starting child spans. A span that starts first gets a new trace ID, which makes the request appear as two unrelated traces. Middleware is a reliable place to continue the trace because it covers every incoming request:

with Tracer.continue_trace(request.headers):
    result = handle_request(payload)
await Tracer.continueTrace(req.headers, async () => {
    return handleRequest(payload);
});

Delayed queue work needs a stable job or session ID instead of the live request's trace context. Start a new trace when the worker receives the task. See Durable work.

Verify

First run the shared verification checklist. Then send one request through both services. The downstream spans should appear under the upstream root in one trace. Two traces mean the context did not arrive or was restored after a downstream span had already started.