How to add trace id field in the trace's request header

1.3k Views Asked by At

I would like to see trace id in the trace's request header. It seems to be supported by propagator-b3 as per https://www.npmjs.com/package/@opentelemetry/propagator-b3. I tried to look into other example in Typescript/Javascript, but I couldn't figure out yet.

I expect to see following fields in the trace's request header.

X-B3-TraceId: {TraceId}
X-B3-SpanId: {SpanId}
X-B3-ParentSpanId: {ParentSpanId}
X-B3-Sampled: {SamplingState}

Below is my code snippet. Trace works fine, but the above fields still are not in the request header. Can you advise what I am missing?

import { Span, SpanKind, trace, propagation, context, defaultTextMapSetter } from '@opentelemetry/api';
import { B3Propagator, B3InjectEncoding } from '@opentelemetry/propagator-b3';
import { OLTPTraceExporter } from '@opentelemetry/instrumentation';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { Resource } from '@opentelemetry/resources';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { WebTracerProvide } from '@opentelemetry/sdk-trrace-web';

const collectorOptions = {
url: 'https://<mylocalhost>/v1/traces',
headers: {
'Content-Type': 'application/json'
},
concurrencyLimit: 10
};

function init(): void {
registerInstrumentations({
instrumentations: []
});

const resource = Resource.default().merge(new Resource());
const provider = new WebTracerProvider({ resource });
const exporter = new OTLPTraceExporter(collectorOptions);
const processor = new BatchSpanProcessor(exporter);
 
provider.addSpanProcessor(processor);
provider.register({ propagator: new B3Propagator({ injectEncoding: B3InjectEncoding.MULTI_HEADER }) });
    }

init();

export function tracing(): void {
const tracer = trace.getTracer('tracer');
const span = tracer.startSpan();
span.setAttribute('clientId', '123');

propagation.inject(context.active(), {}, defaultTextMapSetter);
 
span.end();
}

2

There are 2 best solutions below

0
Danny Dyla On

You are close but the span is not in the active context. When you call context.active() you get the "active context" which by default does not contain any span. Adding the span to the context you make it available to any function which reads from context such as propagation.

tracer.startActiveSpan(span => {
    span.setAttribute('clientId', '123');
    
    propagation.inject(context.active(), {}, defaultTextMapSetter);
     
    span.end();
});

What the above is doing is using active context to track the span. This can also be done completely manually without ambient active context like this:

const span = tracer.startSpan();
const newContext = api.setSpan(context.active(), span);
span.setAttribute('clientId', '123');
propagation.inject(newContext, {}, defaultTextMapSetter);
span.end();

But for most users we recommend using the context manager as in the first example.

1
BlueSea On

Thank you for your reply. I tried both and it doesn't work yet.

For the first example, I actually have parameters in startSpan as well. Not sure how I can add the propagation.inject() inside that.

const span = tracer.startSpan(`client order`, {kind: SpanKind.PRODUCER});

My order request is done via websocket. Can this be a reason that it doesn't work?

I also tried using https://www.npmjs.com/package/opentelemetry-instrumentation-ws by replacing:

registerInstrumentations({instrumentations: []});

with:

registerInstrumentations({
  instrumentations: [
    new WSInstrumentation({
      sendSpans: true
    })
  ]
});

but also doesn't work.