Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): Add beforeSendTransaction #6121

Merged
merged 3 commits into from Nov 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 13 additions & 8 deletions packages/core/src/baseclient.ts
Expand Up @@ -613,13 +613,17 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
* @returns A SyncPromise that resolves with the event or rejects in case event was/will not be send.
*/
protected _processEvent(event: Event, hint: EventHint, scope?: Scope): PromiseLike<Event> {
const { beforeSend, sampleRate } = this.getOptions();
const options = this.getOptions();
const { sampleRate } = options;

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

const isTransaction = event.type === 'transaction';
const beforeSendProcessorName = isTransaction ? 'beforeSendTransaction' : 'beforeSend';
const beforeSendProcessor = options[beforeSendProcessorName];

// 1.0 === 100% events are sent
// 0.0 === 0% events are sent
// Sampling for transaction happens somewhere else
Expand All @@ -641,17 +645,17 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
}

const isInternalException = hint.data && (hint.data as { __sentry__: boolean }).__sentry__ === true;
if (isInternalException || isTransaction || !beforeSend) {
if (isInternalException || !beforeSendProcessor) {
return prepared;
}

const beforeSendResult = beforeSend(prepared, hint);
return _validateBeforeSendResult(beforeSendResult);
const beforeSendResult = beforeSendProcessor(prepared, hint);
return _validateBeforeSendResult(beforeSendResult, beforeSendProcessorName);
})
.then(processedEvent => {
if (processedEvent === null) {
this.recordDroppedEvent('before_send', event.type || 'error');
throw new SentryError('`beforeSend` returned `null`, will not send event.', 'log');
throw new SentryError(`\`${beforeSendProcessorName}\` returned \`null\`, will not send event.`, 'log');
}

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

/**
* Verifies that return value of configured `beforeSend` is of expected type, and returns the value if so.
* Verifies that return value of configured `beforeSend` or `beforeSendTransaction` is of expected type, and returns the value if so.
*/
function _validateBeforeSendResult(
beforeSendResult: PromiseLike<Event | null> | Event | null,
beforeSendProcessorName: 'beforeSend' | 'beforeSendTransaction',
): PromiseLike<Event | null> | Event | null {
const invalidValueError = '`beforeSend` must return `null` or a valid event.';
const invalidValueError = `\`${beforeSendProcessorName}\` must return \`null\` or a valid event.`;
if (isThenable(beforeSendResult)) {
return beforeSendResult.then(
event => {
Expand All @@ -779,7 +784,7 @@ function _validateBeforeSendResult(
return event;
},
e => {
throw new SentryError(`beforeSend rejected with ${e}`);
throw new SentryError(`\`${beforeSendProcessorName}\` rejected with ${e}`);
},
);
} else if (!isPlainObject(beforeSendResult) && beforeSendResult !== null) {
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/integration.ts
Expand Up @@ -65,10 +65,10 @@ export function getIntegrationsToSetup(options: Options): Integration[] {

const finalIntegrations = filterDuplicates(integrations);

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