Skip to content

Commit 782f2f5

Browse files
authored
feat(tracing): Add transaction source field (#5367)
This patch adds `source` information to `Transaction`, which is typed by `TransactionSource` in `@sentry/tracing`. This helps track how the name of a transaction was determined, which will be used by the server for server-side controls. For now, we are placing the `source` field under transaction metadata. In the future, we can move this up into a top level API (an argument to `startTransaction` or `transaction.setSource`) if needed, but this should be fine to get us started. For next steps, after this patch gets merged, we will start going through various routing instrumentation frameworks and adding transaction source.
1 parent ba4a5e7 commit 782f2f5

File tree

5 files changed

+81
-3
lines changed

5 files changed

+81
-3
lines changed

packages/tracing/src/transaction.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ export class Transaction extends SpanClass implements TransactionInterface {
7575
}
7676

7777
/**
78-
* Set metadata for this transaction.
79-
* @hidden
78+
* @inheritDoc
8079
*/
8180
public setMetadata(newMetadata: TransactionMetadata): void {
8281
this.metadata = { ...this.metadata, ...newMetadata };
@@ -122,6 +121,8 @@ export class Transaction extends SpanClass implements TransactionInterface {
122121
}).endTimestamp;
123122
}
124123

124+
const metadata = this.metadata;
125+
125126
const transaction: Event = {
126127
contexts: {
127128
trace: this.getTraceContext(),
@@ -133,9 +134,14 @@ export class Transaction extends SpanClass implements TransactionInterface {
133134
transaction: this.name,
134135
type: 'transaction',
135136
sdkProcessingMetadata: {
136-
...this.metadata,
137+
...metadata,
137138
baggage: this.getBaggage(),
138139
},
140+
...(metadata.source && {
141+
transaction_info: {
142+
source: metadata.source,
143+
},
144+
}),
139145
};
140146

141147
const hasMeasurements = Object.keys(this._measurements).length > 0;

packages/tracing/test/span.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,4 +474,42 @@ describe('Span', () => {
474474
expect(baggage && getThirdPartyBaggage(baggage)).toStrictEqual('');
475475
});
476476
});
477+
478+
describe('Transaction source', () => {
479+
test('is not included by default', () => {
480+
const spy = jest.spyOn(hub as any, 'captureEvent') as any;
481+
const transaction = hub.startTransaction({ name: 'test', sampled: true });
482+
expect(spy).toHaveBeenCalledTimes(0);
483+
484+
transaction.finish();
485+
486+
expect(spy).toHaveBeenCalledTimes(1);
487+
expect(spy).toHaveBeenLastCalledWith(
488+
expect.not.objectContaining({
489+
transaction_info: {
490+
source: expect.any(String),
491+
},
492+
}),
493+
);
494+
});
495+
496+
test('is included when transaction metadata is set', () => {
497+
const spy = jest.spyOn(hub as any, 'captureEvent') as any;
498+
const transaction = hub.startTransaction({ name: 'test', sampled: true });
499+
transaction.setMetadata({
500+
source: 'url',
501+
});
502+
expect(spy).toHaveBeenCalledTimes(0);
503+
504+
transaction.finish();
505+
expect(spy).toHaveBeenCalledTimes(1);
506+
expect(spy).toHaveBeenLastCalledWith(
507+
expect.objectContaining({
508+
transaction_info: {
509+
source: 'url',
510+
},
511+
}),
512+
);
513+
});
514+
});
477515
});

packages/types/src/event.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { CaptureContext } from './scope';
1111
import { SdkInfo } from './sdkinfo';
1212
import { Severity, SeverityLevel } from './severity';
1313
import { Span } from './span';
14+
import { TransactionSource } from './transaction';
1415
import { User } from './user';
1516

1617
/** JSDoc */
@@ -46,6 +47,9 @@ export interface Event {
4647
debug_meta?: DebugMeta;
4748
// A place to stash data which is needed at some point in the SDK's event processing pipeline but which shouldn't get sent to Sentry
4849
sdkProcessingMetadata?: { [key: string]: any };
50+
transaction_info?: {
51+
source: TransactionSource;
52+
};
4953
}
5054

5155
/** JSDoc */

packages/types/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export type {
7171
TransactionContext,
7272
TransactionMetadata,
7373
TransactionSamplingMethod,
74+
TransactionSource,
7475
} from './transaction';
7576
export type {
7677
DurationUnit,

packages/types/src/transaction.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ export interface Transaction extends TransactionContext, Span {
8989
/** Updates the current transaction with a new `TransactionContext` */
9090
updateWithContext(transactionContext: TransactionContext): this;
9191

92+
/**
93+
* Set metadata for this transaction.
94+
* @hidden
95+
*/
96+
setMetadata(newMetadata: TransactionMetadata): void;
97+
9298
/** return the baggage for dynamic sampling and trace propagation */
9399
getBaggage(): Baggage;
94100
}
@@ -138,4 +144,27 @@ export interface TransactionMetadata {
138144

139145
/** For transactions tracing server-side request handling, the path of the request being tracked. */
140146
requestPath?: string;
147+
148+
/** Information on how a transaction name was generated. */
149+
source?: TransactionSource;
141150
}
151+
152+
/**
153+
* Contains information about how the name of the transaction was determined. This will be used by the server to decide
154+
* whether or not to scrub identifiers from the transaction name, or replace the entire name with a placeholder.
155+
*/
156+
export type TransactionSource =
157+
/** User-defined name */
158+
| 'custom'
159+
/** Raw URL, potentially containing identifiers */
160+
| 'url'
161+
/** Parametrized URL / route */
162+
| 'route'
163+
/** Name of the view handling the request */
164+
| 'view'
165+
/** This is the default value set by Relay for legacy SDKs. */
166+
| 'unknown'
167+
/** Named after a software component, such as a function or class name. */
168+
| 'component'
169+
/** Name of a background task (e.g. a Celery task) */
170+
| 'task';

0 commit comments

Comments
 (0)