Skip to content

Commit

Permalink
fix: add debug flag to b3 propagator
Browse files Browse the repository at this point in the history
  • Loading branch information
srjames90 committed Jul 24, 2020
1 parent e9005b5 commit bfaa63c
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 28 deletions.
9 changes: 8 additions & 1 deletion packages/opentelemetry-api/src/trace/span_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export interface SpanContext {
/**
* Debug flag to propagate.
*
* This flag only seems relevant to b3. According to the b3 spec,
* This flag is relevant to b3. According to the b3 spec,
* Debug is encoded as X-B3-Flags: 1. Absent or any other value can be ignored.
* Debug is a production troubleshooting aid used in tools like curl or chrome debug.
* Debug is an emphasized accept decision that implies accept (or setting traceFlags to accept),
Expand All @@ -62,6 +62,13 @@ export interface SpanContext {
* do not send the sampled header as well.
*/
debug?: boolean;
/**
*
* The ID of the parent span propagated by b3. Encoded as a 16
* lowercase hex characters corresponding to 64 bits.
* May be present on a child span and must be absent on the root span
*/
parentSpanId?: string;
/**
* Tracing-system-specific info to propagate.
*
Expand Down
36 changes: 25 additions & 11 deletions packages/opentelemetry-core/src/context/propagation/B3Propagator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,23 @@ export class B3Propagator implements HttpTextPropagator {
inject(context: Context, carrier: unknown, setter: SetterFunction) {
const spanContext = getParentSpanContext(context);
if (!spanContext) return;

if (
isValidTraceId(spanContext.traceId) &&
isValidSpanId(spanContext.spanId)
) {
const parentSpanExists = !!spanContext.parentSpanId;
if (parentSpanExists) {
if (isValidTraceId(spanContext.parentSpanId || ''))
setter(carrier, X_B3_PARENT_SPAN_ID, spanContext.parentSpanId);
else return;
}
setter(carrier, X_B3_TRACE_ID, spanContext.traceId);
setter(carrier, X_B3_SPAN_ID, spanContext.spanId);
// According to the B3 spec, if the debug flag is set,
// the sampled flag shouldn't be propagated as well.
if (spanContext.debug) {
setter(
carrier,
X_B3_FLAGS,
'1'
);
}
setter(carrier, X_B3_FLAGS, '1');
}
// We set the header only if there is an existing sampling decision.
// Otherwise we will omit it => Absent.
else if (spanContext.traceFlags !== undefined) {
Expand All @@ -81,23 +82,35 @@ export class B3Propagator implements HttpTextPropagator {
extract(context: Context, carrier: unknown, getter: GetterFunction): Context {
const traceIdHeader = getter(carrier, X_B3_TRACE_ID);
const spanIdHeader = getter(carrier, X_B3_SPAN_ID);
const parentSpanIdHeader = getter(carrier, X_B3_PARENT_SPAN_ID);
const sampledHeader = getter(carrier, X_B3_SAMPLED);
const flagsHeader = getter(carrier, X_B3_FLAGS);

const traceIdHeaderValue = Array.isArray(traceIdHeader)
? traceIdHeader[0]
: traceIdHeader;
const spanId = Array.isArray(spanIdHeader) ? spanIdHeader[0] : spanIdHeader;
const parentSpanId = Array.isArray(parentSpanIdHeader)
? parentSpanIdHeader[0]
: parentSpanIdHeader;

const options = Array.isArray(sampledHeader)
? sampledHeader[0]
: sampledHeader;

const debugHeaderValue = Array.isArray(flagsHeader) ? flagsHeader[0] : flagsHeader;
const debug = isNaN(Number(debugHeaderValue)) ? false : debugHeaderValue === "1";
const debugHeaderValue = Array.isArray(flagsHeader)
? flagsHeader[0]
: flagsHeader;
const debug = isNaN(Number(debugHeaderValue))
? false
: debugHeaderValue === '1';
const traceFlagsOrDebug = Number(debug) || Number(options);

if (typeof traceIdHeaderValue !== 'string' || typeof spanId !== 'string') {
if (
typeof traceIdHeaderValue !== 'string' ||
typeof spanId !== 'string' ||
(typeof parentSpanIdHeader === 'string' && !isValidSpanId(parentSpanId))
) {
return context;
}

Expand All @@ -109,8 +122,9 @@ export class B3Propagator implements HttpTextPropagator {
spanId,
isRemote: true,
// Set traceFlags as 1 if debug is 1
traceFlags: traceFlagsOrDebug || TraceFlags.NONE ,
traceFlags: traceFlagsOrDebug || TraceFlags.NONE,
debug,
parentSpanId,
});
}
return context;
Expand Down
96 changes: 80 additions & 16 deletions packages/opentelemetry-core/test/context/B3Propagator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
import {
B3Propagator,
X_B3_FLAGS,
X_B3_PARENT_SPAN_ID,
X_B3_SAMPLED,
X_B3_SPAN_ID,
X_B3_TRACE_ID,
Expand Down Expand Up @@ -108,7 +109,31 @@ describe('B3Propagator', () => {
assert.deepStrictEqual(carrier[X_B3_SPAN_ID], '6e0c63257de34c92');
assert.deepStrictEqual(carrier[X_B3_FLAGS], '1');
assert.deepStrictEqual(carrier[X_B3_SAMPLED], undefined);
})
});

it('should set b3 traceId, spanId, and parentSpanId headers', () => {
const spanContext: SpanContext = {
traceId: 'd4cda95b652f4a1592b449d5929fda1b',
parentSpanId: 'f4592dc481026a8c',
spanId: '6e0c63257de34c92',
traceFlags: TraceFlags.NONE,
debug: true,
};

b3Propagator.inject(
setExtractedSpanContext(Context.ROOT_CONTEXT, spanContext),
carrier,
defaultSetter
);
assert.deepStrictEqual(
carrier[X_B3_TRACE_ID],
'd4cda95b652f4a1592b449d5929fda1b'
);
assert.deepStrictEqual(carrier[X_B3_PARENT_SPAN_ID], 'f4592dc481026a8c');
assert.deepStrictEqual(carrier[X_B3_SPAN_ID], '6e0c63257de34c92');
assert.deepStrictEqual(carrier[X_B3_FLAGS], '1');
assert.deepStrictEqual(carrier[X_B3_SAMPLED], undefined);
});

it('should not inject empty spancontext', () => {
const emptySpanContext = {
Expand Down Expand Up @@ -137,6 +162,7 @@ describe('B3Propagator', () => {
assert.deepStrictEqual(extractedSpanContext, {
debug: false,
spanId: 'b7ad6b7169203331',
parentSpanId: undefined,
traceId: '0af7651916cd43dd8448eb211c80319c',
isRemote: true,
traceFlags: TraceFlags.NONE,
Expand All @@ -154,6 +180,7 @@ describe('B3Propagator', () => {
assert.deepStrictEqual(extractedSpanContext, {
debug: false,
spanId: 'b7ad6b7169203331',
parentSpanId: undefined,
traceId: '0af7651916cd43dd8448eb211c80319c',
isRemote: true,
traceFlags: TraceFlags.SAMPLED,
Expand All @@ -171,6 +198,7 @@ describe('B3Propagator', () => {
assert.deepStrictEqual(extractedSpanContext, {
debug: false,
spanId: 'b7ad6b7169203331',
parentSpanId: undefined,
traceId: '0af7651916cd43dd8448eb211c80319c',
isRemote: true,
traceFlags: TraceFlags.SAMPLED,
Expand All @@ -188,42 +216,65 @@ describe('B3Propagator', () => {
assert.deepStrictEqual(extractedSpanContext, {
debug: false,
spanId: 'b7ad6b7169203331',
parentSpanId: undefined,
traceId: '0af7651916cd43dd8448eb211c80319c',
isRemote: true,
traceFlags: TraceFlags.NONE,
});
});

it("should extract context of a debug span from carrier when debug flag is valid", () => {
carrier[X_B3_TRACE_ID] = "0af7651916cd43dd8448eb211c80319c";
carrier[X_B3_SPAN_ID] = "b7ad6b7169203331";
carrier[X_B3_FLAGS] = "1";
it('should extract context of a debug span from carrier when debug flag is valid', () => {
carrier[X_B3_TRACE_ID] = '0af7651916cd43dd8448eb211c80319c';
carrier[X_B3_SPAN_ID] = 'b7ad6b7169203331';
carrier[X_B3_FLAGS] = '1';
const extractedSpanContext = getExtractedSpanContext(
b3Propagator.extract(Context.ROOT_CONTEXT, carrier, defaultGetter)
);

assert.deepStrictEqual(extractedSpanContext, {
debug: true,
spanId: "b7ad6b7169203331",
traceId: "0af7651916cd43dd8448eb211c80319c",
spanId: 'b7ad6b7169203331',
parentSpanId: undefined,
traceId: '0af7651916cd43dd8448eb211c80319c',
isRemote: true,
traceFlags: TraceFlags.SAMPLED,
});
});

it('should extract context of a span from carrier when debug flag is invalidly set as 0', () => {
carrier[X_B3_TRACE_ID] = '0af7651916cd43dd8448eb211c80319c';
carrier[X_B3_SPAN_ID] = 'b7ad6b7169203331';
carrier[X_B3_FLAGS] = '0';
carrier[X_B3_SAMPLED] = '1';
const extractedSpanContext = getExtractedSpanContext(
b3Propagator.extract(Context.ROOT_CONTEXT, carrier, defaultGetter)
);

assert.deepStrictEqual(extractedSpanContext, {
debug: false,
spanId: 'b7ad6b7169203331',
parentSpanId: undefined,
traceId: '0af7651916cd43dd8448eb211c80319c',
isRemote: true,
traceFlags: TraceFlags.SAMPLED,
});
});

it("should extract context of a span from carrier when debug flag is invalidly set as 0", () => {
carrier[X_B3_TRACE_ID] = "0af7651916cd43dd8448eb211c80319c";
carrier[X_B3_SPAN_ID] = "b7ad6b7169203331";
carrier[X_B3_FLAGS] = "0";
carrier[X_B3_SAMPLED] ="1"
it('should extract context of a span from carrier with a parent span id', () => {
carrier[X_B3_TRACE_ID] = '0af7651916cd43dd8448eb211c80319c';
carrier[X_B3_SPAN_ID] = 'b7ad6b7169203331';
carrier[X_B3_PARENT_SPAN_ID] = 'f4592dc481026a8c';
carrier[X_B3_FLAGS] = '0';
carrier[X_B3_SAMPLED] = '1';
const extractedSpanContext = getExtractedSpanContext(
b3Propagator.extract(Context.ROOT_CONTEXT, carrier, defaultGetter)
);

assert.deepStrictEqual(extractedSpanContext, {
debug: false,
spanId: "b7ad6b7169203331",
traceId: "0af7651916cd43dd8448eb211c80319c",
spanId: 'b7ad6b7169203331',
parentSpanId: 'f4592dc481026a8c',
traceId: '0af7651916cd43dd8448eb211c80319c',
isRemote: true,
traceFlags: TraceFlags.SAMPLED,
});
Expand All @@ -240,7 +291,7 @@ describe('B3Propagator', () => {
);
});

it('should return undefined when options and spanId are undefined', () => {
it('should return undefined when spanId is undefined', () => {
carrier[X_B3_TRACE_ID] = '0af7651916cd43dd8448eb211c80319c';
carrier[X_B3_SPAN_ID] = undefined;
assert.deepStrictEqual(
Expand All @@ -251,6 +302,18 @@ describe('B3Propagator', () => {
);
});

it('should return undefined when parentSpanId is invalid', () => {
carrier[X_B3_TRACE_ID] = '0af7651916cd43dd8448eb211c80319c';
carrier[X_B3_SPAN_ID] = 'b7ad6b7169203331';
carrier[X_B3_PARENT_SPAN_ID] = 'invalid';
assert.deepStrictEqual(
getExtractedSpanContext(
b3Propagator.extract(Context.ROOT_CONTEXT, carrier, defaultGetter)
),
undefined
);
});

it('returns undefined if b3 header is missing', () => {
assert.deepStrictEqual(
getExtractedSpanContext(
Expand Down Expand Up @@ -280,6 +343,7 @@ describe('B3Propagator', () => {
assert.deepStrictEqual(extractedSpanContext, {
debug: false,
spanId: 'b7ad6b7169203331',
parentSpanId: undefined,
traceId: '0af7651916cd43dd8448eb211c80319c',
isRemote: true,
traceFlags: TraceFlags.SAMPLED,
Expand Down Expand Up @@ -325,7 +389,6 @@ describe('B3Propagator', () => {

Object.getOwnPropertyNames(testCases).forEach(testCase => {
carrier[X_B3_TRACE_ID] = testCases[testCase];

const extractedSpanContext = getExtractedSpanContext(
b3Propagator.extract(Context.ROOT_CONTEXT, carrier, defaultGetter)
);
Expand Down Expand Up @@ -366,6 +429,7 @@ describe('B3Propagator', () => {
assert.deepStrictEqual(extractedSpanContext, {
debug: false,
spanId: 'b7ad6b7169203331',
parentSpanId: undefined,
traceId: '00000000000000008448eb211c80319c',
isRemote: true,
traceFlags: TraceFlags.SAMPLED,
Expand Down

0 comments on commit bfaa63c

Please sign in to comment.