Skip to content

Commit

Permalink
docs: document how to implement a propagator (#3351)
Browse files Browse the repository at this point in the history
Co-authored-by: Marc Pichler <marcpi@edu.aau.at>
Co-authored-by: Daniel Dyla <dyladan@users.noreply.github.com>
Co-authored-by: Valentin Marchaud <contact@vmarchaud.fr>
  • Loading branch information
4 people authored Nov 8, 2022
1 parent 85c62ef commit c6ff50e
Showing 1 changed file with 89 additions and 2 deletions.
91 changes: 89 additions & 2 deletions doc/propagation.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,92 @@
# Propagation

TODO
Span context fields like trace id, span id, trace flags, and baggages need to be send to the downstream services
in order to properly associate downstream created spans with the current span.

_Propagation API reference: <https://open-telemetry.github.io/opentelemetry-js-api/classes/propagationapi.html>_
This is commonly achieved with HTTP headers, RPC metadata, with well-known formats like:

- [W3C Trace Context][]: Supported with [W3CTraceContextPropagator][].
- [B3][]: Supported with [B3Propagator][].
- Jaeger: Supported with [JaegerPropagator][].

If none of the above formats meet your needs, you can implement your own propagator.

## Implement your own propagator

To implement a propagator, you need to define a class implementing the `TextMapPropagator` interface.

```ts
import {
Context,
isSpanContextValid,
isValidSpanId,
isValidTraceId,
TextMapGetter,
TextMapPropagator,
TextMapSetter,
TraceFlags,
trace,
} from '@opentelemetry/api';
import { isTracingSuppressed } from '@opentelemetry/core';

// Example header, the content format can be `<trace-id>:<span-id>`
const MyHeader = 'my-header';

export class MyPropagator implements TextMapPropagator {
// Inject the header to the outgoing request.
inject(context: Context, carrier: unknown, setter: TextMapSetter): void {
const spanContext = trace.getSpanContext(context);
// Skip if the current span context is not valid or suppressed.
if (
!spanContext ||
!isSpanContextValid(spanContext) ||
isTracingSuppressed(context)
) {
return;
}

const value = `${spanContext.traceId}:${spanContext.spanId}`;
setter.set(carrier, MyHeader, value);
// You can set more header fields as you need.
}

// Extract the header from the incoming request.
extract(context: Context, carrier: unknown, getter: TextMapGetter): Context {
const headers = getter.get(carrier, MyHeader);
const header = Array.isArray(headers) ? headers[0] : headers;
if (typeof header !== 'string') return context;

const [traceId, spanId] = header.split(':');

// Skip if the traceId or spanId is invalid.
if (!isValidTraceId(traceId) || !isValidSpanId(spanId)) return context;

return trace.setSpanContext(context, {
traceId,
spanId,
isRemote: true,
traceFlags: TraceFlags.SAMPLED,
});
}

fields(): string[] {
return [MyHeader];
}
}
```

With the propagator defined, you can set it as the global propagator, so that all instrumentations
can make use of it.

```ts
const api = require('@opentelemetry/api');
const { MyPropagator } = require('./my-propagator');

api.propagation.setGlobalPropagator(new MyPropagator());
```

[B3]: https://github.com/openzipkin/b3-propagation
[B3Propagator]: https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-propagator-b3
[JaegerPropagator]: https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-propagator-jaeger
[W3C Trace Context]: https://www.w3.org/TR/trace-context/
[W3CTraceContextPropagator]: https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-core#w3ctracecontextpropagator-propagator

0 comments on commit c6ff50e

Please sign in to comment.