-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
ref(node): Stop using registerSpanErrorInstrumentation() on server
#21169
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
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import * as Sentry from '@sentry/node'; | ||
| import { loggingTransport } from '@sentry-internal/node-integration-tests'; | ||
|
|
||
| Sentry.init({ | ||
| dsn: 'https://public@dsn.ingest.sentry.io/1337', | ||
| tracesSampleRate: 1.0, | ||
| transport: loggingTransport, | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import * as Sentry from '@sentry/node'; | ||
|
|
||
| const tracer = Sentry.getClient().tracer; | ||
|
|
||
| async function run() { | ||
| await tracer.startActiveSpan('test span name', async span => { | ||
| try { | ||
| throw new Error('Test error from tracer.startActiveSpan'); | ||
| } finally { | ||
| span.end(); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| run(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import { afterAll, describe, expect } from 'vitest'; | ||
| import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; | ||
|
|
||
| describe('tracer.startActiveSpan errors', () => { | ||
| afterAll(() => { | ||
| cleanupChildProcesses(); | ||
| }); | ||
|
|
||
| createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { | ||
| // When a callback to raw OTel `tracer.startActiveSpan` throws and the error propagates | ||
| // (uncaught), the span status is NOT automatically marked as errored. The user's `finally` | ||
| // calls `span.end()` before the error propagates, and an OTel span becomes immutable on end. | ||
| // | ||
| // Users who want auto-status-on-error should use `Sentry.startSpan` instead, or follow the | ||
| // OTel-idiomatic pattern: `span.recordException(err); span.setStatus({ code: ERROR })` in a | ||
| // `catch` inside the callback. | ||
| test('does NOT mark span errored when uncaught error escapes raw tracer.startActiveSpan callback', async () => { | ||
| await createRunner() | ||
| .expect({ | ||
| transaction: { | ||
| transaction: 'test span name', | ||
| contexts: { | ||
| trace: { | ||
| status: 'ok', | ||
| }, | ||
| }, | ||
| }, | ||
| }) | ||
| .start() | ||
| .completed(); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,10 +6,6 @@ import { logAndExitProcess } from '../utils/errorhandling'; | |
|
|
||
| type OnFatalErrorHandler = (firstError: Error, secondError?: Error) => void; | ||
|
|
||
| type TaggedListener = NodeJS.UncaughtExceptionListener & { | ||
| tag?: string; | ||
| }; | ||
|
|
||
| interface OnUncaughtExceptionOptions { | ||
| /** | ||
| * Controls if the SDK should register a handler to exit the process on uncaught errors: | ||
|
|
@@ -83,19 +79,15 @@ export function makeErrorHandler(client: NodeClient, options: OnUncaughtExceptio | |
| // exit behaviour of the SDK accordingly: | ||
| // - If other listeners are attached, do not exit. | ||
| // - If the only listener attached is ours, exit. | ||
| const userProvidedListenersCount = (global.process.listeners('uncaughtException') as TaggedListener[]).filter( | ||
| listener => { | ||
| // There are 3 listeners we ignore: | ||
| return ( | ||
| // as soon as we're using domains this listener is attached by node itself | ||
| listener.name !== 'domainUncaughtExceptionClear' && | ||
| // the handler we register for tracing | ||
| listener.tag !== 'sentry_tracingErrorCallback' && | ||
| // the handler we register in this integration | ||
| (listener as ErrorHandler)._errorHandler !== true | ||
| ); | ||
| }, | ||
| ).length; | ||
| const userProvidedListenersCount = global.process.listeners('uncaughtException').filter(listener => { | ||
|
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. hmm this change has me slightly suspicious because IIUC it implies that the
Member
Author
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. yeah also not sure, the code was here to handle the theoretical case where this would have worked but it hasn't - either it used to work differently back in the day, or it never worked - there was also not really test coverage for this as far as I can tell 😬 |
||
| // There are 3 listeners we ignore: | ||
| return ( | ||
| // as soon as we're using domains this listener is attached by node itself | ||
| listener.name !== 'domainUncaughtExceptionClear' && | ||
| // the handler we register in this integration | ||
| (listener as ErrorHandler)._errorHandler !== true | ||
| ); | ||
| }).length; | ||
|
|
||
| const processWouldExit = userProvidedListenersCount === 0; | ||
| const shouldApplyFatalHandlingLogic = options.exitEvenIfOtherHandlersAreRegistered || processWouldExit; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.