diff --git a/packages/baggage-span-processor/README.md b/packages/baggage-span-processor/README.md index 0b6af08d91..273924d8d2 100644 --- a/packages/baggage-span-processor/README.md +++ b/packages/baggage-span-processor/README.md @@ -27,16 +27,16 @@ npm install --save @opentelemetry/baggage-span-processor ### Usage -Add to the span processors during configuration: +Add to the span processors that copies all baggage entries during configuration: ```javascript -import { NodeSDK, tracing } from "@opentelemetry/sdk-node"; -import { BaggageSpanProcessor } from "@opentelemetry/baggage-span-processor"; +import { NodeSDK, tracing } from '@opentelemetry/sdk-node'; +import { ALLOW_ALL_BAGGAGE_KEYS, BaggageSpanProcessor } from '@opentelemetry/baggage-span-processor'; const spanProcessors = [ new tracing.SimpleSpanProcessor( new tracing.ConsoleSpanExporter()), - new BaggageSpanProcessor()]; + new BaggageSpanProcessor(ALLOW_ALL_BAGGAGE_KEYS)]; const sdk = new NodeSDK({ serviceName: "example-service", @@ -46,6 +46,21 @@ const sdk = new NodeSDK({ sdk.start(); ``` +Alternatively, you can provide a custom baggage key predicate to select which baggage keys you want to copy. + +For example, to only copy baggage entries that start with `my-key`: + +```javascript +new BaggageSpanProcessor((baggageKey: string) => key.startsWith('my-key')) +``` + +For example, to only copy baggage entries that matches the regex `^key.+`: + +```javascript +const regex = new RegExp("^key.+") +new BaggageSpanProcessor((baggageKey: string) => regex.test(baggageKey)) +``` + ## Useful links - For more information on OpenTelemetry, visit: diff --git a/packages/baggage-span-processor/src/baggage-span-processor.ts b/packages/baggage-span-processor/src/baggage-span-processor.ts index 13d3c84260..ddec06a20a 100644 --- a/packages/baggage-span-processor/src/baggage-span-processor.ts +++ b/packages/baggage-span-processor/src/baggage-span-processor.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { BaggageKeyPredicate } from './types'; import { Context, propagation } from '@opentelemetry/api'; import { SpanProcessor, @@ -43,6 +44,16 @@ import { * values will appear in all outgoing HTTP headers from the application. */ export class BaggageSpanProcessor implements SpanProcessor { + private _keyPredicate: BaggageKeyPredicate; + + /** + * Constructs a new BaggageSpanProcessor instance. + * @param keyPredicate A predicate that determines whether a baggage key-value pair should be added to new spans as a span attribute. + */ + constructor(keyPredicate: BaggageKeyPredicate) { + this._keyPredicate = keyPredicate; + } + /** * Forces to export all finished spans */ @@ -57,11 +68,9 @@ export class BaggageSpanProcessor implements SpanProcessor { * @param span the Span that just started. */ onStart(span: Span, parentContext: Context): void { - (propagation.getBaggage(parentContext)?.getAllEntries() ?? []).forEach( - entry => { - span.setAttribute(entry[0], entry[1].value); - } - ); + (propagation.getBaggage(parentContext)?.getAllEntries() ?? []) + .filter(entry => this._keyPredicate(entry[0])) + .forEach(entry => span.setAttribute(entry[0], entry[1].value)); } /** diff --git a/packages/baggage-span-processor/src/index.ts b/packages/baggage-span-processor/src/index.ts index 39e175e9b3..23a4aa44e7 100644 --- a/packages/baggage-span-processor/src/index.ts +++ b/packages/baggage-span-processor/src/index.ts @@ -14,4 +14,5 @@ * limitations under the License. */ -export { BaggageSpanProcessor } from './baggage-span-processor'; +export * from './baggage-span-processor'; +export * from './types'; diff --git a/packages/baggage-span-processor/src/types.ts b/packages/baggage-span-processor/src/types.ts new file mode 100644 index 0000000000..3a0e105176 --- /dev/null +++ b/packages/baggage-span-processor/src/types.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +/** + * A function that determines whether a baggage key-value pair should be added to new + * spans as a span attribute. + */ +export type BaggageKeyPredicate = (baggageKey: string) => boolean; + +/** + * A {@link BaggageKeyPredicate} that includes all baggage keys. + */ +export const ALLOW_ALL_BAGGAGE_KEYS: BaggageKeyPredicate = (_: string) => true; diff --git a/packages/baggage-span-processor/test/baggage-span-processor.test.ts b/packages/baggage-span-processor/test/baggage-span-processor.test.ts index 2829858ab1..fdc19560c8 100644 --- a/packages/baggage-span-processor/test/baggage-span-processor.test.ts +++ b/packages/baggage-span-processor/test/baggage-span-processor.test.ts @@ -15,6 +15,7 @@ */ import { BaggageSpanProcessor } from '../src/baggage-span-processor'; +import { ALLOW_ALL_BAGGAGE_KEYS } from '../src/types'; import { propagation, ROOT_CONTEXT, @@ -24,8 +25,8 @@ import { import { BasicTracerProvider, Span } from '@opentelemetry/sdk-trace-base'; import { expect } from 'expect'; -describe('BaggageSpanProcessor', () => { - const baggageProcessor = new BaggageSpanProcessor(); +describe('BaggageSpanProcessor with all keys filter', () => { + const baggageProcessor = new BaggageSpanProcessor(ALLOW_ALL_BAGGAGE_KEYS); const bag = propagation.createBaggage({ brand: { value: 'samsonite' }, @@ -72,3 +73,82 @@ describe('BaggageSpanProcessor', () => { await expect(baggageProcessor.shutdown()).resolves.not.toThrow(); }); }); + +describe('BaggageSpanProcessor with startWith key filter', () => { + const baggageProcessor = new BaggageSpanProcessor((key: string) => + key.startsWith('brand') + ); + + const bag = propagation.createBaggage({ + brand: { value: 'samsonite' }, + color: { value: 'blue' }, + }); + + const expectedAttrs = { + brand: 'samsonite', + }; + + let span: Span; + + beforeEach(() => { + span = new Span( + new BasicTracerProvider().getTracer('baggage-testing'), + ROOT_CONTEXT, + 'Edward W. Span', + { + traceId: 'e4cda95b652f4a1592b449d5929fda1b', + spanId: '7e0c63257de34c92', + traceFlags: TraceFlags.SAMPLED, + }, + SpanKind.SERVER + ); + }); + + it('should only add baggage entries that match filter', () => { + expect(span.attributes).toEqual({}); + const ctx = propagation.setBaggage(ROOT_CONTEXT, bag); + baggageProcessor.onStart(span, ctx); + + expect(span.attributes).toEqual(expectedAttrs); + }); +}); + +describe('BaggageSpanProcessor with regex key filter', () => { + const regex = new RegExp('^col.+'); + const baggageProcessor = new BaggageSpanProcessor((key: string) => + regex.test(key) + ); + + const bag = propagation.createBaggage({ + brand: { value: 'samsonite' }, + color: { value: 'blue' }, + }); + + const expectedAttrs = { + color: 'blue', + }; + + let span: Span; + + beforeEach(() => { + span = new Span( + new BasicTracerProvider().getTracer('baggage-testing'), + ROOT_CONTEXT, + 'Edward W. Span', + { + traceId: 'e4cda95b652f4a1592b449d5929fda1b', + spanId: '7e0c63257de34c92', + traceFlags: TraceFlags.SAMPLED, + }, + SpanKind.SERVER + ); + }); + + it('should only add baggage entries that match filter', () => { + expect(span.attributes).toEqual({}); + const ctx = propagation.setBaggage(ROOT_CONTEXT, bag); + baggageProcessor.onStart(span, ctx); + + expect(span.attributes).toEqual(expectedAttrs); + }); +});