Skip to content

Commit 97fbd3a

Browse files
committed
feat(tracing): add propagation of environment and release values in baggage headers
1 parent 571d661 commit 97fbd3a

File tree

7 files changed

+109
-12
lines changed

7 files changed

+109
-12
lines changed

packages/tracing/src/browser/request.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-disable max-lines */
2+
import type { Span } from '@sentry/types';
23
import {
34
addInstrumentationHandler,
45
BAGGAGE_HEADER_NAME,
@@ -7,7 +8,6 @@ import {
78
mergeAndSerializeBaggage,
89
} from '@sentry/utils';
910

10-
import { Span } from '../span';
1111
import { getActiveTransaction, hasTracingEnabled } from '../utils';
1212

1313
export const DEFAULT_TRACING_ORIGINS = ['localhost', /^\//];

packages/tracing/src/span.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
/* eslint-disable max-lines */
2-
import { Baggage, Primitive, Span as SpanInterface, SpanContext, Transaction } from '@sentry/types';
3-
import { dropUndefinedKeys, timestampWithMs, uuid4 } from '@sentry/utils';
2+
import { getCurrentHub } from '@sentry/hub';
3+
import { Baggage, Hub, Primitive, Span as SpanInterface, SpanContext, Transaction } from '@sentry/types';
4+
import {
5+
createBaggage,
6+
dropUndefinedKeys,
7+
isBaggageEmpty,
8+
isSentryBaggageEmpty,
9+
setBaggageValue,
10+
timestampWithMs,
11+
uuid4,
12+
} from '@sentry/utils';
413

514
/**
615
* Keeps track of finished spans for a given transaction
@@ -302,7 +311,14 @@ export class Span implements SpanInterface {
302311
* @inheritdoc
303312
*/
304313
public getBaggage(): Baggage | undefined {
305-
return this.transaction && this.transaction.metadata.baggage;
314+
const existingBaggage = this.transaction && this.transaction.metadata.baggage;
315+
316+
const finalBaggage =
317+
!existingBaggage || isSentryBaggageEmpty(existingBaggage)
318+
? this._getBaggageWithSentryValues(existingBaggage)
319+
: existingBaggage;
320+
321+
return isBaggageEmpty(finalBaggage) ? undefined : finalBaggage;
306322
}
307323

308324
/**
@@ -334,6 +350,24 @@ export class Span implements SpanInterface {
334350
trace_id: this.traceId,
335351
});
336352
}
353+
354+
/**
355+
*
356+
* @param baggage
357+
* @returns
358+
*/
359+
private _getBaggageWithSentryValues(baggage: Baggage = createBaggage({})): Baggage {
360+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
361+
const hub: Hub = ((this.transaction as any) && (this.transaction as any)._hub) || getCurrentHub();
362+
const client = hub.getClient();
363+
364+
const { environment, release } = (client && client.getOptions()) || {};
365+
366+
environment && setBaggageValue(baggage, 'environment', environment);
367+
release && setBaggageValue(baggage, 'release', release);
368+
369+
return baggage;
370+
}
337371
}
338372

339373
export type SpanStatusType =

packages/tracing/src/transaction.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ export class Transaction extends SpanClass implements TransactionInterface {
1717

1818
public metadata: TransactionMetadata;
1919

20-
private _measurements: Measurements = {};
21-
2220
/**
2321
* The reference to the current hub.
2422
*/
25-
private readonly _hub: Hub;
23+
protected readonly _hub: Hub;
24+
25+
private _measurements: Measurements = {};
2626

2727
private _trimEnd?: boolean;
2828

packages/tracing/test/span.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { BrowserClient } from '@sentry/browser';
22
import { Hub, makeMain, Scope } from '@sentry/hub';
3+
import { createBaggage, getSentryBaggageItems, getThirdPartyBaggage, isSentryBaggageEmpty } from '@sentry/utils';
34

45
import { Span, Transaction } from '../src';
56
import { TRACEPARENT_REGEXP } from '../src/utils';
67
import { getDefaultBrowserClientOptions } from './testutils';
8+
import { BaseTransportOptions, ClientOptions } from '@sentry/types';
79

810
describe('Span', () => {
911
let hub: Hub;
@@ -390,4 +392,57 @@ describe('Span', () => {
390392
expect(span.data).toStrictEqual({ data0: 'foo', data1: 'bar' });
391393
});
392394
});
395+
396+
describe('getBaggage and _getBaggageWithSentryValues', () => {
397+
beforeEach(() => {
398+
hub.getClient()!!.getOptions = () => {
399+
return {
400+
release: '1.0.1',
401+
environment: 'production',
402+
} as ClientOptions<BaseTransportOptions>;
403+
};
404+
});
405+
406+
test('leave baggage content untouched and just return baggage if there already is Sentry content in it', () => {
407+
const transaction = new Transaction(
408+
{
409+
name: 'tx',
410+
metadata: { baggage: createBaggage({ environment: 'myEnv' }, '') },
411+
},
412+
hub,
413+
);
414+
415+
const hubSpy = jest.spyOn(hub.getClient()!!, 'getOptions');
416+
417+
const span = transaction.startChild();
418+
419+
const baggage = span.getBaggage();
420+
421+
expect(hubSpy).toHaveBeenCalledTimes(0);
422+
expect(baggage && isSentryBaggageEmpty(baggage)).toBeFalsy();
423+
expect(baggage && getSentryBaggageItems(baggage)).toStrictEqual({ environment: 'myEnv' });
424+
expect(baggage && getThirdPartyBaggage(baggage)).toStrictEqual('');
425+
});
426+
427+
test('add Sentry baggage data to baggage if Sentry content is empty', () => {
428+
const transaction = new Transaction(
429+
{
430+
name: 'tx',
431+
metadata: { baggage: createBaggage({}, '') },
432+
},
433+
hub,
434+
);
435+
436+
const hubSpy = jest.spyOn(hub.getClient()!!, 'getOptions');
437+
438+
const span = transaction.startChild();
439+
440+
const baggage = span.getBaggage();
441+
442+
expect(hubSpy).toHaveBeenCalledTimes(1);
443+
expect(baggage && isSentryBaggageEmpty(baggage)).toBeFalsy();
444+
expect(baggage && getSentryBaggageItems(baggage)).toStrictEqual({ release: '1.0.1', environment: 'production' });
445+
expect(baggage && getThirdPartyBaggage(baggage)).toStrictEqual('');
446+
});
447+
});
393448
});

