|
1 | 1 | # Propagation |
2 | 2 |
|
3 | | -TODO |
| 3 | +Span context fields like trace id, span id, trace flags, and baggages need to be send to the downstream services |
| 4 | +in order to properly associate downstream created spans with the current span. |
4 | 5 |
|
5 | | -_Propagation API reference: <https://open-telemetry.github.io/opentelemetry-js-api/classes/propagationapi.html>_ |
| 6 | +This is commonly achieved with HTTP headers, RPC metadata, with well-known formats like: |
| 7 | + |
| 8 | +- [W3C Trace Context][]: Supported with [W3CTraceContextPropagator][]. |
| 9 | +- [B3][]: Supported with [B3Propagator][]. |
| 10 | +- Jaeger: Supported with [JaegerPropagator][]. |
| 11 | + |
| 12 | +If none of the above formats meet your needs, you can implement your own propagator. |
| 13 | + |
| 14 | +## Implement your own propagator |
| 15 | + |
| 16 | +To implement a propagator, you need to define a class implementing the `TextMapPropagator` interface. |
| 17 | + |
| 18 | +```ts |
| 19 | +import { |
| 20 | + Context, |
| 21 | + isSpanContextValid, |
| 22 | + isValidSpanId, |
| 23 | + isValidTraceId, |
| 24 | + TextMapGetter, |
| 25 | + TextMapPropagator, |
| 26 | + TextMapSetter, |
| 27 | + TraceFlags, |
| 28 | + trace, |
| 29 | +} from '@opentelemetry/api'; |
| 30 | +import { isTracingSuppressed } from '@opentelemetry/core'; |
| 31 | + |
| 32 | +// Example header, the content format can be `<trace-id>:<span-id>` |
| 33 | +const MyHeader = 'my-header'; |
| 34 | + |
| 35 | +export class MyPropagator implements TextMapPropagator { |
| 36 | + // Inject the header to the outgoing request. |
| 37 | + inject(context: Context, carrier: unknown, setter: TextMapSetter): void { |
| 38 | + const spanContext = trace.getSpanContext(context); |
| 39 | + // Skip if the current span context is not valid or suppressed. |
| 40 | + if ( |
| 41 | + !spanContext || |
| 42 | + !isSpanContextValid(spanContext) || |
| 43 | + isTracingSuppressed(context) |
| 44 | + ) { |
| 45 | + return; |
| 46 | + } |
| 47 | + |
| 48 | + const value = `${spanContext.traceId}:${spanContext.spanId}`; |
| 49 | + setter.set(carrier, MyHeader, value); |
| 50 | + // You can set more header fields as you need. |
| 51 | + } |
| 52 | + |
| 53 | + // Extract the header from the incoming request. |
| 54 | + extract(context: Context, carrier: unknown, getter: TextMapGetter): Context { |
| 55 | + const headers = getter.get(carrier, MyHeader); |
| 56 | + const header = Array.isArray(headers) ? headers[0] : headers; |
| 57 | + if (typeof header !== 'string') return context; |
| 58 | + |
| 59 | + const [traceId, spanId] = header.split(':'); |
| 60 | + |
| 61 | + // Skip if the traceId or spanId is invalid. |
| 62 | + if (!isValidTraceId(traceId) || !isValidSpanId(spanId)) return context; |
| 63 | + |
| 64 | + return trace.setSpanContext(context, { |
| 65 | + traceId, |
| 66 | + spanId, |
| 67 | + isRemote: true, |
| 68 | + traceFlags: TraceFlags.SAMPLED, |
| 69 | + }); |
| 70 | + } |
| 71 | + |
| 72 | + fields(): string[] { |
| 73 | + return [MyHeader]; |
| 74 | + } |
| 75 | +} |
| 76 | +``` |
| 77 | + |
| 78 | +With the propagator defined, you can set it as the global propagator, so that all instrumentations |
| 79 | +can make use of it. |
| 80 | + |
| 81 | +```ts |
| 82 | +const api = require('@opentelemetry/api'); |
| 83 | +const { MyPropagator } = require('./my-propagator'); |
| 84 | + |
| 85 | +api.propagation.setGlobalPropagator(new MyPropagator()); |
| 86 | +``` |
| 87 | + |
| 88 | +[B3]: https://github.com/openzipkin/b3-propagation |
| 89 | +[B3Propagator]: https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-propagator-b3 |
| 90 | +[JaegerPropagator]: https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-propagator-jaeger |
| 91 | +[W3C Trace Context]: https://www.w3.org/TR/trace-context/ |
| 92 | +[W3CTraceContextPropagator]: https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-core#w3ctracecontextpropagator-propagator |
0 commit comments