Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 1.8k
feat(core): Record callback_error client reports for throwing user callbacks#23903
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
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -6,6 +6,14 @@ import { hasSpansEnabled } from '../utils/hasSpansEnabled'; | ||
| import { parseSampleRate } from '../utils/parseSampleRate'; | ||
| import { safeCallback } from '../utils/safeCallback'; | ||
| interface SamplingDecision { | ||
| sampled: boolean; | ||
| sampleRate?: number; | ||
| localSampleRateWasApplied?: boolean; | ||
| /** Set when the span was dropped for a reason other than the sampling decision itself. */ | ||
| dropReason?: 'callback_error'; | ||
| } | ||
| /** | ||
| * Makes a sampling decision for the given options. | ||
| * | ||
| @@ -16,15 +24,17 @@ export function sampleSpan( | ||
| options: Pick<CoreOptions, 'tracesSampleRate' | 'tracesSampler'>, | ||
| samplingContext: SamplingContext, | ||
| sampleRand: number, | ||
| ): [sampled: boolean, sampleRate?: number, localSampleRateWasApplied?: boolean] { | ||
| ): SamplingDecision { | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. m: this is API breaking, since Breaking here isn't a big deal though, so we can also do it if the tuple no longer works. But if we do, let's add a note in the migration guide. | ||
| // nothing to do if span recording is not enabled | ||
| if (!hasSpansEnabled(options)) { | ||
| return [false]; | ||
| return { sampled: false }; | ||
| } | ||
| const resolved = resolveSampleRate(options, samplingContext); | ||
| if (!resolved) { | ||
| return [false]; | ||
| // `hasSpansEnabled` guarantees either `tracesSampleRate` or `tracesSampler` is set, so the only way to end up | ||
| // without a sample rate is a throwing `tracesSampler` with nothing to fall back to. | ||
| return { sampled: false, dropReason: 'callback_error' }; | ||
| } | ||
| const [sampleRate, localSampleRateWasApplied] = resolved; | ||
| @@ -39,7 +49,7 @@ export function sampleSpan( | ||
| sampleRate, | ||
| )} of type ${JSON.stringify(typeof sampleRate)}.`, | ||
| ); | ||
| return [false]; | ||
| return { sampled: false }; | ||
| } | ||
| // if the function returned 0 (or false), or if `tracesSampleRate` is 0, it's a sign the transaction should be dropped | ||
| @@ -52,7 +62,7 @@ export function sampleSpan( | ||
| : 'a negative sampling decision was inherited or tracesSampleRate is set to 0' | ||
| }`, | ||
| ); | ||
| return [false, parsedSampleRate, localSampleRateWasApplied]; | ||
| return { sampled: false, sampleRate: parsedSampleRate, localSampleRateWasApplied }; | ||
| } | ||
| // We always compare the sample rand for the current execution context against the chosen sample rate. | ||
| @@ -69,7 +79,7 @@ export function sampleSpan( | ||
| ); | ||
| } | ||
| return [shouldSample, parsedSampleRate, localSampleRateWasApplied]; | ||
| return { sampled: shouldSample, sampleRate: parsedSampleRate, localSampleRateWasApplied }; | ||
| } | ||
| /** | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m: throwing here and in
client.tsmade me a bit suspicious because we have to be really careful to also catch our throws. Looks like there's a case in replay where we also callprepareEventwhich doesn't try/catch the call. I think this only concerns event processor throws though. This leads to us trying to re-send the replay because we assume a network error. Ultimately, we stop recording.I think we have two options how to avoid this:
notifyEventProcessorsand distinguish there.Tbqh: I haven't thought this through end-to-end, so maybe 1 is easier. I don't see us reusing
prepareEventmuch in the foreseeable future. But happy to let you make the call (also feel free to come up with something else).