packages/types/src/span.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,4 +178,6 @@ export interface Span extends SpanContext {
178178

179179
/** return the baggage for dynamic sampling and trace propagation */
180180
getBaggage(): Baggage | undefined;
181+
182+
//_getBaggageWithSentryValues(baggage: Baggage): Baggage;
181183
}

packages/utils/src/baggage.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,17 @@ export function setBaggageValue(baggage: Baggage, key: keyof BaggageObj, value:
3131
baggage[0][key] = value;
3232
}
3333

34-
/** Check if the baggage object (i.e. the first element in the tuple) is empty */
35-
export function isBaggageEmpty(baggage: Baggage): boolean {
34+
/** Check if the Sentry part of the passed baggage (i.e. the first element in the tuple) is empty */
35+
export function isSentryBaggageEmpty(baggage: Baggage): boolean {
3636
return Object.keys(baggage[0]).length === 0;
3737
}
3838

39+
/** Check if the Sentry part of the passed baggage (i.e. the first element in the tuple) is empty */
40+
export function isBaggageEmpty(baggage: Baggage): boolean {
41+
const thirdPartyBaggage = getThirdPartyBaggage(baggage);
42+
return isSentryBaggageEmpty(baggage) && (thirdPartyBaggage == undefined || thirdPartyBaggage.length === 0);
43+
}
44+
3945
/** Returns Sentry specific baggage values */
4046
export function getSentryBaggageItems(baggage: Baggage): BaggageObj {
4147
return baggage[0];

packages/utils/test/baggage.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
createBaggage,
33
getBaggageValue,
4-
isBaggageEmpty,
4+
isSentryBaggageEmpty,
55
mergeAndSerializeBaggage,
66
parseBaggageString,
77
serializeBaggage,
@@ -98,12 +98,12 @@ describe('Baggage', () => {
9898
});
9999
});
100100

101-
describe('isBaggageEmpty', () => {
101+
describe('isSentryBaggageEmpty', () => {
102102
it.each([
103103
['returns true if the modifyable part of baggage is empty', createBaggage({}), true],
104104
['returns false if the modifyable part of baggage is not empty', createBaggage({ release: '10.0.2' }), false],
105105
])('%s', (_: string, baggage, outcome) => {
106-
expect(isBaggageEmpty(baggage)).toEqual(outcome);
106+
expect(isSentryBaggageEmpty(baggage)).toEqual(outcome);
107107
});
108108
});
109109

0 commit comments

Comments
 (0)