Skip to content

Commit c6ff50e

Browse files
legendecaspichlermarcdyladanvmarchaud
authored
docs: document how to implement a propagator (#3351)
Co-authored-by: Marc Pichler <[email protected]> Co-authored-by: Daniel Dyla <[email protected]> Co-authored-by: Valentin Marchaud <[email protected]>
1 parent 85c62ef commit c6ff50e

File tree

1 file changed

+89
-2
lines changed

1 file changed

+89
-2
lines changed

doc/propagation.md

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,92 @@
11
# Propagation
22

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.
45

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

Comments
 (0)