229 lines
6.5 KiB
TypeScript
229 lines
6.5 KiB
TypeScript
/*
|
|
* Copyright The OpenTelemetry Authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import {
|
|
defaultTextMapGetter,
|
|
defaultTextMapSetter,
|
|
TextMapPropagator,
|
|
SpanContext,
|
|
TextMapGetter,
|
|
TextMapSetter,
|
|
trace,
|
|
} from '@opentelemetry/api';
|
|
import { Context, ROOT_CONTEXT } from '@opentelemetry/api';
|
|
import * as assert from 'assert';
|
|
import { CompositePropagator, W3CTraceContextPropagator } from '../../../src';
|
|
import {
|
|
TRACE_PARENT_HEADER,
|
|
TRACE_STATE_HEADER,
|
|
} from '../../../src/trace/W3CTraceContextPropagator';
|
|
import { TraceState } from '../../../src/trace/TraceState';
|
|
|
|
class DummyPropagator implements TextMapPropagator {
|
|
inject(context: Context, carrier: any, setter: TextMapSetter<any>): void {
|
|
carrier['dummy'] = trace.getSpanContext(context);
|
|
}
|
|
extract(context: Context, carrier: any, getter: TextMapGetter<any>): Context {
|
|
if (carrier['dummy']) {
|
|
return trace.setSpanContext(context, carrier['dummy']);
|
|
}
|
|
return context;
|
|
}
|
|
fields(): string[] {
|
|
return ['dummy'];
|
|
}
|
|
}
|
|
|
|
describe('Composite Propagator', () => {
|
|
const traceId = 'd4cda95b652f4a1592b449d5929fda1b';
|
|
const spanId = '6e0c63257de34c92';
|
|
|
|
describe('inject', () => {
|
|
let carrier: { [key: string]: unknown };
|
|
let spanContext: SpanContext;
|
|
let ctxWithSpanContext: Context;
|
|
|
|
beforeEach(() => {
|
|
carrier = {};
|
|
spanContext = {
|
|
spanId,
|
|
traceId,
|
|
traceFlags: 1,
|
|
traceState: new TraceState('foo=bar'),
|
|
};
|
|
ctxWithSpanContext = trace.setSpanContext(ROOT_CONTEXT, spanContext);
|
|
});
|
|
|
|
it('should inject context using all configured propagators', () => {
|
|
const composite = new CompositePropagator({
|
|
propagators: [new DummyPropagator(), new W3CTraceContextPropagator()],
|
|
});
|
|
composite.inject(ctxWithSpanContext, carrier, defaultTextMapSetter);
|
|
|
|
assert.strictEqual(carrier['dummy'], spanContext);
|
|
assert.strictEqual(
|
|
carrier[TRACE_PARENT_HEADER],
|
|
`00-${traceId}-${spanId}-01`
|
|
);
|
|
assert.strictEqual(carrier[TRACE_STATE_HEADER], 'foo=bar');
|
|
});
|
|
|
|
it('should not throw', () => {
|
|
const composite = new CompositePropagator({
|
|
propagators: [
|
|
new ThrowingPropagator(),
|
|
new W3CTraceContextPropagator(),
|
|
],
|
|
});
|
|
composite.inject(ctxWithSpanContext, carrier, defaultTextMapSetter);
|
|
|
|
assert.strictEqual(
|
|
carrier[TRACE_PARENT_HEADER],
|
|
`00-${traceId}-${spanId}-01`
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('extract', () => {
|
|
let carrier: { [key: string]: unknown };
|
|
|
|
beforeEach(() => {
|
|
carrier = {
|
|
['dummy']: { traceId, spanId },
|
|
[TRACE_PARENT_HEADER]: `00-${traceId}-${spanId}-01`,
|
|
[TRACE_STATE_HEADER]: 'foo=bar',
|
|
};
|
|
});
|
|
|
|
it('should extract context using all configured propagators', () => {
|
|
const composite = new CompositePropagator({
|
|
propagators: [new DummyPropagator(), new W3CTraceContextPropagator()],
|
|
});
|
|
const spanContext = trace.getSpanContext(
|
|
composite.extract(ROOT_CONTEXT, carrier, defaultTextMapGetter)
|
|
);
|
|
|
|
if (!spanContext) {
|
|
throw new Error('no extracted context');
|
|
}
|
|
|
|
assert.strictEqual(spanContext.traceId, traceId);
|
|
assert.strictEqual(spanContext.spanId, spanId);
|
|
assert.strictEqual(spanContext.traceFlags, 1);
|
|
assert.strictEqual(spanContext.isRemote, true);
|
|
assert.strictEqual(spanContext.traceState!.get('foo'), 'bar');
|
|
});
|
|
|
|
it('should not throw', () => {
|
|
const composite = new CompositePropagator({
|
|
propagators: [
|
|
new ThrowingPropagator(),
|
|
new W3CTraceContextPropagator(),
|
|
],
|
|
});
|
|
const spanContext = trace.getSpanContext(
|
|
composite.extract(ROOT_CONTEXT, carrier, defaultTextMapGetter)
|
|
);
|
|
|
|
if (!spanContext) {
|
|
throw new Error('no extracted context');
|
|
}
|
|
|
|
assert.strictEqual(spanContext.traceId, traceId);
|
|
assert.strictEqual(spanContext.spanId, spanId);
|
|
assert.strictEqual(spanContext.traceFlags, 1);
|
|
assert.strictEqual(spanContext.isRemote, true);
|
|
assert.strictEqual(spanContext.traceState!.get('foo'), 'bar');
|
|
});
|
|
});
|
|
|
|
describe('fields()', () => {
|
|
it('should combine fields from both propagators', () => {
|
|
const composite = new CompositePropagator({
|
|
propagators: [
|
|
{
|
|
extract: c => c,
|
|
inject: () => {},
|
|
fields: () => ['p1'],
|
|
},
|
|
{
|
|
extract: c => c,
|
|
inject: () => {},
|
|
fields: () => ['p2'],
|
|
},
|
|
],
|
|
});
|
|
|
|
assert.deepStrictEqual(composite.fields(), ['p1', 'p2']);
|
|
});
|
|
|
|
it('should ignore propagators without fields function', () => {
|
|
const composite = new CompositePropagator({
|
|
propagators: [
|
|
{
|
|
extract: c => c,
|
|
inject: () => {},
|
|
fields: () => ['p1'],
|
|
},
|
|
// @ts-expect-error verify missing fields case
|
|
{
|
|
extract: c => c,
|
|
inject: () => {},
|
|
},
|
|
],
|
|
});
|
|
|
|
assert.deepStrictEqual(composite.fields(), ['p1']);
|
|
});
|
|
|
|
it('should not allow caller to modify fields', () => {
|
|
const composite = new CompositePropagator({
|
|
propagators: [
|
|
{
|
|
extract: c => c,
|
|
inject: () => {},
|
|
fields: () => ['p1'],
|
|
},
|
|
{
|
|
extract: c => c,
|
|
inject: () => {},
|
|
fields: () => ['p2'],
|
|
},
|
|
],
|
|
});
|
|
|
|
const fields = composite.fields();
|
|
assert.deepStrictEqual(fields, ['p1', 'p2']);
|
|
fields[1] = 'p3';
|
|
assert.deepStrictEqual(composite.fields(), ['p1', 'p2']);
|
|
});
|
|
});
|
|
});
|
|
|
|
class ThrowingPropagator implements TextMapPropagator {
|
|
inject(context: Context, carrier: unknown) {
|
|
throw new Error('this propagator throws');
|
|
}
|
|
|
|
extract(context: Context, carrier: unknown): Context {
|
|
throw new Error('This propagator throws');
|
|
}
|
|
|
|
fields(): string[] {
|
|
return [];
|
|
}
|
|
}
|