traceparent) through every service invocation, so your handlers can join the distributed trace started by the calling client.
See the server tracing docs for how to configure Restate’s OTLP exporter.
Extracting trace context in a handler
When a handler is invoked, Restate forwards the trace context via attempt headers. Extract it fromctx.request().attemptHeaders and pass it to your OpenTelemetry propagator:
Why not use Node.js auto-instrumentation?
Unlike Java and Go, Node.js does have OTEL auto-instrumentation packages (e.g.@opentelemetry/auto-instrumentations-node). However, they can’t replace this pattern for two reasons:
- Restate wraps the HTTP transport. Auto-instrumentation intercepts at the raw HTTP layer, which Restate manages internally. It can’t see the logical handler invocation.
-
Durable execution means handlers replay. When Restate retries a handler, the auto-instrumentation would create a new span for each HTTP-level attempt. Extracting from
ctx.request().attemptHeadersgives you exactly one span per logical invocation, correctly positioned in the trace hierarchy regardless of retries.
Propagating context to outbound calls
When making HTTP calls insidectx.run(), inject the current context into the outgoing headers so downstream services can continue the trace: