install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/codex/otel-context-propagation" ~/.claude/skills/intense-visions-harness-engineering-otel-context-propagation-0394b3 && rm -rf "$T"
manifest:
agents/skills/codex/otel-context-propagation/SKILL.mdsource content
OpenTelemetry Context Propagation
Propagate trace context across service boundaries using W3C TraceContext headers and baggage
When to Use
- Linking traces across microservices into a single distributed trace
- Passing metadata (tenant ID, feature flags) across service boundaries without modifying APIs
- Integrating services using different languages/frameworks into one trace view
- Debugging why context is lost between services (broken traces)
Instructions
- Register propagators in the SDK setup. W3C TraceContext is the default and recommended standard.
- HTTP auto-instrumentation handles propagation automatically for most frameworks. Verify it works before adding manual propagation.
- For non-HTTP transports (queues, gRPC metadata, custom protocols), inject context into carrier objects manually.
- Use Baggage to pass key-value pairs across service boundaries (tenant ID, request priority).
- Ensure all services in the chain use the same propagation format (W3C, B3, or both via composite propagator).
// SDK setup — configure propagators import { W3CTraceContextPropagator } from '@opentelemetry/core'; import { W3CBaggagePropagator } from '@opentelemetry/core'; import { CompositePropagator } from '@opentelemetry/core'; const sdk = new NodeSDK({ textMapPropagator: new CompositePropagator({ propagators: [ new W3CTraceContextPropagator(), // traceparent + tracestate headers new W3CBaggagePropagator(), // baggage header ], }), // ... rest of config });
// Manual propagation for message queues import { context, propagation, trace } from '@opentelemetry/api'; // Producer — inject context into message headers function publishMessage(queue: string, payload: object): void { const headers: Record<string, string> = {}; propagation.inject(context.active(), headers); messageQueue.publish(queue, { body: payload, headers, // Contains traceparent, tracestate, baggage }); } // Consumer — extract context from message headers async function consumeMessage(message: QueueMessage): Promise<void> { const parentContext = propagation.extract(context.active(), message.headers); const tracer = trace.getTracer('consumer'); await context.with(parentContext, async () => { await tracer.startActiveSpan( 'process.message', { kind: SpanKind.CONSUMER, attributes: { 'messaging.system': 'rabbitmq', 'messaging.destination': message.queue }, }, async (span) => { try { await processMessage(message.body); } finally { span.end(); } } ); }); }
// Baggage — pass metadata across services import { propagation, context, BaggageEntry } from '@opentelemetry/api'; // Set baggage in the upstream service function setTenantContext(tenantId: string) { const baggage = propagation.createBaggage({ 'tenant.id': { value: tenantId }, 'request.priority': { value: 'high' }, }); return propagation.setBaggage(context.active(), baggage); } // Read baggage in the downstream service function getTenantId(): string | undefined { const baggage = propagation.getBaggage(context.active()); return baggage?.getEntry('tenant.id')?.value; }
Details
W3C TraceContext headers:
— the core propagation headertraceparent: 00-<traceId>-<spanId>-<flags>
— vendor-specific trace informationtracestate: vendor1=value1,vendor2=value2
— application-level key-value pairsbaggage: tenant.id=abc,priority=high
Auto-propagation: The HTTP instrumentation automatically injects
traceparent on outgoing requests and extracts it on incoming requests. You typically do NOT need manual propagation for HTTP.
When you need manual propagation:
- Message queues (RabbitMQ, Kafka, SQS)
- gRPC metadata
- WebSocket messages
- Custom RPC protocols
- Cron jobs that should link to the triggering request
B3 compatibility: If some services use Zipkin B3 headers, add the B3 propagator:
import { B3Propagator } from '@opentelemetry/propagator-b3'; new CompositePropagator({ propagators: [ new W3CTraceContextPropagator(), new B3Propagator(), // Also understands X-B3-TraceId headers ], });
Debugging broken traces: If traces are disconnected across services:
- Check that both services use the same propagation format
- Verify the HTTP client is instrumented (auto-instrumentation must be loaded)
- Check for reverse proxies stripping
headerstraceparent - For async operations, verify context is passed through
context.with()
Source
https://opentelemetry.io/docs/concepts/context-propagation/
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.