Skip to content

Commit f112204

Browse files
authored
ref(core): Split transaction finish into underlying _finishTransaction (#9137)
This makes it easier to extend the transaction (e.g. for POTEL) and make use of the _finishing_ code without actually sending the transaction to sentry. This is needed for #9085.
1 parent f22bb15 commit f112204

File tree

1 file changed

+88
-77
lines changed

1 file changed

+88
-77
lines changed

packages/core/src/tracing/transaction.ts

Lines changed: 88 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import type {
22
Context,
33
Contexts,
44
DynamicSamplingContext,
5-
Event,
65
Measurements,
76
MeasurementUnit,
87
Transaction as TransactionInterface,
98
TransactionContext,
9+
TransactionEvent,
1010
TransactionMetadata,
1111
} from '@sentry/types';
1212
import { dropUndefinedKeys, logger } from '@sentry/utils';
@@ -134,84 +134,10 @@ export class Transaction extends SpanClass implements TransactionInterface {
134134
* @inheritDoc
135135
*/
136136
public finish(endTimestamp?: number): string | undefined {
137-
// This transaction is already finished, so we should not flush it again.
138-
if (this.endTimestamp !== undefined) {
137+
const transaction = this._finishTransaction(endTimestamp);
138+
if (!transaction) {
139139
return undefined;
140140
}
141-
142-
if (!this.name) {
143-
__DEBUG_BUILD__ && logger.warn('Transaction has no name, falling back to `<unlabeled transaction>`.');
144-
this.name = '<unlabeled transaction>';
145-
}
146-
147-
// just sets the end timestamp
148-
super.finish(endTimestamp);
149-
150-
const client = this._hub.getClient();
151-
if (client && client.emit) {
152-
client.emit('finishTransaction', this);
153-
}
154-
155-
if (this.sampled !== true) {
156-
// At this point if `sampled !== true` we want to discard the transaction.
157-
__DEBUG_BUILD__ && logger.log('[Tracing] Discarding transaction because its trace was not chosen to be sampled.');
158-
159-
if (client) {
160-
client.recordDroppedEvent('sample_rate', 'transaction');
161-
}
162-
163-
return undefined;
164-
}
165-
166-
const finishedSpans = this.spanRecorder ? this.spanRecorder.spans.filter(s => s !== this && s.endTimestamp) : [];
167-
168-
if (this._trimEnd && finishedSpans.length > 0) {
169-
this.endTimestamp = finishedSpans.reduce((prev: SpanClass, current: SpanClass) => {
170-
if (prev.endTimestamp && current.endTimestamp) {
171-
return prev.endTimestamp > current.endTimestamp ? prev : current;
172-
}
173-
return prev;
174-
}).endTimestamp;
175-
}
176-
177-
const metadata = this.metadata;
178-
179-
const transaction: Event = {
180-
contexts: {
181-
...this._contexts,
182-
// We don't want to override trace context
183-
trace: this.getTraceContext(),
184-
},
185-
spans: finishedSpans,
186-
start_timestamp: this.startTimestamp,
187-
tags: this.tags,
188-
timestamp: this.endTimestamp,
189-
transaction: this.name,
190-
type: 'transaction',
191-
sdkProcessingMetadata: {
192-
...metadata,
193-
dynamicSamplingContext: this.getDynamicSamplingContext(),
194-
},
195-
...(metadata.source && {
196-
transaction_info: {
197-
source: metadata.source,
198-
},
199-
}),
200-
};
201-
202-
const hasMeasurements = Object.keys(this._measurements).length > 0;
203-
204-
if (hasMeasurements) {
205-
__DEBUG_BUILD__ &&
206-
logger.log(
207-
'[Measurements] Adding measurements to transaction',
208-
JSON.stringify(this._measurements, undefined, 2),
209-
);
210-
transaction.measurements = this._measurements;
211-
}
212-
213-
__DEBUG_BUILD__ && logger.log(`[Tracing] Finishing ${this.op} transaction: ${this.name}.`);
214-
215141
return this._hub.captureEvent(transaction);
216142
}
217143

@@ -289,4 +215,89 @@ export class Transaction extends SpanClass implements TransactionInterface {
289215
public setHub(hub: Hub): void {
290216
this._hub = hub;
291217
}
218+
219+
/**
220+
* Finish the transaction & prepare the event to send to Sentry.
221+
*/
222+
protected _finishTransaction(endTimestamp?: number): TransactionEvent | undefined {
223+
// This transaction is already finished, so we should not flush it again.
224+
if (this.endTimestamp !== undefined) {
225+
return undefined;
226+
}
227+
228+
if (!this.name) {
229+
__DEBUG_BUILD__ && logger.warn('Transaction has no name, falling back to `<unlabeled transaction>`.');
230+
this.name = '<unlabeled transaction>';
231+
}
232+
233+
// just sets the end timestamp
234+
super.finish(endTimestamp);
235+
236+
const client = this._hub.getClient();
237+
if (client && client.emit) {
238+
client.emit('finishTransaction', this);
239+
}
240+
241+
if (this.sampled !== true) {
242+
// At this point if `sampled !== true` we want to discard the transaction.
243+
__DEBUG_BUILD__ && logger.log('[Tracing] Discarding transaction because its trace was not chosen to be sampled.');
244+
245+
if (client) {
246+
client.recordDroppedEvent('sample_rate', 'transaction');
247+
}
248+
249+
return undefined;
250+
}
251+
252+
const finishedSpans = this.spanRecorder ? this.spanRecorder.spans.filter(s => s !== this && s.endTimestamp) : [];
253+
254+
if (this._trimEnd && finishedSpans.length > 0) {
255+
this.endTimestamp = finishedSpans.reduce((prev: SpanClass, current: SpanClass) => {
256+
if (prev.endTimestamp && current.endTimestamp) {
257+
return prev.endTimestamp > current.endTimestamp ? prev : current;
258+
}
259+
return prev;
260+
}).endTimestamp;
261+
}
262+
263+
const metadata = this.metadata;
264+
265+
const transaction: TransactionEvent = {
266+
contexts: {
267+
...this._contexts,
268+
// We don't want to override trace context
269+
trace: this.getTraceContext(),
270+
},
271+
spans: finishedSpans,
272+
start_timestamp: this.startTimestamp,
273+
tags: this.tags,
274+
timestamp: this.endTimestamp,
275+
transaction: this.name,
276+
type: 'transaction',
277+
sdkProcessingMetadata: {
278+
...metadata,
279+
dynamicSamplingContext: this.getDynamicSamplingContext(),
280+
},
281+
...(metadata.source && {
282+
transaction_info: {
283+
source: metadata.source,
284+
},
285+
}),
286+
};
287+
288+
const hasMeasurements = Object.keys(this._measurements).length > 0;
289+
290+
if (hasMeasurements) {
291+
__DEBUG_BUILD__ &&
292+
logger.log(
293+
'[Measurements] Adding measurements to transaction',
294+
JSON.stringify(this._measurements, undefined, 2),
295+
);
296+
transaction.measurements = this._measurements;
297+
}
298+
299+
__DEBUG_BUILD__ && logger.log(`[Tracing] Finishing ${this.op} transaction: ${this.name}.`);
300+
301+
return transaction;
302+
}
292303
}

0 commit comments

Comments
 (0)