Skip to content

Commit e9e1525

Browse files
authored
feat(tracing): Add context update methods to Span and Transaction (#3192)
* feat(tracing): Add context update methods to Span and Transaction * ref: Return this from updateWithContext instead of Span/Transaction
1 parent 8c20fd2 commit e9e1525

File tree

5 files changed

+160
-2
lines changed

5 files changed

+160
-2
lines changed

packages/tracing/src/span.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,44 @@ export class Span implements SpanInterface {
246246
return `${this.traceId}-${this.spanId}${sampledString}`;
247247
}
248248

249+
/**
250+
* @inheritDoc
251+
*/
252+
public toContext(): SpanContext {
253+
return dropUndefinedKeys({
254+
data: this.data,
255+
description: this.description,
256+
endTimestamp: this.endTimestamp,
257+
op: this.op,
258+
parentSpanId: this.parentSpanId,
259+
sampled: this.sampled,
260+
spanId: this.spanId,
261+
startTimestamp: this.startTimestamp,
262+
status: this.status,
263+
tags: this.tags,
264+
traceId: this.traceId,
265+
});
266+
}
267+
268+
/**
269+
* @inheritDoc
270+
*/
271+
public updateWithContext(spanContext: SpanContext): this {
272+
this.data = spanContext.data ?? {};
273+
this.description = spanContext.description;
274+
this.endTimestamp = spanContext.endTimestamp;
275+
this.op = spanContext.op;
276+
this.parentSpanId = spanContext.parentSpanId;
277+
this.sampled = spanContext.sampled;
278+
this.spanId = spanContext.spanId ?? this.spanId;
279+
this.startTimestamp = spanContext.startTimestamp ?? this.startTimestamp;
280+
this.status = spanContext.status;
281+
this.tags = spanContext.tags ?? {};
282+
this.traceId = spanContext.traceId ?? this.traceId;
283+
284+
return this;
285+
}
286+
249287
/**
250288
* @inheritDoc
251289
*/

packages/tracing/src/transaction.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { getCurrentHub, Hub } from '@sentry/hub';
22
import { Event, Measurements, Transaction as TransactionInterface, TransactionContext } from '@sentry/types';
3-
import { isInstanceOf, logger } from '@sentry/utils';
3+
import { dropUndefinedKeys, isInstanceOf, logger } from '@sentry/utils';
44

55
import { Span as SpanClass, SpanRecorder } from './span';
66

@@ -14,7 +14,7 @@ export class Transaction extends SpanClass implements TransactionInterface {
1414
*/
1515
private readonly _hub: Hub = (getCurrentHub() as unknown) as Hub;
1616

17-
private readonly _trimEnd?: boolean;
17+
private _trimEnd?: boolean;
1818

1919
/**
2020
* This constructor should never be called manually. Those instrumenting tracing should use
@@ -119,4 +119,30 @@ export class Transaction extends SpanClass implements TransactionInterface {
119119

120120
return this._hub.captureEvent(transaction);
121121
}
122+
123+
/**
124+
* @inheritDoc
125+
*/
126+
public toContext(): TransactionContext {
127+
const spanContext = super.toContext();
128+
129+
return dropUndefinedKeys({
130+
...spanContext,
131+
name: this.name,
132+
trimEnd: this._trimEnd,
133+
});
134+
}
135+
136+
/**
137+
* @inheritDoc
138+
*/
139+
public updateWithContext(transactionContext: TransactionContext): this {
140+
super.updateWithContext(transactionContext);
141+
142+
this.name = transactionContext.name ?? '';
143+
144+
this._trimEnd = transactionContext.trimEnd;
145+
146+
return this;
147+
}
122148
}

packages/tracing/test/span.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,4 +287,86 @@ describe('Span', () => {
287287
});
288288
});
289289
});
290+
291+
describe('toContext and updateWithContext', () => {
292+
test('toContext should return correct context', () => {
293+
const originalContext = { traceId: 'a', spanId: 'b', sampled: false, description: 'test', op: 'op' };
294+
const span = new Span(originalContext);
295+
296+
const newContext = span.toContext();
297+
298+
expect(newContext).toStrictEqual({
299+
...originalContext,
300+
data: {},
301+
spanId: expect.any(String),
302+
startTimestamp: expect.any(Number),
303+
tags: {},
304+
traceId: expect.any(String),
305+
});
306+
});
307+
308+
test('updateWithContext should completely change span properties', () => {
309+
const originalContext = {
310+
traceId: 'a',
311+
spanId: 'b',
312+
sampled: false,
313+
description: 'test',
314+
op: 'op',
315+
tags: {
316+
tag0: 'hello',
317+
},
318+
};
319+
const span = new Span(originalContext);
320+
321+
span.updateWithContext({
322+
traceId: 'c',
323+
spanId: 'd',
324+
sampled: true,
325+
});
326+
327+
expect(span.traceId).toBe('c');
328+
expect(span.spanId).toBe('d');
329+
expect(span.sampled).toBe(true);
330+
expect(span.description).toBe(undefined);
331+
expect(span.op).toBe(undefined);
332+
expect(span.tags).toStrictEqual({});
333+
});
334+
335+
test('using toContext and updateWithContext together should update only changed properties', () => {
336+
const originalContext = {
337+
traceId: 'a',
338+
spanId: 'b',
339+
sampled: false,
340+
description: 'test',
341+
op: 'op',
342+
tags: { tag0: 'hello' },
343+
data: { data0: 'foo' },
344+
};
345+
const span = new Span(originalContext);
346+
347+
const newContext = {
348+
...span.toContext(),
349+
description: 'new',
350+
endTimestamp: 1,
351+
op: 'new-op',
352+
sampled: true,
353+
tags: {
354+
tag1: 'bye',
355+
},
356+
};
357+
358+
if (newContext.data) newContext.data.data1 = 'bar';
359+
360+
span.updateWithContext(newContext);
361+
362+
expect(span.traceId).toBe('a');
363+
expect(span.spanId).toBe('b');
364+
expect(span.description).toBe('new');
365+
expect(span.endTimestamp).toBe(1);
366+
expect(span.op).toBe('new-op');
367+
expect(span.sampled).toBe(true);
368+
expect(span.tags).toStrictEqual({ tag1: 'bye' });
369+
expect(span.data).toStrictEqual({ data0: 'foo', data1: 'bar' });
370+
});
371+
});
290372
});

packages/types/src/span.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ export interface Span extends SpanContext {
152152
/** Return a traceparent compatible header string */
153153
toTraceparent(): string;
154154

155+
/** Returns the current span properties as a `SpanContext` */
156+
toContext(): SpanContext;
157+
158+
/** Updates the current span with a new `SpanContext` */
159+
updateWithContext(spanContext: SpanContext): this;
160+
155161
/** Convert the object to JSON for w. spans array info only */
156162
getTraceContext(): {
157163
data?: { [key: string]: any };

packages/types/src/transaction.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ export interface Transaction extends TransactionContext, Span {
6262
* Set the name of the transaction
6363
*/
6464
setName(name: string): void;
65+
66+
/** Returns the current transaction properties as a `TransactionContext` */
67+
toContext(): TransactionContext;
68+
69+
/** Updates the current transaction with a new `TransactionContext` */
70+
updateWithContext(transactionContext: TransactionContext): this;
6571
}
6672

6773
/**

0 commit comments

Comments
 (0)