Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add baggage key predicate to baggage span processor #2212

Merged
merged 20 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions packages/baggage-span-processor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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: <https://opentelemetry.io/>
Expand Down
19 changes: 14 additions & 5 deletions packages/baggage-span-processor/src/baggage-span-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { BaggageKeyPredicate } from './types';
import { Context, propagation } from '@opentelemetry/api';
import {
SpanProcessor,
Expand Down Expand Up @@ -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) {
blumamir marked this conversation as resolved.
Show resolved Hide resolved
this._keyPredicate = keyPredicate;
}

/**
* Forces to export all finished spans
*/
Expand All @@ -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));
}

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/baggage-span-processor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
* limitations under the License.
*/

export { BaggageSpanProcessor } from './baggage-span-processor';
export * from './baggage-span-processor';
export * from './types';
26 changes: 26 additions & 0 deletions packages/baggage-span-processor/src/types.ts
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import { BaggageSpanProcessor } from '../src/baggage-span-processor';
import { ALLOW_ALL_BAGGAGE_KEYS } from '../src/types';
import {
propagation,
ROOT_CONTEXT,
Expand All @@ -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' },
Expand Down Expand Up @@ -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);
});
});
Loading