❯ when running OTel, if I call a child process, should I also send env vars to
them, so they can also trace?
⏺ Yes — OTel context propagation across process boundaries requires passing the
trace context via environment variables (or another mechanism like HTTP
headers).
The standard approach is to use the W3C TraceContext propagation format.
Before spawning the child, serialize the current span context:
import { propagation, context } from '@opentelemetry/api';
const carrier: Record<string, string> = {};
propagation.inject(context.active(), carrier);
// carrier now has: { traceparent: '00-<traceId>-<spanId>-01', tracestate:
'...' }
spawn('child-process', args, {
env: { ...process.env, ...carrier },
});
In the child process, extract and restore the context:
import { propagation, context, trace } from '@opentelemetry/api';
const carrier = {
traceparent: process.env['traceparent'],
tracestate: process.env['tracestate'],
};
const ctx = propagation.extract(context.active(), carrier);
// Now start spans under the restored parent context
const tracer = trace.getTracer('child');
tracer.startActiveSpan('child-work', {}, ctx, (span) => {
// ...
span.end();
});
Key points:
- The traceparent header carries the trace/span ID and sampling flag — without
it, the child starts a disconnected root span.
- tracestate carries vendor-specific data and should also be forwarded.
- The child still needs its own OTel SDK initialized with an exporter —
propagation only links the spans, it doesn't tunnel telemetry through the
parent.
- If the child is short-lived, make sure it flushes before exit
(provider.shutdown()), otherwise spans may be dropped.
When running under OpenTelemetry, there are some environment variables such as
OTEL_SERVICE_NAMEto propagate, but we also make sure that we're propagating the trace parent + state, so we have more in-depth tracing.Potentially via:
Claude Sonnet 4.6 thoughts
❯ when running OTel, if I call a child process, should I also send env vars to them, so they can also trace? ⏺ Yes — OTel context propagation across process boundaries requires passing the trace context via environment variables (or another mechanism like HTTP headers). The standard approach is to use the W3C TraceContext propagation format. Before spawning the child, serialize the current span context: import { propagation, context } from '@opentelemetry/api'; const carrier: Record<string, string> = {}; propagation.inject(context.active(), carrier); // carrier now has: { traceparent: '00-<traceId>-<spanId>-01', tracestate: '...' } spawn('child-process', args, { env: { ...process.env, ...carrier }, }); In the child process, extract and restore the context: import { propagation, context, trace } from '@opentelemetry/api'; const carrier = { traceparent: process.env['traceparent'], tracestate: process.env['tracestate'], }; const ctx = propagation.extract(context.active(), carrier); // Now start spans under the restored parent context const tracer = trace.getTracer('child'); tracer.startActiveSpan('child-work', {}, ctx, (span) => { // ... span.end(); }); Key points: - The traceparent header carries the trace/span ID and sampling flag — without it, the child starts a disconnected root span. - tracestate carries vendor-specific data and should also be forwarded. - The child still needs its own OTel SDK initialized with an exporter — propagation only links the spans, it doesn't tunnel telemetry through the parent. - If the child is short-lived, make sure it flushes before exit (provider.shutdown()), otherwise spans may be dropped.