Sign In

Distributed Tracing

Every outbound request from the SDK carries a traceparent header so server-side spans stitch directly into your distributed-tracing graph — whether you run Datadog, OpenTelemetry, Jaeger, Tempo, or Grafana Cloud Traces.

Available from SDK 1.2.0. No configuration is required — the header is added automatically, even without OpenTelemetry installed.

#The header

The SDK emits the W3C Trace-Context format on every call:

traceparent: 00-<32-hex-trace-id>-<16-hex-span-id>-01
# example: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01

#Resolution order

  1. Caller-supplied traceparent wins. The SDK never overwrites a header that you passed in headers=. Case-insensitive match, so both traceparent and TraceParent are detected.
  2. OpenTelemetry active span. If opentelemetry is importable and a recording span is live on the current context, the SDK delegates to opentelemetry.propagate.inject()— the header matches the runtime tracer's sampling decision and may also carry a tracestate.
  3. Standalone fallback. When no OTel context exists, the SDK synthesises a W3C-compliant traceparent with 128-bit random trace-id and 64-bit random span-id (via secrets.token_hex). The server still gets a stable correlation id for its logs.

#Integrating with OpenTelemetry

No instrumentation library is required. Simply start a span before the SDK call — the SDK picks it up automatically.

from opentelemetry import trace
from radmah_sdk import RadMahClient

tracer = trace.get_tracer("my-app")
client = RadMahClient(api_key="sl_live_…")

with tracer.start_as_current_span("submit-synthesis-job") as span:
    span.set_attribute("tenant.plan", "enterprise")
    job = client.jobs.create(seal_id="seal_…", engine="mock", rows=10_000)
    span.set_attribute("radmah.job_id", job.id)
    # The server-side span for POST /v1/client/jobs/ is a child of
    # submit-synthesis-job in your APM, no further wiring required.

#Supplying your own trace id

If your service has an existing correlation scheme and you want the server to log your id rather than OTel's, pass the header directly:

caller_tp = f"00-{your_trace_id}-{your_span_id}-01"
client._get("/v1/client/jobs/", headers={"traceparent": caller_tp})
Retry attempts reuse the same traceparent so server-side logs can stitch all attempts of one logical call together.

#Failure modes

  • If opentelemetry raises duringpropagate.inject() — a broken instrumentation install, a misconfigured SDK, a noop tracer — the SDK catches the exception silently and falls back to the standalone generator. Outbound requests are never blocked by OTel failures.
  • If the server rejects the header (shouldn't happen — the platform parses W3C format only), the request still proceeds. The header is informational, never load-bearing for authentication.