Skip to content

Commit f214732

Browse files
authored
feat(core): Add beforeSendTransaction (#6121)
This adds a new `beforeSendTransaction` option to the SDK. As one would expect from the name, it works just like `beforeSend` (in other words, it's a guaranteed-to-be-last event processor), except that it acts upon transaction events, which the original `beforeSend` doesn't. Docs PR will be linked in the PR once it's done. Ref: getsentry/rfcs#19 (comment)
1 parent 59047ec commit f214732

File tree

5 files changed

+309
-14
lines changed

5 files changed

+309
-14
lines changed

packages/core/src/baseclient.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -613,13 +613,17 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
613613
* @returns A SyncPromise that resolves with the event or rejects in case event was/will not be send.
614614
*/
615615
protected _processEvent(event: Event, hint: EventHint, scope?: Scope): PromiseLike<Event> {
616-
const { beforeSend, sampleRate } = this.getOptions();
616+
const options = this.getOptions();
617+
const { sampleRate } = options;
617618

618619
if (!this._isEnabled()) {
619620
return rejectedSyncPromise(new SentryError('SDK not enabled, will not capture event.', 'log'));
620621
}
621622

622623
const isTransaction = event.type === 'transaction';
624+
const beforeSendProcessorName = isTransaction ? 'beforeSendTransaction' : 'beforeSend';
625+
const beforeSendProcessor = options[beforeSendProcessorName];
626+
623627
// 1.0 === 100% events are sent
624628
// 0.0 === 0% events are sent
625629
// Sampling for transaction happens somewhere else
@@ -641,17 +645,17 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
641645
}
642646

643647
const isInternalException = hint.data && (hint.data as { __sentry__: boolean }).__sentry__ === true;
644-
if (isInternalException || isTransaction || !beforeSend) {
648+
if (isInternalException || !beforeSendProcessor) {
645649
return prepared;
646650
}
647651

648-
const beforeSendResult = beforeSend(prepared, hint);
649-
return _validateBeforeSendResult(beforeSendResult);
652+
const beforeSendResult = beforeSendProcessor(prepared, hint);
653+
return _validateBeforeSendResult(beforeSendResult, beforeSendProcessorName);
650654
})
651655
.then(processedEvent => {
652656
if (processedEvent === null) {
653657
this.recordDroppedEvent('before_send', event.type || 'error');
654-
throw new SentryError('`beforeSend` returned `null`, will not send event.', 'log');
658+
throw new SentryError(`\`${beforeSendProcessorName}\` returned \`null\`, will not send event.`, 'log');
655659
}
656660

657661
const session = scope && scope.getSession();
@@ -764,12 +768,13 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
764768
}
765769

766770
/**
767-
* Verifies that return value of configured `beforeSend` is of expected type, and returns the value if so.
771+
* Verifies that return value of configured `beforeSend` or `beforeSendTransaction` is of expected type, and returns the value if so.
768772
*/
769773
function _validateBeforeSendResult(
770774
beforeSendResult: PromiseLike<Event | null> | Event | null,
775+
beforeSendProcessorName: 'beforeSend' | 'beforeSendTransaction',
771776
): PromiseLike<Event | null> | Event | null {
772-
const invalidValueError = '`beforeSend` must return `null` or a valid event.';
777+
const invalidValueError = `\`${beforeSendProcessorName}\` must return \`null\` or a valid event.`;
773778
if (isThenable(beforeSendResult)) {
774779
return beforeSendResult.then(
775780
event => {
@@ -779,7 +784,7 @@ function _validateBeforeSendResult(
779784
return event;
780785
},
781786
e => {
782-
throw new SentryError(`beforeSend rejected with ${e}`);
787+
throw new SentryError(`\`${beforeSendProcessorName}\` rejected with ${e}`);
783788
},
784789
);
785790
} else if (!isPlainObject(beforeSendResult) && beforeSendResult !== null) {

packages/core/src/integration.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ export function getIntegrationsToSetup(options: Options): Integration[] {
6565

6666
const finalIntegrations = filterDuplicates(integrations);
6767

68-
// The `Debug` integration prints copies of the `event` and `hint` which will be passed to `beforeSend`. It therefore
69-
// has to run after all other integrations, so that the changes of all event processors will be reflected in the
70-
// printed values. For lack of a more elegant way to guarantee that, we therefore locate it and, assuming it exists,
71-
// pop it out of its current spot and shove it onto the end of the array.
68+
// The `Debug` integration prints copies of the `event` and `hint` which will be passed to `beforeSend` or
69+
// `beforeSendTransaction`. It therefore has to run after all other integrations, so that the changes of all event
70+
// processors will be reflected in the printed values. For lack of a more elegant way to guarantee that, we therefore
71+
// locate it and, assuming it exists, pop it out of its current spot and shove it onto the end of the array.
7272
const debugIndex = finalIntegrations.findIndex(integration => integration.name === 'Debug');
7373
if (debugIndex !== -1) {
7474
const [debugInstance] = finalIntegrations.splice(debugIndex, 1);

0 commit comments

Comments
 (0)