Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,16 @@ Affected SDKs: All server-side SDKs.

The LangGraph instrumentation no longer emits `gen_ai.create_agent` spans when a graph is compiled. `gen_ai.invoke_agent` and `gen_ai.execute_tool` spans are unaffected. If you reference `create_agent` spans in dashboards or alerts, update them accordingly.

### Express: errors are captured automatically

Affected SDKs: All server-side SDKs that support Express.

`expressIntegration()` now captures errors thrown from your route handlers automatically, so calling `setupExpressErrorHandler(app)` is no longer necessary — the call can be removed. It is deprecated and will be removed in the next major version. To customize which errors are captured, pass `shouldHandleError` to `expressIntegration()` (by default, 5xx errors and errors without a resolvable status are captured, while 3xx/4xx errors are not).

If you prefer to capture errors yourself, set `shouldHandleError: false` on `expressIntegration()` to opt out of automatic capture entirely, and call `Sentry.captureException` from your own error-handling middleware.

The `expressErrorHandler` and `patchExpressModule` exports are deprecated for the same reason and will be removed in the next major version.

### `@sentry/nextjs`

**Tracing removed from generated templates:** Tracing was removed from the generated Pages Router API handler, Edge API handler, and Middleware wrapper templates. Route handlers and middleware are still instrumented automatically, so no action is required for most users.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ test('Sends correct error event', async ({ baseURL }) => {
const exception = errorEvent.exception?.values?.[0];
expect(exception?.value).toBe('This is an exception with id 123');
expect(exception?.mechanism).toEqual({
type: 'auto.middleware.express',
type: 'auto.http.express',
handled: false,
});

Expand All @@ -30,6 +30,7 @@ test('Sends correct error event', async ({ baseURL }) => {
expect(errorEvent.contexts?.trace).toEqual({
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
span_id: expect.stringMatching(/[a-f0-9]{16}/),
parent_span_id: expect.stringMatching(/[a-f0-9]{16}/),
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ test('Sends correct error event', async ({ baseURL }) => {
expect(errorEvent.contexts?.trace).toEqual({
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
span_id: expect.stringMatching(/[a-f0-9]{16}/),
parent_span_id: expect.stringMatching(/[a-f0-9]{16}/),
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ test('Sends correct error event', async ({ baseURL }) => {
const exception = errorEvent.exception?.values?.[0];
expect(exception?.value).toBe('This is an exception with id 123');
expect(exception?.mechanism).toEqual({
type: 'auto.middleware.express',
type: 'auto.http.express',
handled: false,
});

Expand All @@ -30,6 +30,7 @@ test('Sends correct error event', async ({ baseURL }) => {
expect(errorEvent.contexts?.trace).toEqual({
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
span_id: expect.stringMatching(/[a-f0-9]{16}/),
parent_span_id: expect.stringMatching(/[a-f0-9]{16}/),
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ test('Sends correct error event', async ({ baseURL }) => {
expect(errorEvent.contexts?.trace).toEqual({
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
span_id: expect.stringMatching(/[a-f0-9]{16}/),
parent_span_id: expect.stringMatching(/[a-f0-9]{16}/),
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as Sentry from '@sentry/node';
import { loggingTransport } from '@sentry-internal/node-integration-tests';

Sentry.init({
traceLifecycle: 'static',
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
transport: loggingTransport,
integrations: [
Sentry.expressIntegration({
shouldHandleError: error => {
return error.message === 'error_2';
},
}),
],
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { startExpressServerAndSendPortToRunner } from '@sentry-internal/node-integration-tests';
import cors from 'cors';
import express from 'express';
Expand All @@ -15,10 +14,7 @@ app.get('/test2', (_req, _res) => {
throw new Error('error_2');
});

Sentry.setupExpressErrorHandler(app, {
shouldHandleError: error => {
return error.message === 'error_2';
},
});
// `shouldHandleError` is configured on `expressIntegration` (see the instrument file); no
// error handler needs to be registered on the app anymore.

startExpressServerAndSendPortToRunner(app);
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
values: [
{
mechanism: {
type: 'auto.middleware.express',
type: 'auto.http.express',
handled: false,
},
type: 'Error',
Expand Down Expand Up @@ -68,7 +68,7 @@
values: [
{
mechanism: {
type: 'auto.middleware.express',
type: 'auto.http.express',
handled: false,
},
type: 'Error',
Expand Down Expand Up @@ -106,7 +106,7 @@
values: [
{
mechanism: {
type: 'auto.middleware.express',
type: 'auto.http.express',
handled: false,
},
type: 'Error',
Expand Down Expand Up @@ -148,7 +148,7 @@
values: [
{
mechanism: {
type: 'auto.middleware.express',
type: 'auto.http.express',
handled: false,
},
type: 'Error',
Expand Down Expand Up @@ -187,7 +187,7 @@
values: [
{
mechanism: {
type: 'auto.middleware.express',
type: 'auto.http.express',
handled: false,
},
type: 'Error',
Expand Down Expand Up @@ -235,7 +235,7 @@
values: [
{
mechanism: {
type: 'auto.middleware.express',
type: 'auto.http.express',
handled: false,
},
type: 'Error',
Expand Down Expand Up @@ -265,30 +265,35 @@
});
});

describe('setupExpressErrorHandler options', () => {
createCjsTests(__dirname, 'scenario-should-handle-error.mjs', 'instrument-no-tracing.mjs', (createRunner, test) => {
test('allows to pass options to setupExpressErrorHandler', async () => {
const runner = createRunner()
.expect({
event: {
exception: {
values: [
{
value: 'error_2',
},
],
describe('expressIntegration shouldHandleError option', () => {
createCjsTests(
__dirname,
'scenario-should-handle-error.mjs',
'instrument-should-handle-error.mjs',
(createRunner, test) => {
test('captures only errors for which shouldHandleError returns true', async () => {

Check failure on line 274 in dev-packages/node-integration-tests/suites/express/handle-error/test.ts

View workflow job for this annotation

GitHub Actions / Node (26) Integration Tests

suites/express/handle-error/test.ts > express error handling > expressIntegration shouldHandleError option > captures only errors for which shouldHandleError returns true

Error: Test timed out in 15000ms. If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout". ❯ suites/express/handle-error/test.ts:274:9 ❯ createCjsTests utils/runner/createEsmAndCjsTests.ts:136:3 ❯ suites/express/handle-error/test.ts:269:5

Check failure on line 274 in dev-packages/node-integration-tests/suites/express/handle-error/test.ts

View workflow job for this annotation

GitHub Actions / Node (24) Integration Tests

suites/express/handle-error/test.ts > express error handling > expressIntegration shouldHandleError option > captures only errors for which shouldHandleError returns true

Error: Test timed out in 15000ms. If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout". ❯ suites/express/handle-error/test.ts:274:9 ❯ createCjsTests utils/runner/createEsmAndCjsTests.ts:136:3 ❯ suites/express/handle-error/test.ts:269:5

Check failure on line 274 in dev-packages/node-integration-tests/suites/express/handle-error/test.ts

View workflow job for this annotation

GitHub Actions / Node (20.19) Integration Tests

suites/express/handle-error/test.ts > express error handling > expressIntegration shouldHandleError option > captures only errors for which shouldHandleError returns true

Error: Test timed out in 15000ms. If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout". ❯ suites/express/handle-error/test.ts:274:9 ❯ createCjsTests utils/runner/createEsmAndCjsTests.ts:136:3 ❯ suites/express/handle-error/test.ts:269:5

Check failure on line 274 in dev-packages/node-integration-tests/suites/express/handle-error/test.ts

View workflow job for this annotation

GitHub Actions / Node (22) Integration Tests

suites/express/handle-error/test.ts > express error handling > expressIntegration shouldHandleError option > captures only errors for which shouldHandleError returns true

Error: Test timed out in 15000ms. If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout". ❯ suites/express/handle-error/test.ts:274:9 ❯ createCjsTests utils/runner/createEsmAndCjsTests.ts:136:3 ❯ suites/express/handle-error/test.ts:269:5

Check failure on line 274 in dev-packages/node-integration-tests/suites/express/handle-error/test.ts

View workflow job for this annotation

GitHub Actions / Node (24) (TS 5.0) Integration Tests

suites/express/handle-error/test.ts > express error handling > expressIntegration shouldHandleError option > captures only errors for which shouldHandleError returns true

Error: Test timed out in 15000ms. If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout". ❯ suites/express/handle-error/test.ts:274:9 ❯ createCjsTests utils/runner/createEsmAndCjsTests.ts:136:3 ❯ suites/express/handle-error/test.ts:269:5
const runner = createRunner()
.expect({
event: {
exception: {
values: [
{
value: 'error_2',
},
],
},
},
},
})
.start();
})
.start();

// this error is filtered & ignored
runner.makeRequest('get', '/test1', { expectError: true });
// this error is actually captured
runner.makeRequest('get', '/test2', { expectError: true });
// this error is filtered & ignored
runner.makeRequest('get', '/test1', { expectError: true });
// this error is actually captured
runner.makeRequest('get', '/test2', { expectError: true });

await runner.completed();
});
});
await runner.completed();
});
},
);
});
});
2 changes: 2 additions & 0 deletions packages/astro/src/index.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export {
dedupeIntegration,
defaultStackParser,
endSession,
// oxlint-disable-next-line typescript/no-deprecated
expressErrorHandler,
expressIntegration,
extraErrorDataIntegration,
Expand Down Expand Up @@ -123,6 +124,7 @@ export {
setTags,
setAttribute,
setAttributes,
// oxlint-disable-next-line typescript/no-deprecated
setupExpressErrorHandler,
setupHapiErrorHandler,
setupKoaErrorHandler,
Expand Down
2 changes: 2 additions & 0 deletions packages/aws-serverless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ export {
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
dataloaderIntegration,
expressIntegration,
// oxlint-disable-next-line typescript/no-deprecated
expressErrorHandler,
// oxlint-disable-next-line typescript/no-deprecated
setupExpressErrorHandler,
koaIntegration,
setupKoaErrorHandler,
Expand Down
2 changes: 2 additions & 0 deletions packages/bun/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ export {
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
dataloaderIntegration,
expressIntegration,
// oxlint-disable-next-line typescript/no-deprecated
expressErrorHandler,
// oxlint-disable-next-line typescript/no-deprecated
setupExpressErrorHandler,
fastifyIntegration,
setupFastifyErrorHandler,
Expand Down
14 changes: 14 additions & 0 deletions packages/core/src/integrations/express/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
* limitations under the License.
*/

// This whole module backs the deprecated Express exports (superseded by `expressIntegration()`), so it
// references its own deprecated types/functions throughout.
/* oxlint-disable typescript/no-deprecated */

import { debug } from '../../utils/debug-logger';
import { captureException } from '../../exports';
import { DEBUG_BUILD } from '../../debug-build';
Expand Down Expand Up @@ -67,6 +71,9 @@ import { getDefaultExport } from '../../utils/get-default-export';
*
* Sentry.patchExpressModule(express, () => ({}));
* ```
*
* @deprecated Express is now instrumented automatically via `expressIntegration()`. This export is
* no longer used and will be removed in the next major version.
*/
export function patchExpressModule(
moduleExports: ExpressModuleExport,
Expand Down Expand Up @@ -160,6 +167,9 @@ export function patchExpressModule(

/**
* An Express-compatible error handler, used by setupExpressErrorHandler
*
* @deprecated `expressIntegration()` now captures errors automatically. This export is deprecated
* and will be removed in the next major version.
*/
export function expressErrorHandler(options?: ExpressHandlerOptions): ExpressErrorMiddleware {
return function sentryErrorMiddleware(
Expand Down Expand Up @@ -208,6 +218,10 @@ export function expressErrorHandler(options?: ExpressHandlerOptions): ExpressErr
*
* app.listen(3000);
* ```
*
* @deprecated `expressIntegration()` now captures errors automatically, so calling this is no longer
* necessary. To customize which errors are captured, pass `shouldHandleError` to `expressIntegration()`.
* This export is deprecated and will be removed in the next major version.
*/
export function setupExpressErrorHandler(
app: {
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/integrations/express/patch-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
* limitations under the License.
*/

// This module backs the deprecated Express exports (superseded by `expressIntegration()`), so it
// references the deprecated `ExpressIntegrationOptions` type.
/* oxlint-disable typescript/no-deprecated */

import { SENTRY_OP } from '@sentry/conventions/attributes';
import { WEB_SERVER_MIDDLEWARE_SPAN_OP } from '@sentry/conventions/op';
import { DEBUG_BUILD } from '../../debug-build';
Expand Down
16 changes: 16 additions & 0 deletions packages/core/src/integrations/express/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ export type ExpressRouter = {

export type IgnoreMatcher = string | RegExp | ((name: string) => boolean);

/**
* @deprecated The core Express integration is superseded by `expressIntegration()`. This type is
* deprecated and will be removed in the next major version.
*/
export type ExpressIntegrationOptions = {
/** Ignore specific based on their name */
ignoreLayers?: IgnoreMatcher[];
Expand Down Expand Up @@ -167,15 +171,27 @@ export interface MiddlewareError extends Error {
};
}

/**
* @deprecated `expressIntegration()` captures errors automatically. This type is deprecated and will
* be removed in the next major version.
*/
export type ExpressMiddleware = (req: ExpressRequest, res: ExpressResponse, next: () => void) => void;

/**
* @deprecated `expressIntegration()` captures errors automatically. This type is deprecated and will
* be removed in the next major version.
*/
export type ExpressErrorMiddleware = (
error: MiddlewareError,
req: ExpressRequest,
res: ExpressResponse,
next: (error: MiddlewareError) => void,
) => void;

/**
* @deprecated `expressIntegration()` captures errors automatically; pass `shouldHandleError` to it to
* customize capture. This type is deprecated and will be removed in the next major version.
*/
export interface ExpressHandlerOptions {
/**
* Callback method deciding whether error should be captured and sent to Sentry
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/integrations/express/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
* limitations under the License.
*/

// This module backs the deprecated Express exports (superseded by `expressIntegration()`), so it
// references the deprecated `ExpressIntegrationOptions` type.
/* oxlint-disable typescript/no-deprecated */

import type { SpanAttributes } from '../../types/span';
import { getStoredLayers } from './request-layer-store';
import type {
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/server-exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ export { vercelWaitUntil } from './utils/vercelWaitUntil';
export { flushIfServerless } from './utils/flushIfServerless';
export { callFrameToStackFrame, watchdogTimer } from './utils/anr';
export { safeUnref as _INTERNAL_safeUnref } from './utils/timer';
// eslint-disable-next-line typescript/no-deprecated
/* oxlint-disable typescript/no-deprecated -- deprecated Express exports, kept until the next major */
export { patchExpressModule, setupExpressErrorHandler, expressErrorHandler } from './integrations/express/index';
export type {
ExpressIntegrationOptions,
ExpressHandlerOptions,
ExpressMiddleware,
ExpressErrorMiddleware,
} from './integrations/express/types';
/* oxlint-enable typescript/no-deprecated */
export {
instrumentPostgresJsSql,
_sanitizeSqlQuery as _INTERNAL_sanitizeSqlQuery,
Expand Down
2 changes: 2 additions & 0 deletions packages/elysia/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ export {
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
dataloaderIntegration,
expressIntegration,
// oxlint-disable-next-line typescript/no-deprecated
expressErrorHandler,
// oxlint-disable-next-line typescript/no-deprecated
setupExpressErrorHandler,
fastifyIntegration,
setupFastifyErrorHandler,
Expand Down
2 changes: 2 additions & 0 deletions packages/google-cloud-serverless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ export {
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
dataloaderIntegration,
expressIntegration,
// oxlint-disable-next-line typescript/no-deprecated
expressErrorHandler,
// oxlint-disable-next-line typescript/no-deprecated
setupExpressErrorHandler,
koaIntegration,
setupKoaErrorHandler,
Expand Down
1 change: 1 addition & 0 deletions packages/node/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { httpIntegration } from './integrations/http';
export { nativeNodeFetchIntegration } from './integrations/node-fetch';
export { fsIntegration } from './integrations/fs';
// oxlint-disable-next-line typescript/no-deprecated
export { expressErrorHandler, setupExpressErrorHandler } from './integrations/tracing/express';
export { fastifyIntegration, setupFastifyErrorHandler } from './integrations/tracing/fastify';
export {
Expand Down
Loading
Loading