diff --git a/packages/core/src/baseclient.ts b/packages/core/src/baseclient.ts index 6d246106048c..63140024d071 100644 --- a/packages/core/src/baseclient.ts +++ b/packages/core/src/baseclient.ts @@ -33,6 +33,7 @@ import { resolvedSyncPromise, SentryError, SyncPromise, + timestampInSeconds, truncate, uuid4, } from '@sentry/utils'; @@ -658,6 +659,26 @@ export abstract class BaseClient implements Client { this._updateSessionFromEvent(session, processedEvent); } + // None of the Sentry built event processor will update transaction name, + // so if the transaction name has been changed by an event processor, we know + // it has to come from custom event processor added by a user + const transactionInfo = processedEvent.transaction_info; + if (isTransaction && transactionInfo && processedEvent.transaction !== event.transaction) { + const source = 'custom'; + processedEvent.transaction_info = { + ...transactionInfo, + source, + changes: [ + ...transactionInfo.changes, + { + source, + timestamp: timestampInSeconds(), + propagations: transactionInfo.propagations, + }, + ], + }; + } + this.sendEvent(processedEvent, hint); return processedEvent; }) diff --git a/packages/core/test/lib/base.test.ts b/packages/core/test/lib/base.test.ts index 9c3fcd86f27f..4d0bf265af46 100644 --- a/packages/core/test/lib/base.test.ts +++ b/packages/core/test/lib/base.test.ts @@ -1092,6 +1092,53 @@ describe('BaseClient', () => { expect(recordLostEventSpy).toHaveBeenCalledWith('event_processor', 'error'); }); + test('mutating transaction name with event processors sets transaction name change metadata', () => { + const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, enableSend: true }); + const client = new TestClient(options); + + const transaction: Event = { + contexts: { + trace: { + op: 'pageload', + span_id: 'a3df84a60c2e4e76', + trace_id: '86f39e84263a4de99c326acab3bfe3bd', + }, + }, + environment: 'production', + event_id: '972f45b826a248bba98e990878a177e1', + spans: [], + start_timestamp: 1591603196.614865, + timestamp: 1591603196.728485, + transaction: 'initialName', + type: 'transaction', + transaction_info: { + source: 'url', + changes: [], + propagations: 3, + }, + }; + + const scope = new Scope(); + scope.addEventProcessor(event => { + event.transaction = 'updatedName'; + return event; + }); + + client.captureEvent(transaction, {}, scope); + expect(TestClient.instance!.event!.transaction).toEqual('updatedName'); + expect(TestClient.instance!.event!.transaction_info).toEqual({ + source: 'custom', + changes: [ + { + propagations: 3, + source: 'custom', + timestamp: expect.any(Number), + }, + ], + propagations: 3, + }); + }); + test('eventProcessor sends an event and logs when it crashes', () => { expect.assertions(3);