From 172d043678915b3a2162d6f89ea86f4ec59260dd Mon Sep 17 00:00:00 2001 From: jennmueng Date: Thu, 21 Jan 2021 21:26:59 +0700 Subject: [PATCH 1/2] feat(tracing): Add context update methods to Span and Transaction --- packages/tracing/src/span.ts | 38 +++++++++++++ packages/tracing/src/transaction.ts | 30 ++++++++++- packages/tracing/test/span.test.ts | 82 +++++++++++++++++++++++++++++ packages/types/src/span.ts | 6 +++ packages/types/src/transaction.ts | 6 +++ 5 files changed, 160 insertions(+), 2 deletions(-) diff --git a/packages/tracing/src/span.ts b/packages/tracing/src/span.ts index dc9fbbe09ef0..669d44e2d6b1 100644 --- a/packages/tracing/src/span.ts +++ b/packages/tracing/src/span.ts @@ -246,6 +246,44 @@ export class Span implements SpanInterface { return `${this.traceId}-${this.spanId}${sampledString}`; } + /** + * @inheritDoc + */ + public toContext(): SpanContext { + return dropUndefinedKeys({ + data: this.data, + description: this.description, + endTimestamp: this.endTimestamp, + op: this.op, + parentSpanId: this.parentSpanId, + sampled: this.sampled, + spanId: this.spanId, + startTimestamp: this.startTimestamp, + status: this.status, + tags: this.tags, + traceId: this.traceId, + }); + } + + /** + * @inheritDoc + */ + public updateWithContext(spanContext: SpanContext): Span { + this.data = spanContext.data ?? {}; + this.description = spanContext.description; + this.endTimestamp = spanContext.endTimestamp; + this.op = spanContext.op; + this.parentSpanId = spanContext.parentSpanId; + this.sampled = spanContext.sampled; + this.spanId = spanContext.spanId ?? this.spanId; + this.startTimestamp = spanContext.startTimestamp ?? this.startTimestamp; + this.status = spanContext.status; + this.tags = spanContext.tags ?? {}; + this.traceId = spanContext.traceId ?? this.traceId; + + return this; + } + /** * @inheritDoc */ diff --git a/packages/tracing/src/transaction.ts b/packages/tracing/src/transaction.ts index 7f51f84462d7..6fa29462a54b 100644 --- a/packages/tracing/src/transaction.ts +++ b/packages/tracing/src/transaction.ts @@ -1,6 +1,6 @@ import { getCurrentHub, Hub } from '@sentry/hub'; import { Event, Measurements, Transaction as TransactionInterface, TransactionContext } from '@sentry/types'; -import { isInstanceOf, logger } from '@sentry/utils'; +import { dropUndefinedKeys, isInstanceOf, logger } from '@sentry/utils'; import { Span as SpanClass, SpanRecorder } from './span'; @@ -14,7 +14,7 @@ export class Transaction extends SpanClass implements TransactionInterface { */ private readonly _hub: Hub = (getCurrentHub() as unknown) as Hub; - private readonly _trimEnd?: boolean; + private _trimEnd?: boolean; /** * This constructor should never be called manually. Those instrumenting tracing should use @@ -119,4 +119,30 @@ export class Transaction extends SpanClass implements TransactionInterface { return this._hub.captureEvent(transaction); } + + /** + * @inheritDoc + */ + public toContext(): TransactionContext { + const spanContext = super.toContext(); + + return dropUndefinedKeys({ + ...spanContext, + name: this.name, + trimEnd: this._trimEnd, + }); + } + + /** + * @inheritDoc + */ + public updateWithContext(transactionContext: TransactionContext): TransactionInterface { + super.updateWithContext(transactionContext); + + this.name = transactionContext.name ?? ''; + + this._trimEnd = transactionContext.trimEnd; + + return this; + } } diff --git a/packages/tracing/test/span.test.ts b/packages/tracing/test/span.test.ts index 9ee079503c82..caf16dd26c29 100644 --- a/packages/tracing/test/span.test.ts +++ b/packages/tracing/test/span.test.ts @@ -287,4 +287,86 @@ describe('Span', () => { }); }); }); + + describe('toContext and updateWithContext', () => { + test('toContext should return correct context', () => { + const originalContext = { traceId: 'a', spanId: 'b', sampled: false, description: 'test', op: 'op' }; + const span = new Span(originalContext); + + const newContext = span.toContext(); + + expect(newContext).toStrictEqual({ + ...originalContext, + data: {}, + spanId: expect.any(String), + startTimestamp: expect.any(Number), + tags: {}, + traceId: expect.any(String), + }); + }); + + test('updateWithContext should completely change span properties', () => { + const originalContext = { + traceId: 'a', + spanId: 'b', + sampled: false, + description: 'test', + op: 'op', + tags: { + tag0: 'hello', + }, + }; + const span = new Span(originalContext); + + span.updateWithContext({ + traceId: 'c', + spanId: 'd', + sampled: true, + }); + + expect(span.traceId).toBe('c'); + expect(span.spanId).toBe('d'); + expect(span.sampled).toBe(true); + expect(span.description).toBe(undefined); + expect(span.op).toBe(undefined); + expect(span.tags).toStrictEqual({}); + }); + + test('using toContext and updateWithContext together should update only changed properties', () => { + const originalContext = { + traceId: 'a', + spanId: 'b', + sampled: false, + description: 'test', + op: 'op', + tags: { tag0: 'hello' }, + data: { data0: 'foo' }, + }; + const span = new Span(originalContext); + + const newContext = { + ...span.toContext(), + description: 'new', + endTimestamp: 1, + op: 'new-op', + sampled: true, + tags: { + tag1: 'bye', + }, + }; + + if (newContext.data) newContext.data.data1 = 'bar'; + + span.updateWithContext(newContext); + + expect(span.traceId).toBe('a'); + expect(span.spanId).toBe('b'); + expect(span.description).toBe('new'); + expect(span.endTimestamp).toBe(1); + expect(span.op).toBe('new-op'); + expect(span.sampled).toBe(true); + expect(span.tags).toStrictEqual({ tag1: 'bye' }); + expect(span.data).toStrictEqual({ data0: 'foo', data1: 'bar' }); + }); + }); }); diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 44ac522756c3..15e8b2a3311b 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -152,6 +152,12 @@ export interface Span extends SpanContext { /** Return a traceparent compatible header string */ toTraceparent(): string; + /** Returns the current span properties as a `SpanContext` */ + toContext(): SpanContext; + + /** Updates the current span with a new `SpanContext` */ + updateWithContext(spanContext: SpanContext): Span; + /** Convert the object to JSON for w. spans array info only */ getTraceContext(): { data?: { [key: string]: any }; diff --git a/packages/types/src/transaction.ts b/packages/types/src/transaction.ts index faa264bec985..f171d7f93c41 100644 --- a/packages/types/src/transaction.ts +++ b/packages/types/src/transaction.ts @@ -62,6 +62,12 @@ export interface Transaction extends TransactionContext, Span { * Set the name of the transaction */ setName(name: string): void; + + /** Returns the current transaction properties as a `TransactionContext` */ + toContext(): TransactionContext; + + /** Updates the current transaction with a new `TransactionContext` */ + updateWithContext(transactionContext: TransactionContext): Transaction; } /** From 411dd446ecff452b85f764999e232cf4fc0e7c86 Mon Sep 17 00:00:00 2001 From: jennmueng Date: Fri, 22 Jan 2021 00:05:17 +0700 Subject: [PATCH 2/2] ref: Return this from updateWithContext instead of Span/Transaction --- packages/tracing/src/span.ts | 2 +- packages/tracing/src/transaction.ts | 2 +- packages/types/src/span.ts | 2 +- packages/types/src/transaction.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/tracing/src/span.ts b/packages/tracing/src/span.ts index 669d44e2d6b1..ed3c03651ba0 100644 --- a/packages/tracing/src/span.ts +++ b/packages/tracing/src/span.ts @@ -268,7 +268,7 @@ export class Span implements SpanInterface { /** * @inheritDoc */ - public updateWithContext(spanContext: SpanContext): Span { + public updateWithContext(spanContext: SpanContext): this { this.data = spanContext.data ?? {}; this.description = spanContext.description; this.endTimestamp = spanContext.endTimestamp; diff --git a/packages/tracing/src/transaction.ts b/packages/tracing/src/transaction.ts index 6fa29462a54b..7b8b163fc377 100644 --- a/packages/tracing/src/transaction.ts +++ b/packages/tracing/src/transaction.ts @@ -136,7 +136,7 @@ export class Transaction extends SpanClass implements TransactionInterface { /** * @inheritDoc */ - public updateWithContext(transactionContext: TransactionContext): TransactionInterface { + public updateWithContext(transactionContext: TransactionContext): this { super.updateWithContext(transactionContext); this.name = transactionContext.name ?? ''; diff --git a/packages/types/src/span.ts b/packages/types/src/span.ts index 15e8b2a3311b..09b69454835e 100644 --- a/packages/types/src/span.ts +++ b/packages/types/src/span.ts @@ -156,7 +156,7 @@ export interface Span extends SpanContext { toContext(): SpanContext; /** Updates the current span with a new `SpanContext` */ - updateWithContext(spanContext: SpanContext): Span; + updateWithContext(spanContext: SpanContext): this; /** Convert the object to JSON for w. spans array info only */ getTraceContext(): { diff --git a/packages/types/src/transaction.ts b/packages/types/src/transaction.ts index f171d7f93c41..519ebb18e1dc 100644 --- a/packages/types/src/transaction.ts +++ b/packages/types/src/transaction.ts @@ -67,7 +67,7 @@ export interface Transaction extends TransactionContext, Span { toContext(): TransactionContext; /** Updates the current transaction with a new `TransactionContext` */ - updateWithContext(transactionContext: TransactionContext): Transaction; + updateWithContext(transactionContext: TransactionContext): this; } /**