diff --git a/packages/opentelemetry-propagator-jaeger/src/JaegerPropagator.ts b/packages/opentelemetry-propagator-jaeger/src/JaegerPropagator.ts index f3a739f4b9..18cf2cee59 100644 --- a/packages/opentelemetry-propagator-jaeger/src/JaegerPropagator.ts +++ b/packages/opentelemetry-propagator-jaeger/src/JaegerPropagator.ts @@ -25,10 +25,10 @@ import { TraceFlags, } from '@opentelemetry/api'; import { isTracingSuppressed } from '@opentelemetry/core'; +import { JaegerPropagatorConfig } from './types'; export const UBER_TRACE_ID_HEADER = 'uber-trace-id'; export const UBER_BAGGAGE_HEADER_PREFIX = 'uberctx'; -const UBER_BAGGAGE_HEADER_REGEX = /^uberctx-(.+)/i; /** * Propagates {@link SpanContext} through Trace Context format propagation. @@ -47,12 +47,18 @@ const UBER_BAGGAGE_HEADER_REGEX = /^uberctx-(.+)/i; */ export class JaegerPropagator implements TextMapPropagator { private readonly _jaegerTraceHeader: string; - - /** - * @param {string} [customTraceHeader="uber-trace-id"] - HTTP header to inject\extract trace from. - **/ - constructor(customTraceHeader?: string) { - this._jaegerTraceHeader = customTraceHeader || UBER_TRACE_ID_HEADER; + private readonly _jaegerBaggageHeaderPrefix: string; + + constructor(customTraceHeader?: string) + constructor(config?: JaegerPropagatorConfig) + constructor(config?: JaegerPropagatorConfig | string) { + if (typeof config === 'string') { + this._jaegerTraceHeader = config; + this._jaegerBaggageHeaderPrefix = UBER_BAGGAGE_HEADER_PREFIX; + } else { + this._jaegerTraceHeader = config?.customTraceHeader || UBER_TRACE_ID_HEADER; + this._jaegerBaggageHeaderPrefix = config?.customBaggageHeaderPrefix || UBER_BAGGAGE_HEADER_PREFIX; + } } inject(context: Context, carrier: unknown, setter: TextMapSetter): void { @@ -74,7 +80,7 @@ export class JaegerPropagator implements TextMapPropagator { for (const [key, entry] of baggage.getAllEntries()) { setter.set( carrier, - `${UBER_BAGGAGE_HEADER_PREFIX}-${key}`, + `${this._jaegerBaggageHeaderPrefix}-${key}`, encodeURIComponent(entry.value) ); } @@ -88,11 +94,11 @@ export class JaegerPropagator implements TextMapPropagator { : uberTraceIdHeader; const baggageValues = getter .keys(carrier) - .filter(key => UBER_BAGGAGE_HEADER_REGEX.test(key)) + .filter(key => key.startsWith(`${this._jaegerBaggageHeaderPrefix}-`)) .map(key => { const value = getter.get(carrier, key); return { - key: key.substring(UBER_BAGGAGE_HEADER_PREFIX.length + 1), + key: key.substring(this._jaegerBaggageHeaderPrefix.length + 1), value: Array.isArray(value) ? value[0] : value, }; }); diff --git a/packages/opentelemetry-propagator-jaeger/src/types.ts b/packages/opentelemetry-propagator-jaeger/src/types.ts new file mode 100644 index 0000000000..c6bb9879e1 --- /dev/null +++ b/packages/opentelemetry-propagator-jaeger/src/types.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export interface JaegerPropagatorConfig { + customTraceHeader?: string, + customBaggageHeaderPrefix?: string, +} diff --git a/packages/opentelemetry-propagator-jaeger/test/JaegerPropagator.test.ts b/packages/opentelemetry-propagator-jaeger/test/JaegerPropagator.test.ts index 93836c84c9..be93f05194 100644 --- a/packages/opentelemetry-propagator-jaeger/test/JaegerPropagator.test.ts +++ b/packages/opentelemetry-propagator-jaeger/test/JaegerPropagator.test.ts @@ -34,7 +34,12 @@ import { describe('JaegerPropagator', () => { const jaegerPropagator = new JaegerPropagator(); const customHeader = 'new-header'; + const customBaggageHeaderPrefix = 'custom-baggage-header-prefix'; const customJaegerPropagator = new JaegerPropagator(customHeader); + const customJaegerPropagatorWithConfig = new JaegerPropagator({ + customTraceHeader: customHeader, + customBaggageHeaderPrefix, + }); let carrier: { [key: string]: unknown }; beforeEach(() => { @@ -114,6 +119,28 @@ describe('JaegerPropagator', () => { encodeURIComponent('%id%') ); }); + + it('should propagate baggage with custom prefix with url encoded values', () => { + const baggage = propagation.createBaggage({ + test: { + value: '1', + }, + myuser: { + value: '%id%', + }, + }); + + customJaegerPropagatorWithConfig.inject( + propagation.setBaggage(ROOT_CONTEXT, baggage), + carrier, + defaultTextMapSetter + ); + assert.strictEqual(carrier[`${customBaggageHeaderPrefix}-test`], '1'); + assert.strictEqual( + carrier[`${customBaggageHeaderPrefix}-myuser`], + encodeURIComponent('%id%') + ); + }); }); describe('.extract()', () => { @@ -215,6 +242,21 @@ describe('JaegerPropagator', () => { assert(secondEntry.value === '%id%'); }); + it('should extract baggage with custom prefix from carrier', () => { + carrier[`${customBaggageHeaderPrefix}-test`] = 'value'; + carrier[`${customBaggageHeaderPrefix}-myuser`] = '%25id%25'; + const extractedBaggage = propagation.getBaggage( + customJaegerPropagatorWithConfig.extract(ROOT_CONTEXT, carrier, defaultTextMapGetter) + ); + + const firstEntry = extractedBaggage?.getEntry('test'); + assert(typeof firstEntry !== 'undefined'); + assert(firstEntry.value === 'value'); + const secondEntry = extractedBaggage?.getEntry('myuser'); + assert(typeof secondEntry !== 'undefined'); + assert(secondEntry.value === '%id%'); + }); + it('should extract baggage from carrier and not override current one', () => { carrier[`${UBER_BAGGAGE_HEADER_PREFIX}-test`] = 'value'; carrier[`${UBER_BAGGAGE_HEADER_PREFIX}-myuser`] = '%25id%25'; @@ -266,6 +308,9 @@ describe('JaegerPropagator', () => { it('returns the customized header if customized', () => { assert.deepStrictEqual(customJaegerPropagator.fields(), [customHeader]); }); + it('returns the customized header if customized with config', () => { + assert.deepStrictEqual(customJaegerPropagatorWithConfig.fields(), [customHeader]); + }); }); it('should fail gracefully on bad responses from getter', () => {