From 1adaaac34005d4fea7f3ffdaca4d6a901b348216 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Tue, 13 Aug 2024 10:47:41 -0400 Subject: [PATCH 01/25] feat(node): add genericPool integration using opentelemetry instrumentation Signed-off-by: Kaung Zin Hein --- packages/node/package.json | 1 + .../src/integrations/tracing/genericPool.ts | 33 +++++++++++++++++++ .../node/src/integrations/tracing/index.ts | 3 ++ 3 files changed, 37 insertions(+) create mode 100644 packages/node/src/integrations/tracing/genericPool.ts diff --git a/packages/node/package.json b/packages/node/package.json index 9ec4c8a7e389..7b570302e0f2 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -88,6 +88,7 @@ "@opentelemetry/resources": "^1.25.1", "@opentelemetry/sdk-trace-base": "^1.25.1", "@opentelemetry/semantic-conventions": "^1.25.1", + "@opentelemetry/instrumentation-generic-pool": "^0.38.0", "@prisma/instrumentation": "5.17.0", "@sentry/core": "8.25.0", "@sentry/opentelemetry": "8.25.0", diff --git a/packages/node/src/integrations/tracing/genericPool.ts b/packages/node/src/integrations/tracing/genericPool.ts new file mode 100644 index 000000000000..1c7725f95e45 --- /dev/null +++ b/packages/node/src/integrations/tracing/genericPool.ts @@ -0,0 +1,33 @@ +import { GenericPoolInstrumentation } from '@opentelemetry/instrumentation-generic-pool'; +import { defineIntegration, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, spanToJSON } from '@sentry/core'; +import type { IntegrationFn } from '@sentry/types'; +import { generateInstrumentOnce } from '../../otel/instrument'; + +const INTEGRATION_NAME = 'GenericPool'; + +export const instrumentGenericPool = generateInstrumentOnce(INTEGRATION_NAME, () => new GenericPoolInstrumentation({})); + +const _genericPoolIntegration = (() => { + return { + name: INTEGRATION_NAME, + setupOnce() { + instrumentGenericPool(); + }, + + setup(client) { + client.on('spanStart', span => { + const spanJSON = spanToJSON(span); + if (spanJSON.description === 'generic-pool.acquire') { + span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.generic-pool'); + } + }); + }, + }; +}) satisfies IntegrationFn; + +/** + * GenericPool integration + * + * Capture tracing data for GenericPool. + */ +export const genericPoolIntegration = defineIntegration(_genericPoolIntegration); diff --git a/packages/node/src/integrations/tracing/index.ts b/packages/node/src/integrations/tracing/index.ts index 886c11683674..5e080f8b5ece 100644 --- a/packages/node/src/integrations/tracing/index.ts +++ b/packages/node/src/integrations/tracing/index.ts @@ -14,6 +14,7 @@ import { instrumentMysql2, mysql2Integration } from './mysql2'; import { instrumentNest, nestIntegration } from './nest/nest'; import { instrumentPostgres, postgresIntegration } from './postgres'; import { instrumentRedis, redisIntegration } from './redis'; +import { instrumentGenericPool, genericPoolIntegration} from './genericPool' /** * With OTEL, all performance integrations will be added, as OTEL only initializes them when the patched package is actually required. @@ -37,6 +38,7 @@ export function getAutoPerformanceIntegrations(): Integration[] { hapiIntegration(), koaIntegration(), connectIntegration(), + genericPoolIntegration(), ]; } @@ -61,5 +63,6 @@ export function getOpenTelemetryInstrumentationToPreload(): (((options?: any) => instrumentHapi, instrumentGraphql, instrumentRedis, + instrumentGenericPool, ]; } From 69f52db59ea4498e61e7999b65fd73a776e926b0 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Tue, 13 Aug 2024 10:47:41 -0400 Subject: [PATCH 02/25] feat(node): Add genericPool integration using opentelemetry instrumentation Set up initial code and include this instrumentation as a default integration. Signed-off-by: Kaung Zin Hein From 0c06d16eac9e05ecb6947b479e1e488ca9ed54c4 Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Tue, 13 Aug 2024 17:31:22 +0200 Subject: [PATCH 03/25] fix(nestjs): Exception filters in main app module are not being executed (#13278) [ref](https://github.com/getsentry/sentry-javascript/issues/12351) This PR moves the `SentryGlobalFilter` out of the root module, which led to the filter overriding user exception filters in certain scenarios. Now there is two ways to setup sentry error monitoring: - If users have no catch-all exception filter in their application they add the `SentryGlobalFilter` as a provider in their main module. - If users have a catch-all exception filter (annotated with `@Catch()` they can use the newly introduced `SentryCaptureException()` decorator to capture alle exceptions caught by this filter. Testing: Added a new sample application to test the second setup option and expanded the test suite in general. Side note: - Also removed the `@sentry/microservices` dependency again, since it does not come out of the box with every nest application so we cannot rely on it. --- .../nestjs-basic/src/app.controller.ts | 16 +- .../nestjs-basic/src/app.module.ts | 16 +- .../src/example-global-filter.exception.ts | 5 + .../nestjs-basic/src/example-global.filter.ts | 19 ++ .../src/example-local-filter.exception.ts | 5 + .../nestjs-basic/src/example-local.filter.ts | 19 ++ .../nestjs-basic/tests/errors.test.ts | 70 +++++ .../.gitignore | 56 ++++ .../nestjs-with-submodules-decorator/.npmrc | 2 + .../nest-cli.json | 8 + .../package.json | 47 ++++ .../playwright.config.mjs | 7 + .../src/app.controller.ts | 37 +++ .../src/app.module.ts | 32 +++ .../src/app.service.ts | 14 + .../src/example-global.filter.ts | 20 ++ .../src/example-local.exception.ts | 5 + .../src/example-local.filter.ts | 19 ++ .../example.controller.ts | 6 +- .../example.exception.ts | 2 +- .../example.filter.ts | 8 +- .../example.module.ts | 6 +- .../example.controller.ts | 25 ++ .../example.exception.ts | 5 + .../example.filter.ts | 13 + .../example.module.ts | 16 ++ .../example.controller.ts | 19 ++ .../example.exception.ts | 5 + .../example.filter.ts | 13 + .../example.module.ts | 9 + .../src/example-specific.exception.ts | 5 + .../src/example-specific.filter.ts | 19 ++ .../src/instrument.ts | 12 + .../src/main.ts | 15 + .../start-event-proxy.mjs | 6 + .../tests/errors.test.ts | 266 ++++++++++++++++++ .../tests/transactions.test.ts | 240 ++++++++++++++++ .../tsconfig.build.json | 4 + .../tsconfig.json | 21 ++ .../src/app.controller.ts | 16 +- .../nestjs-with-submodules/src/app.module.ts | 20 +- .../src/example-local.exception.ts | 5 + .../src/example-local.filter.ts | 19 ++ .../example.controller.ts | 17 ++ .../example.exception.ts | 5 + .../example.filter.ts | 13 + .../example.module.ts | 16 ++ .../example.controller.ts | 5 + .../src/example-specific.exception.ts | 5 + .../src/example-specific.filter.ts | 19 ++ .../tests/errors.test.ts | 136 +++++++-- .../tests/transactions.test.ts | 47 +++- packages/nestjs/README.md | 45 ++- packages/nestjs/package.json | 6 +- packages/nestjs/src/error-decorator.ts | 24 ++ packages/nestjs/src/helpers.ts | 13 + packages/nestjs/src/index.ts | 1 + packages/nestjs/src/setup.ts | 20 +- .../nest/sentry-nest-instrumentation.ts | 4 +- yarn.lock | 8 - 60 files changed, 1479 insertions(+), 77 deletions(-) create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-global-filter.exception.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-global.filter.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-local-filter.exception.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-local.filter.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/.gitignore create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/.npmrc create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/nest-cli.json create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/playwright.config.mjs create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.controller.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.module.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.service.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-global.filter.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-local.exception.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-local.filter.ts rename dev-packages/e2e-tests/test-applications/{nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order => nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first}/example.controller.ts (63%) rename dev-packages/e2e-tests/test-applications/{nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order => nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first}/example.exception.ts (54%) rename dev-packages/e2e-tests/test-applications/{nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order => nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first}/example.filter.ts (52%) rename dev-packages/e2e-tests/test-applications/{nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order => nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first}/example.module.ts (56%) create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.controller.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.exception.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.filter.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.module.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.controller.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.exception.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.filter.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.module.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-specific.exception.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-specific.filter.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/instrument.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/main.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/start-event-proxy.mjs create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/errors.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tsconfig.build.json create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tsconfig.json create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-local.exception.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-local.filter.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.controller.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.exception.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.filter.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.module.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-specific.exception.ts create mode 100644 dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-specific.filter.ts create mode 100644 packages/nestjs/src/error-decorator.ts create mode 100644 packages/nestjs/src/helpers.ts diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts index ec0a921da2c4..9cda3c96f9a6 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts @@ -1,10 +1,14 @@ -import { Controller, Get, Param, ParseIntPipe, UseGuards, UseInterceptors } from '@nestjs/common'; +import { Controller, Get, Param, ParseIntPipe, UseFilters, UseGuards, UseInterceptors } from '@nestjs/common'; import { flush } from '@sentry/nestjs'; import { AppService } from './app.service'; +import { ExampleExceptionGlobalFilter } from './example-global-filter.exception'; +import { ExampleExceptionLocalFilter } from './example-local-filter.exception'; +import { ExampleLocalFilter } from './example-local.filter'; import { ExampleGuard } from './example.guard'; import { ExampleInterceptor } from './example.interceptor'; @Controller() +@UseFilters(ExampleLocalFilter) export class AppController { constructor(private readonly appService: AppService) {} @@ -74,4 +78,14 @@ export class AppController { async flush() { await flush(); } + + @Get('example-exception-global-filter') + async exampleExceptionGlobalFilter() { + throw new ExampleExceptionGlobalFilter(); + } + + @Get('example-exception-local-filter') + async exampleExceptionLocalFilter() { + throw new ExampleExceptionLocalFilter(); + } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.module.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.module.ts index b2aad014c745..3de3c82dc925 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.module.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.module.ts @@ -1,14 +1,26 @@ import { MiddlewareConsumer, Module } from '@nestjs/common'; +import { APP_FILTER } from '@nestjs/core'; import { ScheduleModule } from '@nestjs/schedule'; -import { SentryModule } from '@sentry/nestjs/setup'; +import { SentryGlobalFilter, SentryModule } from '@sentry/nestjs/setup'; import { AppController } from './app.controller'; import { AppService } from './app.service'; +import { ExampleGlobalFilter } from './example-global.filter'; import { ExampleMiddleware } from './example.middleware'; @Module({ imports: [SentryModule.forRoot(), ScheduleModule.forRoot()], controllers: [AppController], - providers: [AppService], + providers: [ + AppService, + { + provide: APP_FILTER, + useClass: SentryGlobalFilter, + }, + { + provide: APP_FILTER, + useClass: ExampleGlobalFilter, + }, + ], }) export class AppModule { configure(consumer: MiddlewareConsumer): void { diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-global-filter.exception.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-global-filter.exception.ts new file mode 100644 index 000000000000..41981ba748fe --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-global-filter.exception.ts @@ -0,0 +1,5 @@ +export class ExampleExceptionGlobalFilter extends Error { + constructor() { + super('Original global example exception!'); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-global.filter.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-global.filter.ts new file mode 100644 index 000000000000..988696d0e13d --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-global.filter.ts @@ -0,0 +1,19 @@ +import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter } from '@nestjs/common'; +import { Request, Response } from 'express'; +import { ExampleExceptionGlobalFilter } from './example-global-filter.exception'; + +@Catch(ExampleExceptionGlobalFilter) +export class ExampleGlobalFilter implements ExceptionFilter { + catch(exception: BadRequestException, host: ArgumentsHost): void { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + const request = ctx.getRequest(); + + response.status(400).json({ + statusCode: 400, + timestamp: new Date().toISOString(), + path: request.url, + message: 'Example exception was handled by global filter!', + }); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-local-filter.exception.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-local-filter.exception.ts new file mode 100644 index 000000000000..8f76520a3b94 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-local-filter.exception.ts @@ -0,0 +1,5 @@ +export class ExampleExceptionLocalFilter extends Error { + constructor() { + super('Original local example exception!'); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-local.filter.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-local.filter.ts new file mode 100644 index 000000000000..505217f5dcbd --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/example-local.filter.ts @@ -0,0 +1,19 @@ +import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter } from '@nestjs/common'; +import { Request, Response } from 'express'; +import { ExampleExceptionLocalFilter } from './example-local-filter.exception'; + +@Catch(ExampleExceptionLocalFilter) +export class ExampleLocalFilter implements ExceptionFilter { + catch(exception: BadRequestException, host: ArgumentsHost): void { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + const request = ctx.getRequest(); + + response.status(400).json({ + statusCode: 400, + timestamp: new Date().toISOString(), + path: request.url, + message: 'Example exception was handled by local filter!', + }); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts index 34e626cb8c52..ee7d12dd22ca 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts @@ -94,3 +94,73 @@ test('Does not send RpcExceptions to Sentry', async ({ baseURL }) => { expect(errorEventOccurred).toBe(false); }); + +test('Global exception filter registered in main module is applied and exception is not sent to Sentry', async ({ + baseURL, +}) => { + let errorEventOccurred = false; + + waitForError('nestjs-basic', event => { + if (!event.type && event.exception?.values?.[0]?.value === 'Example exception was handled by global filter!') { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /example-exception-global-filter'; + }); + + const transactionEventPromise = waitForTransaction('nestjs-basic', transactionEvent => { + return transactionEvent?.transaction === 'GET /example-exception-global-filter'; + }); + + const response = await fetch(`${baseURL}/example-exception-global-filter`); + const responseBody = await response.json(); + + expect(response.status).toBe(400); + expect(responseBody).toEqual({ + statusCode: 400, + timestamp: expect.any(String), + path: '/example-exception-global-filter', + message: 'Example exception was handled by global filter!', + }); + + await transactionEventPromise; + + (await fetch(`${baseURL}/flush`)).text(); + + expect(errorEventOccurred).toBe(false); +}); + +test('Local exception filter registered in main module is applied and exception is not sent to Sentry', async ({ + baseURL, +}) => { + let errorEventOccurred = false; + + waitForError('nestjs-basic', event => { + if (!event.type && event.exception?.values?.[0]?.value === 'Example exception was handled by local filter!') { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /example-exception-local-filter'; + }); + + const transactionEventPromise = waitForTransaction('nestjs-basic', transactionEvent => { + return transactionEvent?.transaction === 'GET /example-exception-local-filter'; + }); + + const response = await fetch(`${baseURL}/example-exception-local-filter`); + const responseBody = await response.json(); + + expect(response.status).toBe(400); + expect(responseBody).toEqual({ + statusCode: 400, + timestamp: expect.any(String), + path: '/example-exception-local-filter', + message: 'Example exception was handled by local filter!', + }); + + await transactionEventPromise; + + (await fetch(`${baseURL}/flush`)).text(); + + expect(errorEventOccurred).toBe(false); +}); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/.gitignore b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/.gitignore new file mode 100644 index 000000000000..4b56acfbebf4 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/.gitignore @@ -0,0 +1,56 @@ +# compiled output +/dist +/node_modules +/build + +# Logs +logs +*.log +npm-debug.log* +pnpm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# OS +.DS_Store + +# Tests +/coverage +/.nyc_output + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# temp directory +.temp +.tmp + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/.npmrc b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/.npmrc new file mode 100644 index 000000000000..070f80f05092 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/.npmrc @@ -0,0 +1,2 @@ +@sentry:registry=http://127.0.0.1:4873 +@sentry-internal:registry=http://127.0.0.1:4873 diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/nest-cli.json b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/nest-cli.json new file mode 100644 index 000000000000..f9aa683b1ad5 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/nest-cli.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "compilerOptions": { + "deleteOutDir": true + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json new file mode 100644 index 000000000000..9cc3641d2322 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json @@ -0,0 +1,47 @@ +{ + "name": "nestjs-with-submodules-decorator", + "version": "0.0.1", + "private": true, + "scripts": { + "build": "nest build", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "start": "nest start", + "start:dev": "nest start --watch", + "start:debug": "nest start --debug --watch", + "start:prod": "node dist/main", + "clean": "npx rimraf node_modules pnpm-lock.yaml", + "test": "playwright test", + "test:build": "pnpm install", + "test:assert": "pnpm test" + }, + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0", + "@nestjs/platform-express": "^10.0.0", + "@sentry/nestjs": "latest || *", + "@sentry/types": "latest || *", + "reflect-metadata": "^0.2.0", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@playwright/test": "^1.44.1", + "@sentry-internal/test-utils": "link:../../../test-utils", + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/node": "18.15.1", + "@types/supertest": "^6.0.0", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "prettier": "^3.0.0", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-loader": "^9.4.3", + "tsconfig-paths": "^4.2.0", + "typescript": "^4.9.5" + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/playwright.config.mjs b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/playwright.config.mjs new file mode 100644 index 000000000000..31f2b913b58b --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/playwright.config.mjs @@ -0,0 +1,7 @@ +import { getPlaywrightConfig } from '@sentry-internal/test-utils'; + +const config = getPlaywrightConfig({ + startCommand: `pnpm start`, +}); + +export default config; diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.controller.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.controller.ts new file mode 100644 index 000000000000..efce824a20c3 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.controller.ts @@ -0,0 +1,37 @@ +import { Controller, Get, Param, UseFilters } from '@nestjs/common'; +import { flush } from '@sentry/nestjs'; +import { AppService } from './app.service'; +import { ExampleExceptionLocalFilter } from './example-local.exception'; +import { ExampleLocalFilter } from './example-local.filter'; +import { ExampleExceptionSpecificFilter } from './example-specific.exception'; + +@Controller() +@UseFilters(ExampleLocalFilter) +export class AppController { + constructor(private readonly appService: AppService) {} + + @Get('test-exception/:id') + async testException(@Param('id') id: string) { + return this.appService.testException(id); + } + + @Get('test-expected-exception/:id') + async testExpectedException(@Param('id') id: string) { + return this.appService.testExpectedException(id); + } + + @Get('flush') + async flush() { + await flush(); + } + + @Get('example-exception-specific-filter') + async exampleExceptionGlobalFilter() { + throw new ExampleExceptionSpecificFilter(); + } + + @Get('example-exception-local-filter') + async exampleExceptionLocalFilter() { + throw new ExampleExceptionLocalFilter(); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.module.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.module.ts new file mode 100644 index 000000000000..77cf85a4fa9c --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.module.ts @@ -0,0 +1,32 @@ +import { Module } from '@nestjs/common'; +import { APP_FILTER } from '@nestjs/core'; +import { SentryModule } from '@sentry/nestjs/setup'; +import { AppController } from './app.controller'; +import { AppService } from './app.service'; +import { ExampleWrappedGlobalFilter } from './example-global.filter'; +import { ExampleModuleGlobalFilterRegisteredFirst } from './example-module-global-filter-registered-first/example.module'; +import { ExampleModuleGlobalFilter } from './example-module-global-filter/example.module'; +import { ExampleModuleLocalFilter } from './example-module-local-filter/example.module'; +import { ExampleSpecificFilter } from './example-specific.filter'; + +@Module({ + imports: [ + ExampleModuleGlobalFilterRegisteredFirst, + SentryModule.forRoot(), + ExampleModuleGlobalFilter, + ExampleModuleLocalFilter, + ], + controllers: [AppController], + providers: [ + AppService, + { + provide: APP_FILTER, + useClass: ExampleWrappedGlobalFilter, + }, + { + provide: APP_FILTER, + useClass: ExampleSpecificFilter, + }, + ], +}) +export class AppModule {} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.service.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.service.ts new file mode 100644 index 000000000000..242408023586 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/app.service.ts @@ -0,0 +1,14 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; + +@Injectable() +export class AppService { + constructor() {} + + testException(id: string) { + throw new Error(`This is an exception with id ${id}`); + } + + testExpectedException(id: string) { + throw new HttpException(`This is an expected exception with id ${id}`, HttpStatus.FORBIDDEN); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-global.filter.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-global.filter.ts new file mode 100644 index 000000000000..cee50d0d2c7c --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-global.filter.ts @@ -0,0 +1,20 @@ +import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter } from '@nestjs/common'; +import { WithSentry } from '@sentry/nestjs'; +import { Request, Response } from 'express'; + +@Catch() +export class ExampleWrappedGlobalFilter implements ExceptionFilter { + @WithSentry() + catch(exception: BadRequestException, host: ArgumentsHost): void { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + const request = ctx.getRequest(); + + response.status(501).json({ + statusCode: 501, + timestamp: new Date().toISOString(), + path: request.url, + message: 'Example exception was handled by global filter!', + }); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-local.exception.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-local.exception.ts new file mode 100644 index 000000000000..8f76520a3b94 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-local.exception.ts @@ -0,0 +1,5 @@ +export class ExampleExceptionLocalFilter extends Error { + constructor() { + super('Original local example exception!'); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-local.filter.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-local.filter.ts new file mode 100644 index 000000000000..0e93e5f7fac2 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-local.filter.ts @@ -0,0 +1,19 @@ +import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter } from '@nestjs/common'; +import { Request, Response } from 'express'; +import { ExampleExceptionLocalFilter } from './example-local.exception'; + +@Catch(ExampleExceptionLocalFilter) +export class ExampleLocalFilter implements ExceptionFilter { + catch(exception: BadRequestException, host: ArgumentsHost): void { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + const request = ctx.getRequest(); + + response.status(400).json({ + statusCode: 400, + timestamp: new Date().toISOString(), + path: request.url, + message: 'Example exception was handled by local filter!', + }); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.controller.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.controller.ts similarity index 63% rename from dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.controller.ts rename to dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.controller.ts index 028af4a43f87..967886948a25 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.controller.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.controller.ts @@ -1,13 +1,13 @@ import { Controller, Get } from '@nestjs/common'; -import { ExampleExceptionWrongRegistrationOrder } from './example.exception'; +import { ExampleExceptionRegisteredFirst } from './example.exception'; -@Controller('example-module-wrong-order') +@Controller('example-module-registered-first') export class ExampleController { constructor() {} @Get('/expected-exception') getCaughtException(): string { - throw new ExampleExceptionWrongRegistrationOrder(); + throw new ExampleExceptionRegisteredFirst(); } @Get('/unexpected-exception') diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.exception.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.exception.ts similarity index 54% rename from dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.exception.ts rename to dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.exception.ts index 0e4f58314fa2..9bb3b5948343 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.exception.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.exception.ts @@ -1,4 +1,4 @@ -export class ExampleExceptionWrongRegistrationOrder extends Error { +export class ExampleExceptionRegisteredFirst extends Error { constructor() { super('Something went wrong in the example module!'); } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.filter.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.filter.ts similarity index 52% rename from dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.filter.ts rename to dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.filter.ts index 6ecdf88937aa..6c3b81d395b5 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.filter.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.filter.ts @@ -1,11 +1,11 @@ import { ArgumentsHost, BadRequestException, Catch } from '@nestjs/common'; import { BaseExceptionFilter } from '@nestjs/core'; -import { ExampleExceptionWrongRegistrationOrder } from './example.exception'; +import { ExampleExceptionRegisteredFirst } from './example.exception'; -@Catch(ExampleExceptionWrongRegistrationOrder) -export class ExampleExceptionFilterWrongRegistrationOrder extends BaseExceptionFilter { +@Catch(ExampleExceptionRegisteredFirst) +export class ExampleExceptionFilterRegisteredFirst extends BaseExceptionFilter { catch(exception: unknown, host: ArgumentsHost) { - if (exception instanceof ExampleExceptionWrongRegistrationOrder) { + if (exception instanceof ExampleExceptionRegisteredFirst) { return super.catch(new BadRequestException(exception.message), host); } return super.catch(exception, host); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.module.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.module.ts similarity index 56% rename from dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.module.ts rename to dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.module.ts index c98a5757b01c..8751856f99cd 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-wrong-registration-order/example.module.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter-registered-first/example.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common'; import { APP_FILTER } from '@nestjs/core'; import { ExampleController } from './example.controller'; -import { ExampleExceptionFilterWrongRegistrationOrder } from './example.filter'; +import { ExampleExceptionFilterRegisteredFirst } from './example.filter'; @Module({ imports: [], @@ -9,8 +9,8 @@ import { ExampleExceptionFilterWrongRegistrationOrder } from './example.filter'; providers: [ { provide: APP_FILTER, - useClass: ExampleExceptionFilterWrongRegistrationOrder, + useClass: ExampleExceptionFilterRegisteredFirst, }, ], }) -export class ExampleModuleGlobalFilterWrongRegistrationOrder {} +export class ExampleModuleGlobalFilterRegisteredFirst {} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.controller.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.controller.ts new file mode 100644 index 000000000000..53356e906130 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.controller.ts @@ -0,0 +1,25 @@ +import { Controller, Get } from '@nestjs/common'; +import * as Sentry from '@sentry/nestjs'; +import { ExampleException } from './example.exception'; + +@Controller('example-module') +export class ExampleController { + constructor() {} + + @Get('/expected-exception') + getCaughtException(): string { + throw new ExampleException(); + } + + @Get('/unexpected-exception') + getUncaughtException(): string { + throw new Error(`This is an uncaught exception!`); + } + + @Get('/transaction') + testTransaction() { + Sentry.startSpan({ name: 'test-span' }, () => { + Sentry.startSpan({ name: 'child-span' }, () => {}); + }); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.exception.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.exception.ts new file mode 100644 index 000000000000..ac43dddfa8dc --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.exception.ts @@ -0,0 +1,5 @@ +export class ExampleException extends Error { + constructor() { + super('Something went wrong in the example module!'); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.filter.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.filter.ts new file mode 100644 index 000000000000..848441caf855 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.filter.ts @@ -0,0 +1,13 @@ +import { ArgumentsHost, BadRequestException, Catch } from '@nestjs/common'; +import { BaseExceptionFilter } from '@nestjs/core'; +import { ExampleException } from './example.exception'; + +@Catch(ExampleException) +export class ExampleExceptionFilter extends BaseExceptionFilter { + catch(exception: unknown, host: ArgumentsHost) { + if (exception instanceof ExampleException) { + return super.catch(new BadRequestException(exception.message), host); + } + return super.catch(exception, host); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.module.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.module.ts new file mode 100644 index 000000000000..8052cb137aac --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-global-filter/example.module.ts @@ -0,0 +1,16 @@ +import { Module } from '@nestjs/common'; +import { APP_FILTER } from '@nestjs/core'; +import { ExampleController } from './example.controller'; +import { ExampleExceptionFilter } from './example.filter'; + +@Module({ + imports: [], + controllers: [ExampleController], + providers: [ + { + provide: APP_FILTER, + useClass: ExampleExceptionFilter, + }, + ], +}) +export class ExampleModuleGlobalFilter {} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.controller.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.controller.ts new file mode 100644 index 000000000000..11a0470ace17 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.controller.ts @@ -0,0 +1,19 @@ +import { Controller, Get, UseFilters } from '@nestjs/common'; +import { LocalExampleException } from './example.exception'; +import { LocalExampleExceptionFilter } from './example.filter'; + +@Controller('example-module-local-filter') +@UseFilters(LocalExampleExceptionFilter) +export class ExampleControllerLocalFilter { + constructor() {} + + @Get('/expected-exception') + getCaughtException() { + throw new LocalExampleException(); + } + + @Get('/unexpected-exception') + getUncaughtException(): string { + throw new Error(`This is an uncaught exception!`); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.exception.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.exception.ts new file mode 100644 index 000000000000..85a64d26d75e --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.exception.ts @@ -0,0 +1,5 @@ +export class LocalExampleException extends Error { + constructor() { + super('Something went wrong in the example module with local filter!'); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.filter.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.filter.ts new file mode 100644 index 000000000000..9b6797c95e44 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.filter.ts @@ -0,0 +1,13 @@ +import { ArgumentsHost, BadRequestException, Catch } from '@nestjs/common'; +import { BaseExceptionFilter } from '@nestjs/core'; +import { LocalExampleException } from './example.exception'; + +@Catch(LocalExampleException) +export class LocalExampleExceptionFilter extends BaseExceptionFilter { + catch(exception: unknown, host: ArgumentsHost) { + if (exception instanceof LocalExampleException) { + return super.catch(new BadRequestException(exception.message), host); + } + return super.catch(exception, host); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.module.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.module.ts new file mode 100644 index 000000000000..91d229a553c1 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-module-local-filter/example.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { ExampleControllerLocalFilter } from './example.controller'; + +@Module({ + imports: [], + controllers: [ExampleControllerLocalFilter], + providers: [], +}) +export class ExampleModuleLocalFilter {} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-specific.exception.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-specific.exception.ts new file mode 100644 index 000000000000..a26cb1a26d52 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-specific.exception.ts @@ -0,0 +1,5 @@ +export class ExampleExceptionSpecificFilter extends Error { + constructor() { + super('Original specific example exception!'); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-specific.filter.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-specific.filter.ts new file mode 100644 index 000000000000..bf85385a9a86 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/example-specific.filter.ts @@ -0,0 +1,19 @@ +import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter } from '@nestjs/common'; +import { Request, Response } from 'express'; +import { ExampleExceptionSpecificFilter } from './example-specific.exception'; + +@Catch(ExampleExceptionSpecificFilter) +export class ExampleSpecificFilter implements ExceptionFilter { + catch(exception: BadRequestException, host: ArgumentsHost): void { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + const request = ctx.getRequest(); + + response.status(400).json({ + statusCode: 400, + timestamp: new Date().toISOString(), + path: request.url, + message: 'Example exception was handled by specific filter!', + }); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/instrument.ts new file mode 100644 index 000000000000..4f16ebb36d11 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/instrument.ts @@ -0,0 +1,12 @@ +import * as Sentry from '@sentry/nestjs'; + +Sentry.init({ + environment: 'qa', // dynamic sampling bias to keep transactions + dsn: process.env.E2E_TEST_DSN, + tunnel: `http://localhost:3031/`, // proxy server + tracesSampleRate: 1, + transportOptions: { + // We expect the app to send a lot of events in a short time + bufferSize: 1000, + }, +}); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/main.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/main.ts new file mode 100644 index 000000000000..71ce685f4d61 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/main.ts @@ -0,0 +1,15 @@ +// Import this first +import './instrument'; + +// Import other modules +import { NestFactory } from '@nestjs/core'; +import { AppModule } from './app.module'; + +const PORT = 3030; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + await app.listen(PORT); +} + +bootstrap(); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/start-event-proxy.mjs b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/start-event-proxy.mjs new file mode 100644 index 000000000000..3c205b59a2d1 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/start-event-proxy.mjs @@ -0,0 +1,6 @@ +import { startEventProxyServer } from '@sentry-internal/test-utils'; + +startEventProxyServer({ + port: 3031, + proxyServerName: 'nestjs-with-submodules-decorator', +}); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/errors.test.ts new file mode 100644 index 000000000000..94c742dd210a --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/errors.test.ts @@ -0,0 +1,266 @@ +import { expect, test } from '@playwright/test'; +import { waitForError, waitForTransaction } from '@sentry-internal/test-utils'; + +test('Sends unexpected exception to Sentry if thrown in module with global filter', async ({ baseURL }) => { + const errorEventPromise = waitForError('nestjs-with-submodules-decorator', event => { + return !event.type && event.exception?.values?.[0]?.value === 'This is an uncaught exception!'; + }); + + const response = await fetch(`${baseURL}/example-module/unexpected-exception`); + const responseBody = await response.json(); + + expect(response.status).toBe(501); + expect(responseBody).toEqual({ + statusCode: 501, + timestamp: expect.any(String), + path: '/example-module/unexpected-exception', + message: 'Example exception was handled by global filter!', + }); + + const errorEvent = await errorEventPromise; + + expect(errorEvent.exception?.values).toHaveLength(1); + expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an uncaught exception!'); + + expect(errorEvent.request).toEqual({ + method: 'GET', + cookies: {}, + headers: expect.any(Object), + url: 'http://localhost:3030/example-module/unexpected-exception', + }); + + expect(errorEvent.transaction).toEqual('GET /example-module/unexpected-exception'); + + expect(errorEvent.contexts?.trace).toEqual({ + trace_id: expect.any(String), + span_id: expect.any(String), + }); +}); + +test('Sends unexpected exception to Sentry if thrown in module with local filter', async ({ baseURL }) => { + const errorEventPromise = waitForError('nestjs-with-submodules-decorator', event => { + return !event.type && event.exception?.values?.[0]?.value === 'This is an uncaught exception!'; + }); + + const response = await fetch(`${baseURL}/example-module-local-filter/unexpected-exception`); + const responseBody = await response.json(); + + expect(response.status).toBe(501); + expect(responseBody).toEqual({ + statusCode: 501, + timestamp: expect.any(String), + path: '/example-module-local-filter/unexpected-exception', + message: 'Example exception was handled by global filter!', + }); + + const errorEvent = await errorEventPromise; + + expect(errorEvent.exception?.values).toHaveLength(1); + expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an uncaught exception!'); + + expect(errorEvent.request).toEqual({ + method: 'GET', + cookies: {}, + headers: expect.any(Object), + url: 'http://localhost:3030/example-module-local-filter/unexpected-exception', + }); + + expect(errorEvent.transaction).toEqual('GET /example-module-local-filter/unexpected-exception'); + + expect(errorEvent.contexts?.trace).toEqual({ + trace_id: expect.any(String), + span_id: expect.any(String), + }); +}); + +test('Sends unexpected exception to Sentry if thrown in module that was registered before Sentry', async ({ + baseURL, +}) => { + const errorEventPromise = waitForError('nestjs-with-submodules-decorator', event => { + return !event.type && event.exception?.values?.[0]?.value === 'This is an uncaught exception!'; + }); + + const response = await fetch(`${baseURL}/example-module-registered-first/unexpected-exception`); + const responseBody = await response.json(); + + expect(response.status).toBe(501); + expect(responseBody).toEqual({ + statusCode: 501, + timestamp: expect.any(String), + path: '/example-module-registered-first/unexpected-exception', + message: 'Example exception was handled by global filter!', + }); + + const errorEvent = await errorEventPromise; + + expect(errorEvent.exception?.values).toHaveLength(1); + expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an uncaught exception!'); + + expect(errorEvent.request).toEqual({ + method: 'GET', + cookies: {}, + headers: expect.any(Object), + url: 'http://localhost:3030/example-module-registered-first/unexpected-exception', + }); + + expect(errorEvent.transaction).toEqual('GET /example-module-registered-first/unexpected-exception'); + + expect(errorEvent.contexts?.trace).toEqual({ + trace_id: expect.any(String), + span_id: expect.any(String), + }); +}); + +test('Does not send exception to Sentry if user-defined global exception filter already catches the exception', async ({ + baseURL, +}) => { + let errorEventOccurred = false; + + waitForError('nestjs-with-submodules-decorator', event => { + if (!event.type && event.exception?.values?.[0]?.value === 'Something went wrong in the example module!') { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /example-module/expected-exception'; + }); + + const transactionEventPromise = waitForTransaction('nestjs-with-submodules-decorator', transactionEvent => { + return transactionEvent?.transaction === 'GET /example-module/expected-exception'; + }); + + const response = await fetch(`${baseURL}/example-module/expected-exception`); + expect(response.status).toBe(400); + + await transactionEventPromise; + + (await fetch(`${baseURL}/flush`)).text(); + + expect(errorEventOccurred).toBe(false); +}); + +test('Does not send exception to Sentry if user-defined local exception filter already catches the exception', async ({ + baseURL, +}) => { + let errorEventOccurred = false; + + waitForError('nestjs-with-submodules-decorator', event => { + if ( + !event.type && + event.exception?.values?.[0]?.value === 'Something went wrong in the example module with local filter!' + ) { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /example-module-local-filter/expected-exception'; + }); + + const transactionEventPromise = waitForTransaction('nestjs-with-submodules-decorator', transactionEvent => { + return transactionEvent?.transaction === 'GET /example-module-local-filter/expected-exception'; + }); + + const response = await fetch(`${baseURL}/example-module-local-filter/expected-exception`); + expect(response.status).toBe(400); + + await transactionEventPromise; + + (await fetch(`${baseURL}/flush`)).text(); + + expect(errorEventOccurred).toBe(false); +}); + +test('Does not send expected exception to Sentry if exception is thrown in module registered before Sentry', async ({ + baseURL, +}) => { + let errorEventOccurred = false; + + waitForError('nestjs-with-submodules-decorator', event => { + if (!event.type && event.exception?.values?.[0].value === 'Something went wrong in the example module!') { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /example-module-registered-first/expected-exception'; + }); + + const transactionEventPromise = waitForTransaction('nestjs-with-submodules-decorator', transactionEvent => { + return transactionEvent?.transaction === 'GET /example-module-registered-first/expected-exception'; + }); + + const response = await fetch(`${baseURL}/example-module-registered-first/expected-exception`); + expect(response.status).toBe(400); + + await transactionEventPromise; + + (await fetch(`${baseURL}/flush`)).text(); + + expect(errorEventOccurred).toBe(false); +}); + +test('Global specific exception filter registered in main module is applied and exception is not sent to Sentry', async ({ + baseURL, +}) => { + let errorEventOccurred = false; + + waitForError('nestjs-with-submodules-decorator', event => { + if (!event.type && event.exception?.values?.[0]?.value === 'Example exception was handled by specific filter!') { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /example-exception-specific-filter'; + }); + + const transactionEventPromise = waitForTransaction('nestjs-with-submodules-decorator', transactionEvent => { + return transactionEvent?.transaction === 'GET /example-exception-specific-filter'; + }); + + const response = await fetch(`${baseURL}/example-exception-specific-filter`); + const responseBody = await response.json(); + + expect(response.status).toBe(400); + expect(responseBody).toEqual({ + statusCode: 400, + timestamp: expect.any(String), + path: '/example-exception-specific-filter', + message: 'Example exception was handled by specific filter!', + }); + + await transactionEventPromise; + + (await fetch(`${baseURL}/flush`)).text(); + + expect(errorEventOccurred).toBe(false); +}); + +test('Local specific exception filter registered in main module is applied and exception is not sent to Sentry', async ({ + baseURL, +}) => { + let errorEventOccurred = false; + + waitForError('nestjs-with-submodules-decorator', event => { + if (!event.type && event.exception?.values?.[0]?.value === 'Example exception was handled by local filter!') { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /example-exception-local-filter'; + }); + + const transactionEventPromise = waitForTransaction('nestjs-with-submodules-decorator', transactionEvent => { + return transactionEvent?.transaction === 'GET /example-exception-local-filter'; + }); + + const response = await fetch(`${baseURL}/example-exception-local-filter`); + const responseBody = await response.json(); + + expect(response.status).toBe(400); + expect(responseBody).toEqual({ + statusCode: 400, + timestamp: expect.any(String), + path: '/example-exception-local-filter', + message: 'Example exception was handled by local filter!', + }); + + await transactionEventPromise; + + (await fetch(`${baseURL}/flush`)).text(); + + expect(errorEventOccurred).toBe(false); +}); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts new file mode 100644 index 000000000000..740ab6f5650c --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts @@ -0,0 +1,240 @@ +import { expect, test } from '@playwright/test'; +import { waitForTransaction } from '@sentry-internal/test-utils'; + +test('Sends an API route transaction from module', async ({ baseURL }) => { + const pageloadTransactionEventPromise = waitForTransaction('nestjs-with-submodules-decorator', transactionEvent => { + return ( + transactionEvent?.contexts?.trace?.op === 'http.server' && + transactionEvent?.transaction === 'GET /example-module/transaction' + ); + }); + + await fetch(`${baseURL}/example-module/transaction`); + + const transactionEvent = await pageloadTransactionEventPromise; + + expect(transactionEvent.contexts?.trace).toEqual({ + data: { + 'sentry.source': 'route', + 'sentry.origin': 'auto.http.otel.http', + 'sentry.op': 'http.server', + 'sentry.sample_rate': 1, + url: 'http://localhost:3030/example-module/transaction', + 'otel.kind': 'SERVER', + 'http.response.status_code': 200, + 'http.url': 'http://localhost:3030/example-module/transaction', + 'http.host': 'localhost:3030', + 'net.host.name': 'localhost', + 'http.method': 'GET', + 'http.scheme': 'http', + 'http.target': '/example-module/transaction', + 'http.user_agent': 'node', + 'http.flavor': '1.1', + 'net.transport': 'ip_tcp', + 'net.host.ip': expect.any(String), + 'net.host.port': expect.any(Number), + 'net.peer.ip': expect.any(String), + 'net.peer.port': expect.any(Number), + 'http.status_code': 200, + 'http.status_text': 'OK', + 'http.route': '/example-module/transaction', + }, + op: 'http.server', + span_id: expect.any(String), + status: 'ok', + trace_id: expect.any(String), + origin: 'auto.http.otel.http', + }); + + expect(transactionEvent).toEqual( + expect.objectContaining({ + spans: expect.arrayContaining([ + { + data: { + 'express.name': '/example-module/transaction', + 'express.type': 'request_handler', + 'http.route': '/example-module/transaction', + 'sentry.origin': 'auto.http.otel.express', + 'sentry.op': 'request_handler.express', + }, + op: 'request_handler.express', + description: '/example-module/transaction', + parent_span_id: expect.any(String), + span_id: expect.any(String), + start_timestamp: expect.any(Number), + status: 'ok', + timestamp: expect.any(Number), + trace_id: expect.any(String), + origin: 'auto.http.otel.express', + }, + { + data: { + 'sentry.origin': 'manual', + }, + description: 'test-span', + parent_span_id: expect.any(String), + span_id: expect.any(String), + start_timestamp: expect.any(Number), + status: 'ok', + timestamp: expect.any(Number), + trace_id: expect.any(String), + origin: 'manual', + }, + { + data: { + 'sentry.origin': 'manual', + }, + description: 'child-span', + parent_span_id: expect.any(String), + span_id: expect.any(String), + start_timestamp: expect.any(Number), + status: 'ok', + timestamp: expect.any(Number), + trace_id: expect.any(String), + origin: 'manual', + }, + { + span_id: expect.any(String), + trace_id: expect.any(String), + data: { + 'sentry.origin': 'auto.http.otel.nestjs', + 'sentry.op': 'handler.nestjs', + component: '@nestjs/core', + 'nestjs.version': expect.any(String), + 'nestjs.type': 'handler', + 'nestjs.callback': 'testTransaction', + }, + description: 'testTransaction', + parent_span_id: expect.any(String), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + status: 'ok', + origin: 'auto.http.otel.nestjs', + op: 'handler.nestjs', + }, + ]), + transaction: 'GET /example-module/transaction', + type: 'transaction', + transaction_info: { + source: 'route', + }, + }), + ); +}); + +test('API route transaction includes exception filter span for global filter in module registered after Sentry', async ({ + baseURL, +}) => { + const transactionEventPromise = waitForTransaction('nestjs-with-submodules-decorator', transactionEvent => { + return ( + transactionEvent?.contexts?.trace?.op === 'http.server' && + transactionEvent?.transaction === 'GET /example-module/expected-exception' && + transactionEvent?.request?.url?.includes('/example-module/expected-exception') + ); + }); + + const response = await fetch(`${baseURL}/example-module/expected-exception`); + expect(response.status).toBe(400); + + const transactionEvent = await transactionEventPromise; + + expect(transactionEvent).toEqual( + expect.objectContaining({ + spans: expect.arrayContaining([ + { + span_id: expect.any(String), + trace_id: expect.any(String), + data: { + 'sentry.op': 'middleware.nestjs', + 'sentry.origin': 'auto.middleware.nestjs', + }, + description: 'ExampleExceptionFilter', + parent_span_id: expect.any(String), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + status: 'ok', + op: 'middleware.nestjs', + origin: 'auto.middleware.nestjs', + }, + ]), + }), + ); +}); + +test('API route transaction includes exception filter span for local filter in module registered after Sentry', async ({ + baseURL, +}) => { + const transactionEventPromise = waitForTransaction('nestjs-with-submodules-decorator', transactionEvent => { + return ( + transactionEvent?.contexts?.trace?.op === 'http.server' && + transactionEvent?.transaction === 'GET /example-module-local-filter/expected-exception' && + transactionEvent?.request?.url?.includes('/example-module-local-filter/expected-exception') + ); + }); + + const response = await fetch(`${baseURL}/example-module-local-filter/expected-exception`); + expect(response.status).toBe(400); + + const transactionEvent = await transactionEventPromise; + + expect(transactionEvent).toEqual( + expect.objectContaining({ + spans: expect.arrayContaining([ + { + span_id: expect.any(String), + trace_id: expect.any(String), + data: { + 'sentry.op': 'middleware.nestjs', + 'sentry.origin': 'auto.middleware.nestjs', + }, + description: 'LocalExampleExceptionFilter', + parent_span_id: expect.any(String), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + status: 'ok', + op: 'middleware.nestjs', + origin: 'auto.middleware.nestjs', + }, + ]), + }), + ); +}); + +test('API route transaction includes exception filter span for global filter in module registered before Sentry', async ({ + baseURL, +}) => { + const transactionEventPromise = waitForTransaction('nestjs-with-submodules-decorator', transactionEvent => { + return ( + transactionEvent?.contexts?.trace?.op === 'http.server' && + transactionEvent?.transaction === 'GET /example-module-registered-first/expected-exception' && + transactionEvent?.request?.url?.includes('/example-module-registered-first/expected-exception') + ); + }); + + const response = await fetch(`${baseURL}/example-module-registered-first/expected-exception`); + expect(response.status).toBe(400); + + const transactionEvent = await transactionEventPromise; + + expect(transactionEvent).toEqual( + expect.objectContaining({ + spans: expect.arrayContaining([ + { + span_id: expect.any(String), + trace_id: expect.any(String), + data: { + 'sentry.op': 'middleware.nestjs', + 'sentry.origin': 'auto.middleware.nestjs', + }, + description: 'ExampleExceptionFilterRegisteredFirst', + parent_span_id: expect.any(String), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + status: 'ok', + op: 'middleware.nestjs', + origin: 'auto.middleware.nestjs', + }, + ]), + }), + ); +}); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tsconfig.build.json b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tsconfig.build.json new file mode 100644 index 000000000000..26c30d4eddf2 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "test", "dist"] +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tsconfig.json b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tsconfig.json new file mode 100644 index 000000000000..95f5641cf7f3 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "target": "ES2021", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "incremental": true, + "skipLibCheck": true, + "strictNullChecks": false, + "noImplicitAny": false, + "strictBindCallApply": false, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.controller.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.controller.ts index 0d2c46e90da2..efce824a20c3 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.controller.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.controller.ts @@ -1,8 +1,12 @@ -import { Controller, Get, Param } from '@nestjs/common'; +import { Controller, Get, Param, UseFilters } from '@nestjs/common'; import { flush } from '@sentry/nestjs'; import { AppService } from './app.service'; +import { ExampleExceptionLocalFilter } from './example-local.exception'; +import { ExampleLocalFilter } from './example-local.filter'; +import { ExampleExceptionSpecificFilter } from './example-specific.exception'; @Controller() +@UseFilters(ExampleLocalFilter) export class AppController { constructor(private readonly appService: AppService) {} @@ -20,4 +24,14 @@ export class AppController { async flush() { await flush(); } + + @Get('example-exception-specific-filter') + async exampleExceptionGlobalFilter() { + throw new ExampleExceptionSpecificFilter(); + } + + @Get('example-exception-local-filter') + async exampleExceptionLocalFilter() { + throw new ExampleExceptionLocalFilter(); + } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.module.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.module.ts index 212b17a3556b..2a93747ac075 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.module.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.module.ts @@ -1,19 +1,31 @@ import { Module } from '@nestjs/common'; -import { SentryModule } from '@sentry/nestjs/setup'; +import { APP_FILTER } from '@nestjs/core'; +import { SentryGlobalFilter, SentryModule } from '@sentry/nestjs/setup'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { ExampleModuleGlobalFilterWrongRegistrationOrder } from './example-module-global-filter-wrong-registration-order/example.module'; +import { ExampleModuleGlobalFilterRegisteredFirst } from './example-module-global-filter-registered-first/example.module'; import { ExampleModuleGlobalFilter } from './example-module-global-filter/example.module'; import { ExampleModuleLocalFilter } from './example-module-local-filter/example.module'; +import { ExampleSpecificFilter } from './example-specific.filter'; @Module({ imports: [ - ExampleModuleGlobalFilterWrongRegistrationOrder, + ExampleModuleGlobalFilterRegisteredFirst, SentryModule.forRoot(), ExampleModuleGlobalFilter, ExampleModuleLocalFilter, ], controllers: [AppController], - providers: [AppService], + providers: [ + AppService, + { + provide: APP_FILTER, + useClass: SentryGlobalFilter, + }, + { + provide: APP_FILTER, + useClass: ExampleSpecificFilter, + }, + ], }) export class AppModule {} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-local.exception.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-local.exception.ts new file mode 100644 index 000000000000..8f76520a3b94 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-local.exception.ts @@ -0,0 +1,5 @@ +export class ExampleExceptionLocalFilter extends Error { + constructor() { + super('Original local example exception!'); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-local.filter.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-local.filter.ts new file mode 100644 index 000000000000..0e93e5f7fac2 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-local.filter.ts @@ -0,0 +1,19 @@ +import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter } from '@nestjs/common'; +import { Request, Response } from 'express'; +import { ExampleExceptionLocalFilter } from './example-local.exception'; + +@Catch(ExampleExceptionLocalFilter) +export class ExampleLocalFilter implements ExceptionFilter { + catch(exception: BadRequestException, host: ArgumentsHost): void { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + const request = ctx.getRequest(); + + response.status(400).json({ + statusCode: 400, + timestamp: new Date().toISOString(), + path: request.url, + message: 'Example exception was handled by local filter!', + }); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.controller.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.controller.ts new file mode 100644 index 000000000000..967886948a25 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.controller.ts @@ -0,0 +1,17 @@ +import { Controller, Get } from '@nestjs/common'; +import { ExampleExceptionRegisteredFirst } from './example.exception'; + +@Controller('example-module-registered-first') +export class ExampleController { + constructor() {} + + @Get('/expected-exception') + getCaughtException(): string { + throw new ExampleExceptionRegisteredFirst(); + } + + @Get('/unexpected-exception') + getUncaughtException(): string { + throw new Error(`This is an uncaught exception!`); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.exception.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.exception.ts new file mode 100644 index 000000000000..9bb3b5948343 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.exception.ts @@ -0,0 +1,5 @@ +export class ExampleExceptionRegisteredFirst extends Error { + constructor() { + super('Something went wrong in the example module!'); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.filter.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.filter.ts new file mode 100644 index 000000000000..6c3b81d395b5 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.filter.ts @@ -0,0 +1,13 @@ +import { ArgumentsHost, BadRequestException, Catch } from '@nestjs/common'; +import { BaseExceptionFilter } from '@nestjs/core'; +import { ExampleExceptionRegisteredFirst } from './example.exception'; + +@Catch(ExampleExceptionRegisteredFirst) +export class ExampleExceptionFilterRegisteredFirst extends BaseExceptionFilter { + catch(exception: unknown, host: ArgumentsHost) { + if (exception instanceof ExampleExceptionRegisteredFirst) { + return super.catch(new BadRequestException(exception.message), host); + } + return super.catch(exception, host); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.module.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.module.ts new file mode 100644 index 000000000000..8751856f99cd --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-global-filter-registered-first/example.module.ts @@ -0,0 +1,16 @@ +import { Module } from '@nestjs/common'; +import { APP_FILTER } from '@nestjs/core'; +import { ExampleController } from './example.controller'; +import { ExampleExceptionFilterRegisteredFirst } from './example.filter'; + +@Module({ + imports: [], + controllers: [ExampleController], + providers: [ + { + provide: APP_FILTER, + useClass: ExampleExceptionFilterRegisteredFirst, + }, + ], +}) +export class ExampleModuleGlobalFilterRegisteredFirst {} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-local-filter/example.controller.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-local-filter/example.controller.ts index 41d75d6eaf89..11a0470ace17 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-local-filter/example.controller.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-module-local-filter/example.controller.ts @@ -11,4 +11,9 @@ export class ExampleControllerLocalFilter { getCaughtException() { throw new LocalExampleException(); } + + @Get('/unexpected-exception') + getUncaughtException(): string { + throw new Error(`This is an uncaught exception!`); + } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-specific.exception.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-specific.exception.ts new file mode 100644 index 000000000000..a26cb1a26d52 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-specific.exception.ts @@ -0,0 +1,5 @@ +export class ExampleExceptionSpecificFilter extends Error { + constructor() { + super('Original specific example exception!'); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-specific.filter.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-specific.filter.ts new file mode 100644 index 000000000000..bf85385a9a86 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/example-specific.filter.ts @@ -0,0 +1,19 @@ +import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter } from '@nestjs/common'; +import { Request, Response } from 'express'; +import { ExampleExceptionSpecificFilter } from './example-specific.exception'; + +@Catch(ExampleExceptionSpecificFilter) +export class ExampleSpecificFilter implements ExceptionFilter { + catch(exception: BadRequestException, host: ArgumentsHost): void { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + const request = ctx.getRequest(); + + response.status(400).json({ + statusCode: 400, + timestamp: new Date().toISOString(), + path: request.url, + message: 'Example exception was handled by specific filter!', + }); + } +} diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/errors.test.ts index 6fbc9f2c1f32..03d4679fa3c0 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/errors.test.ts @@ -29,6 +29,34 @@ test('Sends unexpected exception to Sentry if thrown in module with global filte }); }); +test('Sends unexpected exception to Sentry if thrown in module with local filter', async ({ baseURL }) => { + const errorEventPromise = waitForError('nestjs-with-submodules', event => { + return !event.type && event.exception?.values?.[0]?.value === 'This is an uncaught exception!'; + }); + + const response = await fetch(`${baseURL}/example-module-local-filter/unexpected-exception`); + expect(response.status).toBe(500); + + const errorEvent = await errorEventPromise; + + expect(errorEvent.exception?.values).toHaveLength(1); + expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an uncaught exception!'); + + expect(errorEvent.request).toEqual({ + method: 'GET', + cookies: {}, + headers: expect.any(Object), + url: 'http://localhost:3030/example-module-local-filter/unexpected-exception', + }); + + expect(errorEvent.transaction).toEqual('GET /example-module-local-filter/unexpected-exception'); + + expect(errorEvent.contexts?.trace).toEqual({ + trace_id: expect.any(String), + span_id: expect.any(String), + }); +}); + test('Sends unexpected exception to Sentry if thrown in module that was registered before Sentry', async ({ baseURL, }) => { @@ -36,7 +64,7 @@ test('Sends unexpected exception to Sentry if thrown in module that was register return !event.type && event.exception?.values?.[0]?.value === 'This is an uncaught exception!'; }); - const response = await fetch(`${baseURL}/example-module-wrong-order/unexpected-exception`); + const response = await fetch(`${baseURL}/example-module-registered-first/unexpected-exception`); expect(response.status).toBe(500); const errorEvent = await errorEventPromise; @@ -48,10 +76,10 @@ test('Sends unexpected exception to Sentry if thrown in module that was register method: 'GET', cookies: {}, headers: expect.any(Object), - url: 'http://localhost:3030/example-module-wrong-order/unexpected-exception', + url: 'http://localhost:3030/example-module-registered-first/unexpected-exception', }); - expect(errorEvent.transaction).toEqual('GET /example-module-wrong-order/unexpected-exception'); + expect(errorEvent.transaction).toEqual('GET /example-module-registered-first/unexpected-exception'); expect(errorEvent.contexts?.trace).toEqual({ trace_id: expect.any(String), @@ -116,33 +144,99 @@ test('Does not send exception to Sentry if user-defined local exception filter a expect(errorEventOccurred).toBe(false); }); -test('Does not handle expected exception if exception is thrown in module registered before Sentry', async ({ +test('Does not send expected exception to Sentry if exception is thrown in module registered before Sentry', async ({ baseURL, }) => { - const errorEventPromise = waitForError('nestjs-with-submodules', event => { - return !event.type && event.exception?.values?.[0]?.value === 'Something went wrong in the example module!'; + let errorEventOccurred = false; + + waitForError('nestjs-with-submodules', event => { + if (!event.type && event.exception?.values?.[0].value === 'Something went wrong in the example module!') { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /example-module-registered-first/expected-exception'; }); - const response = await fetch(`${baseURL}/example-module-wrong-order/expected-exception`); - expect(response.status).toBe(500); // should be 400 + const transactionEventPromise = waitForTransaction('nestjs-with-submodules', transactionEvent => { + return transactionEvent?.transaction === 'GET /example-module-registered-first/expected-exception'; + }); - // should never arrive, but does because the exception is not handled properly - const errorEvent = await errorEventPromise; + const response = await fetch(`${baseURL}/example-module-registered-first/expected-exception`); + expect(response.status).toBe(400); - expect(errorEvent.exception?.values).toHaveLength(1); - expect(errorEvent.exception?.values?.[0]?.value).toBe('Something went wrong in the example module!'); + await transactionEventPromise; - expect(errorEvent.request).toEqual({ - method: 'GET', - cookies: {}, - headers: expect.any(Object), - url: 'http://localhost:3030/example-module-wrong-order/expected-exception', + (await fetch(`${baseURL}/flush`)).text(); + + expect(errorEventOccurred).toBe(false); +}); + +test('Global specific exception filter registered in main module is applied and exception is not sent to Sentry', async ({ + baseURL, +}) => { + let errorEventOccurred = false; + + waitForError('nestjs-with-submodules', event => { + if (!event.type && event.exception?.values?.[0]?.value === 'Example exception was handled by specific filter!') { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /example-exception-specific-filter'; }); - expect(errorEvent.transaction).toEqual('GET /example-module-wrong-order/expected-exception'); + const transactionEventPromise = waitForTransaction('nestjs-with-submodules', transactionEvent => { + return transactionEvent?.transaction === 'GET /example-exception-specific-filter'; + }); - expect(errorEvent.contexts?.trace).toEqual({ - trace_id: expect.any(String), - span_id: expect.any(String), + const response = await fetch(`${baseURL}/example-exception-specific-filter`); + const responseBody = await response.json(); + + expect(response.status).toBe(400); + expect(responseBody).toEqual({ + statusCode: 400, + timestamp: expect.any(String), + path: '/example-exception-specific-filter', + message: 'Example exception was handled by specific filter!', }); + + await transactionEventPromise; + + (await fetch(`${baseURL}/flush`)).text(); + + expect(errorEventOccurred).toBe(false); +}); + +test('Local specific exception filter registered in main module is applied and exception is not sent to Sentry', async ({ + baseURL, +}) => { + let errorEventOccurred = false; + + waitForError('nestjs-with-submodules', event => { + if (!event.type && event.exception?.values?.[0]?.value === 'Example exception was handled by local filter!') { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /example-exception-local-filter'; + }); + + const transactionEventPromise = waitForTransaction('nestjs-with-submodules', transactionEvent => { + return transactionEvent?.transaction === 'GET /example-exception-local-filter'; + }); + + const response = await fetch(`${baseURL}/example-exception-local-filter`); + const responseBody = await response.json(); + + expect(response.status).toBe(400); + expect(responseBody).toEqual({ + statusCode: 400, + timestamp: expect.any(String), + path: '/example-exception-local-filter', + message: 'Example exception was handled by local filter!', + }); + + await transactionEventPromise; + + (await fetch(`${baseURL}/flush`)).text(); + + expect(errorEventOccurred).toBe(false); }); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts index 9217249faad0..a2ea1db9c506 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts @@ -122,7 +122,9 @@ test('Sends an API route transaction from module', async ({ baseURL }) => { ); }); -test('API route transaction includes exception filter span for global filter', async ({ baseURL }) => { +test('API route transaction includes exception filter span for global filter in module registered after Sentry', async ({ + baseURL, +}) => { const transactionEventPromise = waitForTransaction('nestjs-with-submodules', transactionEvent => { return ( transactionEvent?.contexts?.trace?.op === 'http.server' && @@ -159,7 +161,9 @@ test('API route transaction includes exception filter span for global filter', a ); }); -test('API route transaction includes exception filter span for local filter', async ({ baseURL }) => { +test('API route transaction includes exception filter span for local filter in module registered after Sentry', async ({ + baseURL, +}) => { const transactionEventPromise = waitForTransaction('nestjs-with-submodules', transactionEvent => { return ( transactionEvent?.contexts?.trace?.op === 'http.server' && @@ -195,3 +199,42 @@ test('API route transaction includes exception filter span for local filter', as }), ); }); + +test('API route transaction includes exception filter span for global filter in module registered before Sentry', async ({ + baseURL, +}) => { + const transactionEventPromise = waitForTransaction('nestjs-with-submodules', transactionEvent => { + return ( + transactionEvent?.contexts?.trace?.op === 'http.server' && + transactionEvent?.transaction === 'GET /example-module-registered-first/expected-exception' && + transactionEvent?.request?.url?.includes('/example-module-registered-first/expected-exception') + ); + }); + + const response = await fetch(`${baseURL}/example-module-registered-first/expected-exception`); + expect(response.status).toBe(400); + + const transactionEvent = await transactionEventPromise; + + expect(transactionEvent).toEqual( + expect.objectContaining({ + spans: expect.arrayContaining([ + { + span_id: expect.any(String), + trace_id: expect.any(String), + data: { + 'sentry.op': 'middleware.nestjs', + 'sentry.origin': 'auto.middleware.nestjs', + }, + description: 'ExampleExceptionFilterRegisteredFirst', + parent_span_id: expect.any(String), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + status: 'ok', + op: 'middleware.nestjs', + origin: 'auto.middleware.nestjs', + }, + ]), + }), + ); +}); diff --git a/packages/nestjs/README.md b/packages/nestjs/README.md index 9e0192551afc..a78a2c45a620 100644 --- a/packages/nestjs/README.md +++ b/packages/nestjs/README.md @@ -55,26 +55,59 @@ async function bootstrap() { bootstrap(); ``` -Then you can add the `SentryModule` as a root module: +Afterwards, add the `SentryModule` as a root module to your main module: ```typescript import { Module } from '@nestjs/common'; import { SentryModule } from '@sentry/nestjs/setup'; -import { AppController } from './app.controller'; -import { AppService } from './app.service'; @Module({ imports: [ SentryModule.forRoot(), // ...other modules ], - controllers: [AppController], - providers: [AppService], }) export class AppModule {} ``` -The `SentryModule` needs to be registered before any module that should be instrumented by Sentry. +In case you are using a global catch-all exception filter (which is either a filter registered with +`app.useGlobalFilters()` or a filter registered in your app module providers annotated with an empty `@Catch()` +decorator), add a `@WithSentry()` decorator to the `catch()` method of this global error filter. This decorator will +report all unexpected errors that are received by your global error filter to Sentry: + +```typescript +import { Catch, ExceptionFilter } from '@nestjs/common'; +import { WithSentry } from '@sentry/nestjs'; + +@Catch() +export class YourCatchAllExceptionFilter implements ExceptionFilter { + @WithSentry() + catch(exception, host): void { + // your implementation here + } +} +``` + +In case you do not have a global catch-all exception filter, add the `SentryGlobalFilter` to the providers of your main +module. This filter will report all unhandled errors that are not caught by any other error filter to Sentry. +**Important:** The `SentryGlobalFilter` needs to be registered before any other exception filters. + +```typescript +import { Module } from '@nestjs/common'; +import { APP_FILTER } from '@nestjs/core'; +import { SentryGlobalFilter } from '@sentry/nestjs/setup'; + +@Module({ + providers: [ + { + provide: APP_FILTER, + useClass: SentryGlobalFilter, + }, + // ..other providers + ], +}) +export class AppModule {} +``` ## SentryTraced diff --git a/packages/nestjs/package.json b/packages/nestjs/package.json index f4ea1ff1c471..77234da5d263 100644 --- a/packages/nestjs/package.json +++ b/packages/nestjs/package.json @@ -51,13 +51,11 @@ }, "devDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", - "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0", - "@nestjs/microservices": "^8.0.0 || ^9.0.0 || ^10.0.0" + "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0" }, "peerDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", - "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0", - "@nestjs/microservices": "^8.0.0 || ^9.0.0 || ^10.0.0" + "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0" }, "scripts": { "build": "run-p build:transpile build:types", diff --git a/packages/nestjs/src/error-decorator.ts b/packages/nestjs/src/error-decorator.ts new file mode 100644 index 000000000000..bf1fd08d8cee --- /dev/null +++ b/packages/nestjs/src/error-decorator.ts @@ -0,0 +1,24 @@ +import { captureException } from '@sentry/core'; +import { isExpectedError } from './helpers'; + +/** + * A decorator to wrap user-defined exception filters and add Sentry error reporting. + */ +export function WithSentry() { + return function (target: unknown, propertyKey: string, descriptor: PropertyDescriptor) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const originalCatch = descriptor.value as (exception: unknown, host: unknown, ...args: any[]) => void; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + descriptor.value = function (exception: unknown, host: unknown, ...args: any[]) { + if (isExpectedError(exception)) { + return originalCatch.apply(this, args); + } + + captureException(exception); + return originalCatch.apply(this, args); + }; + + return descriptor; + }; +} diff --git a/packages/nestjs/src/helpers.ts b/packages/nestjs/src/helpers.ts new file mode 100644 index 000000000000..34450aa3ac75 --- /dev/null +++ b/packages/nestjs/src/helpers.ts @@ -0,0 +1,13 @@ +/** + * Determines if the exception is an expected control flow error. + * - HttpException errors will have a status property + * - RpcException errors will have an error property + * + * @returns `true` if the exception is expected and should not be reported to Sentry, otherwise `false`. + */ +export function isExpectedError(exception: unknown): boolean { + if (typeof exception === 'object' && exception !== null) { + return 'status' in exception || 'error' in exception; + } + return false; +} diff --git a/packages/nestjs/src/index.ts b/packages/nestjs/src/index.ts index 00519cf49b9e..b30fe547103b 100644 --- a/packages/nestjs/src/index.ts +++ b/packages/nestjs/src/index.ts @@ -4,3 +4,4 @@ export { init } from './sdk'; export { SentryTraced } from './span-decorator'; export { SentryCron } from './cron-decorator'; +export { WithSentry } from './error-decorator'; diff --git a/packages/nestjs/src/setup.ts b/packages/nestjs/src/setup.ts index 5e76f5cbe912..f284c4ed7875 100644 --- a/packages/nestjs/src/setup.ts +++ b/packages/nestjs/src/setup.ts @@ -6,12 +6,8 @@ import type { NestInterceptor, OnModuleInit, } from '@nestjs/common'; -import { HttpException } from '@nestjs/common'; -import { Catch } from '@nestjs/common'; -import { Injectable } from '@nestjs/common'; -import { Global, Module } from '@nestjs/common'; -import { APP_FILTER, APP_INTERCEPTOR, BaseExceptionFilter } from '@nestjs/core'; -import { RpcException } from '@nestjs/microservices'; +import { Catch, Global, Injectable, Module } from '@nestjs/common'; +import { APP_INTERCEPTOR, BaseExceptionFilter } from '@nestjs/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, @@ -24,6 +20,7 @@ import { import type { Span } from '@sentry/types'; import { logger } from '@sentry/utils'; import type { Observable } from 'rxjs'; +import { isExpectedError } from './helpers'; /** * Note: We cannot use @ syntax to add the decorators, so we add them directly below the classes as function wrappers. @@ -70,8 +67,7 @@ class SentryGlobalFilter extends BaseExceptionFilter { * Catches exceptions and reports them to Sentry unless they are expected errors. */ public catch(exception: unknown, host: ArgumentsHost): void { - // don't report expected errors - if (exception instanceof HttpException || exception instanceof RpcException) { + if (isExpectedError(exception)) { return super.catch(exception, host); } @@ -118,10 +114,6 @@ class SentryModule { module: SentryModule, providers: [ SentryService, - { - provide: APP_FILTER, - useClass: SentryGlobalFilter, - }, { provide: APP_INTERCEPTOR, useClass: SentryTracingInterceptor, @@ -135,10 +127,6 @@ Global()(SentryModule); Module({ providers: [ SentryService, - { - provide: APP_FILTER, - useClass: SentryGlobalFilter, - }, { provide: APP_INTERCEPTOR, useClass: SentryTracingInterceptor, diff --git a/packages/node/src/integrations/tracing/nest/sentry-nest-instrumentation.ts b/packages/node/src/integrations/tracing/nest/sentry-nest-instrumentation.ts index 28d5a74ef63d..a8d02e5cbe69 100644 --- a/packages/node/src/integrations/tracing/nest/sentry-nest-instrumentation.ts +++ b/packages/node/src/integrations/tracing/nest/sentry-nest-instrumentation.ts @@ -16,7 +16,9 @@ const supportedVersions = ['>=8.0.0 <11']; /** * Custom instrumentation for nestjs. * - * This hooks into the @Injectable decorator, which is applied on class middleware, interceptors and guards. + * This hooks into + * 1. @Injectable decorator, which is applied on class middleware, interceptors and guards. + * 2. @Catch decorator, which is applied on exception filters. */ export class SentryNestInstrumentation extends InstrumentationBase { public static readonly COMPONENT = '@nestjs/common'; diff --git a/yarn.lock b/yarn.lock index 5603f142ea95..cc4c66703b49 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6135,14 +6135,6 @@ path-to-regexp "3.2.0" tslib "2.6.3" -"@nestjs/microservices@^8.0.0 || ^9.0.0 || ^10.0.0": - version "10.3.10" - resolved "https://registry.yarnpkg.com/@nestjs/microservices/-/microservices-10.3.10.tgz#e00957e0c22b0cc8b041242a40538e2d862255fb" - integrity sha512-zZrilhZmXU2Ik5Usrcy4qEX262Uhvz0/9XlIdX6SRn8I39ns1EE9tAhEBmmkMwh7lsEikRFa4aaa05loi8Gsow== - dependencies: - iterare "1.2.1" - tslib "2.6.3" - "@nestjs/platform-express@^10.3.3": version "10.3.3" resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.3.3.tgz#c1484d30d1e7666c4c8d0d7cde31cfc0b9d166d7" From c0239b1bbca45284f706f6a8555951f4bff46cdb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2024 01:37:17 +0000 Subject: [PATCH 04/25] feat(deps): bump @prisma/instrumentation from 5.17.0 to 5.18.0 (#13327) --- packages/node/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/node/package.json b/packages/node/package.json index 7b570302e0f2..ccae165be8bb 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -89,7 +89,7 @@ "@opentelemetry/sdk-trace-base": "^1.25.1", "@opentelemetry/semantic-conventions": "^1.25.1", "@opentelemetry/instrumentation-generic-pool": "^0.38.0", - "@prisma/instrumentation": "5.17.0", + "@prisma/instrumentation": "5.18.0", "@sentry/core": "8.25.0", "@sentry/opentelemetry": "8.25.0", "@sentry/types": "8.25.0", diff --git a/yarn.lock b/yarn.lock index cc4c66703b49..481175f8db61 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7525,10 +7525,10 @@ resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.9.1.tgz#d92bd2f7f006e0316cb4fda9d73f235965cf2c64" integrity sha512-caSOnG4kxcSkhqC/2ShV7rEoWwd3XrftokxJqOCMVvia4NYV/TPtJlS9C2os3Igxw/Qyxumj9GBQzcStzECvtQ== -"@prisma/instrumentation@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@prisma/instrumentation/-/instrumentation-5.17.0.tgz#f741ff517f54b1a896fb8605e0d702f29855c6cb" - integrity sha512-c1Sle4ji8aasMcYfBBHFM56We4ljfenVtRmS8aY06BllS7SoU6SmJBwG7vil+GHiR0Yrh+t9iBwt4AY0Jr4KNQ== +"@prisma/instrumentation@5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@prisma/instrumentation/-/instrumentation-5.18.0.tgz#8b49e25bf3f8f756eb0c4c199b4cf8b6631db891" + integrity sha512-r074avGkpPXItk+josQPhufZEmGhUCb16PQx4ITPS40vWTpTPET4VsgCBZB2alIN6SS7pRFod2vz2M2HHEEylQ== dependencies: "@opentelemetry/api" "^1.8" "@opentelemetry/instrumentation" "^0.49 || ^0.50 || ^0.51 || ^0.52.0" From 22878c78b0f57783c2037da3164a2749403e363a Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 14 Aug 2024 09:57:18 +0200 Subject: [PATCH 05/25] ci: Streamline some caching (#13355) This streamlines some caching stuff for CI: 1. Extract dependency installation & cache out into a composite action for reusability 2. Updated the cache key for dependencies to only include package & dev-package `package.json`, not the E2E test ones. --- .../actions/install-dependencies/action.yml | 29 ++++++++++++++ .github/workflows/build.yml | 40 ++++--------------- 2 files changed, 36 insertions(+), 33 deletions(-) create mode 100644 .github/actions/install-dependencies/action.yml diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml new file mode 100644 index 000000000000..8cb80ac7440e --- /dev/null +++ b/.github/actions/install-dependencies/action.yml @@ -0,0 +1,29 @@ +name: "Install yarn dependencies" +description: "Installs yarn dependencies and caches them." + +outputs: + cache_key: + description: "The dependency cache key" + value: ${{ steps.compute_lockfile_hash.outputs.hash }} + +runs: + using: "composite" + steps: + # we use a hash of yarn.lock as our cache key, because if it hasn't changed, our dependencies haven't changed, + # so no need to reinstall them + - name: Compute dependency cache key + id: compute_lockfile_hash + run: echo "hash=dependencies-${{ hashFiles('yarn.lock', 'packages/*/package.json', 'dev-packages/*/package.json') }}" >> "$GITHUB_OUTPUT" + shell: bash + + - name: Check dependency cache + uses: actions/cache@v4 + id: cache_dependencies + with: + path: ${{ env.CACHED_DEPENDENCY_PATHS }} + key: ${{ steps.compute_lockfile_hash.outputs.hash }} + + - name: Install dependencies + if: steps.cache_dependencies.outputs.cache-hit != 'true' + run: yarn install --ignore-engines --frozen-lockfile + shell: bash diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a956f585b414..d8ccc2c75dec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -146,22 +146,9 @@ jobs: with: node-version-file: 'package.json' - # we use a hash of yarn.lock as our cache key, because if it hasn't changed, our dependencies haven't changed, - # so no need to reinstall them - - name: Compute dependency cache key - id: compute_lockfile_hash - run: echo "hash=${{ hashFiles('yarn.lock', '**/package.json') }}" >> "$GITHUB_OUTPUT" - - - name: Check dependency cache - uses: actions/cache@v4 - id: cache_dependencies - with: - path: ${{ env.CACHED_DEPENDENCY_PATHS }} - key: ${{ steps.compute_lockfile_hash.outputs.hash }} - - - name: Install dependencies - if: steps.cache_dependencies.outputs.cache-hit != 'true' - run: yarn install --ignore-engines --frozen-lockfile + - name: Install Dependencies + uses: ./.github/actions/install-dependencies + id: install_dependencies - name: Check for Affected Nx Projects uses: dkhunt27/action-nx-affected-list@v5.3 @@ -200,7 +187,7 @@ jobs: run: yarn build outputs: - dependency_cache_key: ${{ steps.compute_lockfile_hash.outputs.hash }} + dependency_cache_key: ${{ steps.install_dependencies.outputs.cache_key }} changed_node_integration: ${{ needs.job_get_metadata.outputs.changed_ci == 'true' || contains(steps.checkForAffected.outputs.affected, '@sentry-internal/node-integration-tests') }} changed_remix: ${{ needs.job_get_metadata.outputs.changed_ci == 'true' || contains(steps.checkForAffected.outputs.affected, '@sentry/remix') }} changed_node: ${{ needs.job_get_metadata.outputs.changed_ci == 'true' || contains(steps.checkForAffected.outputs.affected, '@sentry/node') }} @@ -293,22 +280,9 @@ jobs: with: node-version-file: 'package.json' - # we use a hash of yarn.lock as our cache key, because if it hasn't changed, our dependencies haven't changed, - # so no need to reinstall them - - name: Compute dependency cache key - id: compute_lockfile_hash - run: echo "hash=${{ hashFiles('yarn.lock', '**/package.json') }}" >> "$GITHUB_OUTPUT" - - - name: Check dependency cache - uses: actions/cache@v4 - id: cache_dependencies - with: - path: ${{ env.CACHED_DEPENDENCY_PATHS }} - key: ${{ steps.compute_lockfile_hash.outputs.hash }} - - - name: Install dependencies - if: steps.cache_dependencies.outputs.cache-hit != 'true' - run: yarn install --ignore-engines --frozen-lockfile + - name: Install Dependencies + uses: ./.github/actions/install-dependencies + id: install_dependencies - name: Check file formatting run: yarn lint:prettier && yarn lint:biome From 6d5c5c67ead7b326bd5cbe07afd4885523e35a6a Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 13 Aug 2024 14:47:34 +0200 Subject: [PATCH 06/25] meta: Update Changelog for 8.26.0 --- CHANGELOG.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 931d1462da47..be7298ed213a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,58 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +## 8.26.0 + +### Important Changes + +- **feat(node): Add `fsInstrumentation` (#13291)** + + This release adds `fsIntegration`, an integration that instruments the `fs` API to the Sentry Node SDK. The + integration creates spans with naming patterns of `fs.readFile`, `fs.unlink`, and so on. + + This integration is not enabled by default and needs to be registered in your `Sentry.init` call. You can configure + via options whether to include path arguments or error messages as span attributes when an fs call fails: + + ```js + Sentry.init({ + integrations: [ + Sentry.fsIntegration({ + recordFilePaths: true, + recordErrorMessagesAsSpanAttributes: true, + }), + ], + }); + ``` + + **WARNING:** This integration may add significant overhead to your application. Especially in scenarios with a lot of + file I/O, like for example when running a framework dev server, including this integration can massively slow down + your application. + +### Other Changes + +- feat(browser): Add spotlightBrowser integration (#13263) +- feat(browser): Allow sentry in safari extension background page (#13209) +- feat(browser): Send CLS as standalone span (experimental) (#13056) +- feat(core): Add OpenTelemetry-specific `getTraceData` implementation (#13281) +- feat(nextjs): Always add `browserTracingIntegration` (#13324) +- feat(nextjs): Always transmit trace data to the client (#13337) +- feat(nextjs): export SentryBuildOptions (#13296) +- feat(nextjs): Update `experimental_captureRequestError` to reflect `RequestInfo.path` change in Next.js canary + (#13344) + +- feat(nuxt): Always add tracing meta tags (#13273) +- feat(nuxt): Set transaction name for server error (#13292) +- feat(replay): Add a replay-specific logger (#13256) +- feat(sveltekit): Add bundle size optimizations to plugin options (#13318) +- feat(sveltekit): Always add browserTracingIntegration (#13322) +- feat(tracing): Make long animation frames opt-out (#13255) +- fix(astro): Correctly extract request data (#13315) +- fix(astro): Only track access request headers in dynamic page requests (#13306) +- fix(nuxt): Add import line for disabled `autoImport` (#13342) +- fix(nuxt): Add vue to excludeEsmLoaderHooks array (#13346) +- fix(opentelemetry): Do not overwrite http span name if kind is internal (#13282) +- fix(remix): Ensure `origin` is correctly set for remix server spans (#13305) + Work in this release was contributed by @MonstraG, @undead-voron and @Zen-cronic. Thank you for your contributions! ## 8.25.0 From c1a775bcbbdc408f5882daa2fa3b1853e2abf230 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 13 Aug 2024 14:36:54 +0000 Subject: [PATCH 07/25] release: 8.26.0 --- .../browser-integration-tests/package.json | 4 ++-- .../bundle-analyzer-scenarios/package.json | 2 +- dev-packages/e2e-tests/package.json | 2 +- .../package.json | 2 +- .../node-integration-tests/package.json | 10 +++++----- dev-packages/overhead-metrics/package.json | 2 +- dev-packages/rollup-utils/package.json | 2 +- dev-packages/size-limit-gh-action/package.json | 2 +- dev-packages/test-utils/package.json | 6 +++--- lerna.json | 2 +- packages/angular/package.json | 10 +++++----- packages/astro/package.json | 12 ++++++------ packages/aws-serverless/package.json | 10 +++++----- packages/browser-utils/package.json | 8 ++++---- packages/browser/package.json | 18 +++++++++--------- packages/bun/package.json | 12 ++++++------ packages/cloudflare/package.json | 8 ++++---- packages/core/package.json | 6 +++--- packages/deno/package.json | 8 ++++---- packages/ember/package.json | 10 +++++----- packages/eslint-config-sdk/package.json | 6 +++--- packages/eslint-plugin-sdk/package.json | 2 +- packages/feedback/package.json | 8 ++++---- packages/gatsby/package.json | 10 +++++----- packages/google-cloud-serverless/package.json | 10 +++++----- packages/integration-shims/package.json | 8 ++++---- packages/nestjs/package.json | 10 +++++----- packages/nextjs/package.json | 16 ++++++++-------- packages/node/package.json | 10 +++++----- packages/nuxt/package.json | 16 ++++++++-------- packages/opentelemetry/package.json | 8 ++++---- packages/profiling-node/package.json | 10 +++++----- packages/react/package.json | 10 +++++----- packages/remix/package.json | 14 +++++++------- packages/replay-canvas/package.json | 10 +++++----- packages/replay-internal/package.json | 12 ++++++------ packages/replay-worker/package.json | 2 +- packages/solid/package.json | 10 +++++----- packages/solidstart/package.json | 14 +++++++------- packages/svelte/package.json | 10 +++++----- packages/sveltekit/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/typescript/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/utils/src/version.ts | 2 +- packages/vercel-edge/package.json | 8 ++++---- packages/vue/package.json | 10 +++++----- packages/wasm/package.json | 10 +++++----- 48 files changed, 192 insertions(+), 192 deletions(-) diff --git a/dev-packages/browser-integration-tests/package.json b/dev-packages/browser-integration-tests/package.json index 84b90b6045a9..2e2e6cab12ab 100644 --- a/dev-packages/browser-integration-tests/package.json +++ b/dev-packages/browser-integration-tests/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/browser-integration-tests", - "version": "8.25.0", + "version": "8.26.0", "main": "index.js", "license": "MIT", "engines": { @@ -43,7 +43,7 @@ "@babel/preset-typescript": "^7.16.7", "@playwright/test": "^1.44.1", "@sentry-internal/rrweb": "2.11.0", - "@sentry/browser": "8.25.0", + "@sentry/browser": "8.26.0", "axios": "1.6.7", "babel-loader": "^8.2.2", "html-webpack-plugin": "^5.5.0", diff --git a/dev-packages/bundle-analyzer-scenarios/package.json b/dev-packages/bundle-analyzer-scenarios/package.json index bcf269754bf9..a9f2c9265e72 100644 --- a/dev-packages/bundle-analyzer-scenarios/package.json +++ b/dev-packages/bundle-analyzer-scenarios/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/bundle-analyzer-scenarios", - "version": "8.25.0", + "version": "8.26.0", "description": "Scenarios to test bundle analysis with", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/dev-packages/bundle-analyzer-scenarios", diff --git a/dev-packages/e2e-tests/package.json b/dev-packages/e2e-tests/package.json index 2f4bd429ca17..69211cd141a8 100644 --- a/dev-packages/e2e-tests/package.json +++ b/dev-packages/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/e2e-tests", - "version": "8.25.0", + "version": "8.26.0", "license": "MIT", "private": true, "scripts": { diff --git a/dev-packages/external-contributor-gh-action/package.json b/dev-packages/external-contributor-gh-action/package.json index c5502135c384..3d81148be51a 100644 --- a/dev-packages/external-contributor-gh-action/package.json +++ b/dev-packages/external-contributor-gh-action/package.json @@ -1,7 +1,7 @@ { "name": "@sentry-internal/external-contributor-gh-action", "description": "An internal Github Action to add external contributors to the CHANGELOG.md file.", - "version": "8.25.0", + "version": "8.26.0", "license": "MIT", "engines": { "node": ">=18" diff --git a/dev-packages/node-integration-tests/package.json b/dev-packages/node-integration-tests/package.json index c9ddd75d6402..e381dc99e5d6 100644 --- a/dev-packages/node-integration-tests/package.json +++ b/dev-packages/node-integration-tests/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/node-integration-tests", - "version": "8.25.0", + "version": "8.26.0", "license": "MIT", "engines": { "node": ">=14.18" @@ -31,10 +31,10 @@ "@nestjs/core": "^10.3.3", "@nestjs/platform-express": "^10.3.3", "@prisma/client": "5.9.1", - "@sentry/aws-serverless": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/aws-serverless": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "@types/mongodb": "^3.6.20", "@types/mysql": "^2.15.21", "@types/pg": "^8.6.5", diff --git a/dev-packages/overhead-metrics/package.json b/dev-packages/overhead-metrics/package.json index 724ffad496a8..4b4825b185df 100644 --- a/dev-packages/overhead-metrics/package.json +++ b/dev-packages/overhead-metrics/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "8.25.0", + "version": "8.26.0", "name": "@sentry-internal/overhead-metrics", "main": "index.js", "author": "Sentry", diff --git a/dev-packages/rollup-utils/package.json b/dev-packages/rollup-utils/package.json index 5b591020aaeb..6ac6f0a1a729 100644 --- a/dev-packages/rollup-utils/package.json +++ b/dev-packages/rollup-utils/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/rollup-utils", - "version": "8.25.0", + "version": "8.26.0", "description": "Rollup utilities used at Sentry for the Sentry JavaScript SDK", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/rollup-utils", diff --git a/dev-packages/size-limit-gh-action/package.json b/dev-packages/size-limit-gh-action/package.json index 7179980f6f32..7d76088b54b6 100644 --- a/dev-packages/size-limit-gh-action/package.json +++ b/dev-packages/size-limit-gh-action/package.json @@ -1,7 +1,7 @@ { "name": "@sentry-internal/size-limit-gh-action", "description": "An internal Github Action to compare the current size of a PR against the one on develop.", - "version": "8.25.0", + "version": "8.26.0", "license": "MIT", "engines": { "node": ">=18" diff --git a/dev-packages/test-utils/package.json b/dev-packages/test-utils/package.json index 7fd73360538c..a0b1688f4142 100644 --- a/dev-packages/test-utils/package.json +++ b/dev-packages/test-utils/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "8.25.0", + "version": "8.26.0", "name": "@sentry-internal/test-utils", "author": "Sentry", "license": "MIT", @@ -45,8 +45,8 @@ }, "devDependencies": { "@playwright/test": "^1.44.1", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "volta": { "extends": "../../package.json" diff --git a/lerna.json b/lerna.json index ed95619c70a2..e3c3f83f3096 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "8.25.0", + "version": "8.26.0", "npmClient": "yarn" } diff --git a/packages/angular/package.json b/packages/angular/package.json index 5f22dc37ac12..a6c6bb06ef94 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/angular", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Angular", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/angular", @@ -21,10 +21,10 @@ "rxjs": "^6.5.5 || ^7.x" }, "dependencies": { - "@sentry/browser": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/browser": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "tslib": "^2.4.1" }, "devDependencies": { diff --git a/packages/astro/package.json b/packages/astro/package.json index d857fd048877..b5fd94e25d3a 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/astro", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Astro", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/astro", @@ -56,11 +56,11 @@ "astro": ">=3.x || >=4.0.0-beta" }, "dependencies": { - "@sentry/browser": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/browser": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "@sentry/vite-plugin": "^2.20.1" }, "devDependencies": { diff --git a/packages/aws-serverless/package.json b/packages/aws-serverless/package.json index be6fe9f16c4d..881976a8db34 100644 --- a/packages/aws-serverless/package.json +++ b/packages/aws-serverless/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/aws-serverless", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for AWS Lambda and AWS Serverless Environments", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/serverless", @@ -66,10 +66,10 @@ "dependencies": { "@opentelemetry/instrumentation-aws-lambda": "0.43.0", "@opentelemetry/instrumentation-aws-sdk": "0.43.1", - "@sentry/core": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/core": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "@types/aws-lambda": "^8.10.62" }, "devDependencies": { diff --git a/packages/browser-utils/package.json b/packages/browser-utils/package.json index 8fc2497527a2..235032606e5d 100644 --- a/packages/browser-utils/package.json +++ b/packages/browser-utils/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/browser-utils", - "version": "8.25.0", + "version": "8.26.0", "description": "Browser Utilities for all Sentry JavaScript SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/browser-utils", @@ -39,9 +39,9 @@ "access": "public" }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "scripts": { "build": "run-p build:transpile build:types", diff --git a/packages/browser/package.json b/packages/browser/package.json index 2131cefd692c..07322e621598 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/browser", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for browsers", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/browser", @@ -39,16 +39,16 @@ "access": "public" }, "dependencies": { - "@sentry-internal/browser-utils": "8.25.0", - "@sentry-internal/feedback": "8.25.0", - "@sentry-internal/replay": "8.25.0", - "@sentry-internal/replay-canvas": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry-internal/browser-utils": "8.26.0", + "@sentry-internal/feedback": "8.26.0", + "@sentry-internal/replay": "8.26.0", + "@sentry-internal/replay-canvas": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "devDependencies": { - "@sentry-internal/integration-shims": "8.25.0", + "@sentry-internal/integration-shims": "8.26.0", "fake-indexeddb": "^4.0.1" }, "scripts": { diff --git a/packages/bun/package.json b/packages/bun/package.json index 71fcf3c36310..fe0c181bf70a 100644 --- a/packages/bun/package.json +++ b/packages/bun/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/bun", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for bun", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/bun", @@ -39,11 +39,11 @@ "access": "public" }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/opentelemetry": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/core": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/opentelemetry": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "devDependencies": { "bun-types": "latest" diff --git a/packages/cloudflare/package.json b/packages/cloudflare/package.json index 43803985c7bb..fd9d9bcffe36 100644 --- a/packages/cloudflare/package.json +++ b/packages/cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/cloudflare", - "version": "8.25.0", + "version": "8.26.0", "description": "Offical Sentry SDK for Cloudflare Workers and Pages", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/cloudflare", @@ -39,9 +39,9 @@ "access": "public" }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "optionalDependencies": { "@cloudflare/workers-types": "^4.x" diff --git a/packages/core/package.json b/packages/core/package.json index e37131d2c479..8f140bfbb09c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/core", - "version": "8.25.0", + "version": "8.26.0", "description": "Base implementation for all Sentry JavaScript SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/core", @@ -39,8 +39,8 @@ "access": "public" }, "dependencies": { - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "scripts": { "build": "run-p build:transpile build:types", diff --git a/packages/deno/package.json b/packages/deno/package.json index 2c70255bff45..4178c41cff65 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/deno", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Deno", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/deno", @@ -24,9 +24,9 @@ "/build" ], "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "devDependencies": { "@rollup/plugin-typescript": "^11.1.5", diff --git a/packages/ember/package.json b/packages/ember/package.json index 2682d65f9244..046d187d8da3 100644 --- a/packages/ember/package.json +++ b/packages/ember/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/ember", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Ember.js", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/ember", @@ -33,10 +33,10 @@ "dependencies": { "@babel/core": "^7.24.4", "@embroider/macros": "^1.16.0", - "@sentry/browser": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/browser": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "ember-auto-import": "^2.7.2", "ember-cli-babel": "^8.2.0", "ember-cli-htmlbars": "^6.1.1", diff --git a/packages/eslint-config-sdk/package.json b/packages/eslint-config-sdk/package.json index e2630e1038c3..f7d26ab13625 100644 --- a/packages/eslint-config-sdk/package.json +++ b/packages/eslint-config-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/eslint-config-sdk", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK eslint config", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/eslint-config-sdk", @@ -22,8 +22,8 @@ "access": "public" }, "dependencies": { - "@sentry-internal/eslint-plugin-sdk": "8.25.0", - "@sentry-internal/typescript": "8.25.0", + "@sentry-internal/eslint-plugin-sdk": "8.26.0", + "@sentry-internal/typescript": "8.26.0", "@typescript-eslint/eslint-plugin": "^5.48.0", "@typescript-eslint/parser": "^5.48.0", "eslint-config-prettier": "^6.11.0", diff --git a/packages/eslint-plugin-sdk/package.json b/packages/eslint-plugin-sdk/package.json index b0f74252abf8..6f01f96eee3e 100644 --- a/packages/eslint-plugin-sdk/package.json +++ b/packages/eslint-plugin-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/eslint-plugin-sdk", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK eslint plugin", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/eslint-plugin-sdk", diff --git a/packages/feedback/package.json b/packages/feedback/package.json index def2f283dc81..ff4c10fcad8a 100644 --- a/packages/feedback/package.json +++ b/packages/feedback/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/feedback", - "version": "8.25.0", + "version": "8.26.0", "description": "Sentry SDK integration for user feedback", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/feedback", @@ -39,9 +39,9 @@ "access": "public" }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "devDependencies": { "preact": "^10.19.4" diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index e0aa4ed9bd1a..4bfd08a2dc80 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/gatsby", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Gatsby.js", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/gatsby", @@ -45,10 +45,10 @@ "access": "public" }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/react": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/core": "8.26.0", + "@sentry/react": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "@sentry/webpack-plugin": "2.16.0" }, "peerDependencies": { diff --git a/packages/google-cloud-serverless/package.json b/packages/google-cloud-serverless/package.json index 078b493b3dd1..d8bcc758752b 100644 --- a/packages/google-cloud-serverless/package.json +++ b/packages/google-cloud-serverless/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/google-cloud-serverless", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Google Cloud Functions", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/google-cloud", @@ -48,10 +48,10 @@ "access": "public" }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/core": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "@types/express": "^4.17.14" }, "devDependencies": { diff --git a/packages/integration-shims/package.json b/packages/integration-shims/package.json index e1e1cda60053..88eee4b1175a 100644 --- a/packages/integration-shims/package.json +++ b/packages/integration-shims/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/integration-shims", - "version": "8.25.0", + "version": "8.26.0", "description": "Shims for integrations in Sentry SDK.", "main": "build/cjs/index.js", "module": "build/esm/index.js", @@ -55,9 +55,9 @@ "url": "https://github.com/getsentry/sentry-javascript/issues" }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "engines": { "node": ">=14.18" diff --git a/packages/nestjs/package.json b/packages/nestjs/package.json index 77234da5d263..902b89d11591 100644 --- a/packages/nestjs/package.json +++ b/packages/nestjs/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/nestjs", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for NestJS", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/nestjs", @@ -44,10 +44,10 @@ "access": "public" }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/core": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "devDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index e6ccca4162a4..466a98f8512f 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/nextjs", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Next.js", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/nextjs", @@ -71,13 +71,13 @@ "@opentelemetry/instrumentation-http": "0.52.1", "@opentelemetry/semantic-conventions": "^1.25.1", "@rollup/plugin-commonjs": "26.0.1", - "@sentry/core": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/opentelemetry": "8.25.0", - "@sentry/react": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", - "@sentry/vercel-edge": "8.25.0", + "@sentry/core": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/opentelemetry": "8.26.0", + "@sentry/react": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", + "@sentry/vercel-edge": "8.26.0", "@sentry/webpack-plugin": "2.20.1", "chalk": "3.0.0", "resolve": "1.22.8", diff --git a/packages/node/package.json b/packages/node/package.json index ccae165be8bb..7b7eb3642bf7 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/node", - "version": "8.25.0", + "version": "8.26.0", "description": "Sentry Node SDK using OpenTelemetry for performance instrumentation", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/node", @@ -90,10 +90,10 @@ "@opentelemetry/semantic-conventions": "^1.25.1", "@opentelemetry/instrumentation-generic-pool": "^0.38.0", "@prisma/instrumentation": "5.18.0", - "@sentry/core": "8.25.0", - "@sentry/opentelemetry": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/core": "8.26.0", + "@sentry/opentelemetry": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "import-in-the-middle": "^1.11.0" }, "devDependencies": { diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index eabbba62ca2d..2216991b5e6e 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/nuxt", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Nuxt (EXPERIMENTAL)", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/nuxt", @@ -43,14 +43,14 @@ }, "dependencies": { "@nuxt/kit": "^3.12.2", - "@sentry/browser": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/opentelemetry": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/browser": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/opentelemetry": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "@sentry/vite-plugin": "2.20.1", - "@sentry/vue": "8.25.0" + "@sentry/vue": "8.26.0" }, "devDependencies": { "@nuxt/module-builder": "0.8.1", diff --git a/packages/opentelemetry/package.json b/packages/opentelemetry/package.json index b0b051a42d08..1ffc241172f9 100644 --- a/packages/opentelemetry/package.json +++ b/packages/opentelemetry/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/opentelemetry", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry utilities for OpenTelemetry", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/opentelemetry", @@ -39,9 +39,9 @@ "access": "public" }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", diff --git a/packages/profiling-node/package.json b/packages/profiling-node/package.json index 55bbca6eb100..a779edc4e732 100644 --- a/packages/profiling-node/package.json +++ b/packages/profiling-node/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/profiling-node", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Node.js Profiling", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/profiling-node", @@ -75,10 +75,10 @@ "test": "cross-env SENTRY_PROFILER_BINARY_DIR=lib jest --config jest.config.js" }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/core": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "detect-libc": "^2.0.2", "node-abi": "^3.61.0" }, diff --git a/packages/react/package.json b/packages/react/package.json index c38227d6d30b..9f2c8d5c3c12 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/react", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for React.js", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/react", @@ -39,10 +39,10 @@ "access": "public" }, "dependencies": { - "@sentry/browser": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/browser": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "hoist-non-react-statics": "^3.3.2" }, "peerDependencies": { diff --git a/packages/remix/package.json b/packages/remix/package.json index 4e7655cad905..120f4592d94a 100644 --- a/packages/remix/package.json +++ b/packages/remix/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/remix", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Remix", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/remix", @@ -55,12 +55,12 @@ "@opentelemetry/instrumentation-http": "0.52.1", "@remix-run/router": "1.x", "@sentry/cli": "^2.33.0", - "@sentry/core": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/opentelemetry": "8.25.0", - "@sentry/react": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/core": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/opentelemetry": "8.26.0", + "@sentry/react": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "glob": "^10.3.4", "opentelemetry-instrumentation-remix": "0.7.1", "yargs": "^17.6.0" diff --git a/packages/replay-canvas/package.json b/packages/replay-canvas/package.json index b28b92f9d740..4dd27ce4a18c 100644 --- a/packages/replay-canvas/package.json +++ b/packages/replay-canvas/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/replay-canvas", - "version": "8.25.0", + "version": "8.26.0", "description": "Replay canvas integration", "main": "build/npm/cjs/index.js", "module": "build/npm/esm/index.js", @@ -68,10 +68,10 @@ "@sentry-internal/rrweb": "2.25.0" }, "dependencies": { - "@sentry-internal/replay": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry-internal/replay": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "engines": { "node": ">=14.18" diff --git a/packages/replay-internal/package.json b/packages/replay-internal/package.json index 7500de93d798..cf655cbf1a38 100644 --- a/packages/replay-internal/package.json +++ b/packages/replay-internal/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/replay", - "version": "8.25.0", + "version": "8.26.0", "description": "User replays for Sentry", "main": "build/npm/cjs/index.js", "module": "build/npm/esm/index.js", @@ -68,7 +68,7 @@ "homepage": "https://docs.sentry.io/platforms/javascript/session-replay/", "devDependencies": { "@babel/core": "^7.17.5", - "@sentry-internal/replay-worker": "8.25.0", + "@sentry-internal/replay-worker": "8.26.0", "@sentry-internal/rrweb": "2.25.0", "@sentry-internal/rrweb-snapshot": "2.25.0", "fflate": "^0.8.1", @@ -76,10 +76,10 @@ "jsdom-worker": "^0.2.1" }, "dependencies": { - "@sentry-internal/browser-utils": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry-internal/browser-utils": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "engines": { "node": ">=14.18" diff --git a/packages/replay-worker/package.json b/packages/replay-worker/package.json index 4dcb67603168..337490ecd4f2 100644 --- a/packages/replay-worker/package.json +++ b/packages/replay-worker/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/replay-worker", - "version": "8.25.0", + "version": "8.26.0", "description": "Worker for @sentry-internal/replay", "main": "build/esm/index.js", "module": "build/esm/index.js", diff --git a/packages/solid/package.json b/packages/solid/package.json index 8b4006d7919f..e8c7547014c0 100644 --- a/packages/solid/package.json +++ b/packages/solid/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/solid", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Solid", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/solid", @@ -44,10 +44,10 @@ "access": "public" }, "dependencies": { - "@sentry/browser": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/browser": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "peerDependencies": { "@solidjs/router": "^0.13.4", diff --git a/packages/solidstart/package.json b/packages/solidstart/package.json index e301889fdc0c..3251549a62b5 100644 --- a/packages/solidstart/package.json +++ b/packages/solidstart/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/solidstart", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Solid Start", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/solidstart", @@ -78,12 +78,12 @@ }, "dependencies": { "@opentelemetry/instrumentation": "^0.52.1", - "@sentry/core": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/opentelemetry": "8.25.0", - "@sentry/solid": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/core": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/opentelemetry": "8.26.0", + "@sentry/solid": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "@sentry/vite-plugin": "2.19.0" }, "devDependencies": { diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 24889a757804..cd01ba37e5bc 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/svelte", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Svelte", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/svelte", @@ -39,10 +39,10 @@ "access": "public" }, "dependencies": { - "@sentry/browser": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/browser": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "magic-string": "^0.30.0" }, "peerDependencies": { diff --git a/packages/sveltekit/package.json b/packages/sveltekit/package.json index c2b3fab65322..a3df07e38eff 100644 --- a/packages/sveltekit/package.json +++ b/packages/sveltekit/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/sveltekit", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for SvelteKit", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/sveltekit", @@ -40,12 +40,12 @@ } }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/node": "8.25.0", - "@sentry/opentelemetry": "8.25.0", - "@sentry/svelte": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/core": "8.26.0", + "@sentry/node": "8.26.0", + "@sentry/opentelemetry": "8.26.0", + "@sentry/svelte": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "@sentry/vite-plugin": "2.22.0", "magic-string": "0.30.7", "magicast": "0.2.8", diff --git a/packages/types/package.json b/packages/types/package.json index 2d3f68a5ab1e..3d649c4f3c0f 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/types", - "version": "8.25.0", + "version": "8.26.0", "description": "Types for all Sentry JavaScript SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/types", diff --git a/packages/typescript/package.json b/packages/typescript/package.json index 4825b2245191..890db27ce2f2 100644 --- a/packages/typescript/package.json +++ b/packages/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/typescript", - "version": "8.25.0", + "version": "8.26.0", "description": "Typescript configuration used at Sentry", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/typescript", diff --git a/packages/utils/package.json b/packages/utils/package.json index dabc12ef46fb..f9aaffaeaf56 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/utils", - "version": "8.25.0", + "version": "8.26.0", "description": "Utilities for all Sentry JavaScript SDKs", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/utils", @@ -39,7 +39,7 @@ "access": "public" }, "dependencies": { - "@sentry/types": "8.25.0" + "@sentry/types": "8.26.0" }, "devDependencies": { "@types/array.prototype.flat": "^1.2.1", diff --git a/packages/utils/src/version.ts b/packages/utils/src/version.ts index 3d48b8320114..1b32cd60a8c4 100644 --- a/packages/utils/src/version.ts +++ b/packages/utils/src/version.ts @@ -1 +1 @@ -export const SDK_VERSION = '8.25.0'; +export const SDK_VERSION = '8.26.0'; diff --git a/packages/vercel-edge/package.json b/packages/vercel-edge/package.json index 41c4a359eb0d..93c6b9e46201 100644 --- a/packages/vercel-edge/package.json +++ b/packages/vercel-edge/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/vercel-edge", - "version": "8.25.0", + "version": "8.26.0", "description": "Offical Sentry SDK for the Vercel Edge Runtime", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/vercel-edge", @@ -39,9 +39,9 @@ "access": "public" }, "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "devDependencies": { "@edge-runtime/types": "3.0.1" diff --git a/packages/vue/package.json b/packages/vue/package.json index eb72fc102e36..dbb639eccc40 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/vue", - "version": "8.25.0", + "version": "8.26.0", "description": "Official Sentry SDK for Vue.js", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/vue", @@ -39,10 +39,10 @@ "access": "public" }, "dependencies": { - "@sentry/browser": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/browser": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "peerDependencies": { "vue": "2.x || 3.x" diff --git a/packages/wasm/package.json b/packages/wasm/package.json index 1cb4012fbe38..36d7116050f4 100644 --- a/packages/wasm/package.json +++ b/packages/wasm/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/wasm", - "version": "8.25.0", + "version": "8.26.0", "description": "Support for WASM.", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/wasm", @@ -39,10 +39,10 @@ "access": "public" }, "dependencies": { - "@sentry/browser": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/browser": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "scripts": { "build": "run-p build:transpile build:bundle build:types", From 3db3ba0824567f94a68ab6994dc36c61dc63f840 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 14 Aug 2024 10:24:48 +0200 Subject: [PATCH 08/25] ci: Streamline browser & node unit tests (#13307) Instead of having to keep to separate lists of include/excludes, we now keep this in a single list and invert it when necessary. This way, we should no longer have problems where tests are either run multiple times, or not in the correct env - just add the test to the `browser` list in `ci-unit-tests.ts` to make sure it is not run in multiple node versions unnecessarily. I also added this step to the new package checklist. --- docs/new-sdk-release-checklist.md | 2 +- package.json | 8 +- .../{node-unit-tests.ts => ci-unit-tests.ts} | 92 +++++++++++++------ 3 files changed, 70 insertions(+), 32 deletions(-) rename scripts/{node-unit-tests.ts => ci-unit-tests.ts} (54%) diff --git a/docs/new-sdk-release-checklist.md b/docs/new-sdk-release-checklist.md index 1292c5363fb0..7f1811e53d8f 100644 --- a/docs/new-sdk-release-checklist.md +++ b/docs/new-sdk-release-checklist.md @@ -45,8 +45,8 @@ differ slightly for other SDKs depending on how they are structured and how they - [ ] Make sure `build.yml` CI script is correctly set up to cover tests for the new package - - [ ] Ensure dependent packages are correctly set for “Determine changed packages” - [ ] Ensure unit tests run correctly + - [ ] If it is a browser SDK, add it to `BROWSER_TEST_PACKAGES` in `scripts/ci-unit-tests.ts` - [ ] Make sure the file paths in the ["Upload Artifacts" job](https://github.com/getsentry/sentry-javascript/blob/e5c1486eed236b878f2c49d6a04be86093816ac9/.github/workflows/build.yml#L314-L349) diff --git a/package.json b/package.json index ebf4021a7a6a..ae9491de49f2 100644 --- a/package.json +++ b/package.json @@ -35,10 +35,10 @@ "test:unit": "lerna run --ignore \"@sentry-internal/{browser-integration-tests,e2e-tests,integration-shims,node-integration-tests,overhead-metrics}\" test:unit", "test:update-snapshots": "lerna run test:update-snapshots", "test:pr": "nx affected -t test --exclude \"@sentry-internal/{browser-integration-tests,e2e-tests,integration-shims,node-integration-tests,overhead-metrics}\"", - "test:pr:browser": "yarn test:pr --exclude \"@sentry/{core,utils,opentelemetry,bun,deno,node,profiling-node,aws-serverless,google-cloud-serverless,nextjs,nestjs,astro,cloudflare,solidstart,nuxt,remix,gatsby,sveltekit,vercel-edge}\"", - "test:pr:node": "ts-node ./scripts/node-unit-tests.ts --affected", - "test:ci:browser": "lerna run test --ignore \"@sentry/{core,utils,opentelemetry,bun,deno,node,profiling-node,aws-serverless,google-cloud-serverless,nextjs,nestjs,astro,cloudflare,solidstart,nuxt,remix,gatsby,sveltekit,vercel-edge}\" --ignore \"@sentry-internal/{browser-integration-tests,e2e-tests,integration-shims,node-integration-tests,overhead-metrics}\"", - "test:ci:node": "ts-node ./scripts/node-unit-tests.ts", + "test:pr:browser": "UNIT_TEST_ENV=browser ts-node ./scripts/ci-unit-tests.ts --affected", + "test:pr:node": "UNIT_TEST_ENV=node ts-node ./scripts/ci-unit-tests.ts --affected", + "test:ci:browser": "UNIT_TEST_ENV=browser ts-node ./scripts/ci-unit-tests.ts", + "test:ci:node": "UNIT_TEST_ENV=node ts-node ./scripts/ci-unit-tests.ts", "test:ci:bun": "lerna run test --scope @sentry/bun", "yalc:publish": "lerna run yalc:publish" }, diff --git a/scripts/node-unit-tests.ts b/scripts/ci-unit-tests.ts similarity index 54% rename from scripts/node-unit-tests.ts rename to scripts/ci-unit-tests.ts index e9f22da1309a..ea771b29a957 100644 --- a/scripts/node-unit-tests.ts +++ b/scripts/ci-unit-tests.ts @@ -1,4 +1,6 @@ import * as childProcess from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; type NodeVersion = '14' | '16' | '18' | '20' | '21'; @@ -6,12 +8,17 @@ interface VersionConfig { ignoredPackages: Array<`@${'sentry' | 'sentry-internal'}/${string}`>; } +const UNIT_TEST_ENV = process.env.UNIT_TEST_ENV as 'node' | 'browser' | undefined; + const CURRENT_NODE_VERSION = process.version.replace('v', '').split('.')[0] as NodeVersion; const RUN_AFFECTED = process.argv.includes('--affected'); -const DEFAULT_SKIP_TESTS_PACKAGES = [ - '@sentry-internal/eslint-plugin-sdk', +// These packages are tested separately in CI, so no need to run them here +const DEFAULT_SKIP_PACKAGES = ['@sentry/profiling-node', '@sentry/bun', '@sentry/deno']; + +// All other packages are run for multiple node versions +const BROWSER_TEST_PACKAGES = [ '@sentry/ember', '@sentry/browser', '@sentry/vue', @@ -26,10 +33,9 @@ const DEFAULT_SKIP_TESTS_PACKAGES = [ '@sentry-internal/replay-worker', '@sentry-internal/feedback', '@sentry/wasm', - '@sentry/bun', - '@sentry/deno', ]; +// These are Node-version specific tests that need to be skipped because of support const SKIP_TEST_PACKAGES: Record = { '14': { ignoredPackages: [ @@ -40,6 +46,7 @@ const SKIP_TEST_PACKAGES: Record = { '@sentry/astro', '@sentry/nuxt', '@sentry/nestjs', + '@sentry-internal/eslint-plugin-sdk', ], }, '16': { @@ -56,6 +63,50 @@ const SKIP_TEST_PACKAGES: Record = { }, }; +function getAllPackages(): string[] { + const { workspaces }: { workspaces: string[] } = JSON.parse( + fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8'), + ); + + return workspaces.map(workspacePath => { + const { name }: { name: string } = JSON.parse( + fs.readFileSync(path.join(process.cwd(), workspacePath, 'package.json'), 'utf-8'), + ); + return name; + }); +} + +/** + * Run the tests, accounting for compatibility problems in older versions of Node. + */ +function runTests(): void { + const ignores = new Set(DEFAULT_SKIP_PACKAGES); + + const packages = getAllPackages(); + + if (UNIT_TEST_ENV === 'browser') { + // Since we cannot "include" for affected mode, we instead exclude all other packages + packages.forEach(pkg => { + if (!BROWSER_TEST_PACKAGES.includes(pkg)) { + ignores.add(pkg); + } + }); + } else if (UNIT_TEST_ENV === 'node') { + BROWSER_TEST_PACKAGES.forEach(pkg => ignores.add(pkg)); + } + + const versionConfig = SKIP_TEST_PACKAGES[CURRENT_NODE_VERSION]; + if (versionConfig) { + versionConfig.ignoredPackages.forEach(dep => ignores.add(dep)); + } + + if (RUN_AFFECTED) { + runAffectedTests(ignores); + } else { + runAllTests(ignores); + } +} + /** * Run the given shell command, piping the shell process's `stdin`, `stdout`, and `stderr` to that of the current * process. Returns contents of `stdout`. @@ -67,41 +118,28 @@ function run(cmd: string, options?: childProcess.ExecSyncOptions): void { /** * Run tests, ignoring the given packages */ -function runWithIgnores(skipPackages: string[] = []): void { - const ignoreFlags = skipPackages.map(dep => `--ignore="${dep}"`).join(' '); +function runAllTests(ignorePackages: Set): void { + const ignoreFlags = Array.from(ignorePackages) + .map(dep => `--ignore="${dep}"`) + .join(' '); + run(`yarn test ${ignoreFlags}`); } /** * Run affected tests, ignoring the given packages */ -function runAffectedWithIgnores(skipPackages: string[] = []): void { +function runAffectedTests(ignorePackages: Set): void { const additionalArgs = process.argv .slice(2) .filter(arg => arg !== '--affected') .join(' '); - const ignoreFlags = skipPackages.map(dep => `--exclude="${dep}"`).join(' '); - run(`yarn test:pr ${ignoreFlags} ${additionalArgs}`); -} - -/** - * Run the tests, accounting for compatibility problems in older versions of Node. - */ -function runTests(): void { - const ignores = new Set(); - - DEFAULT_SKIP_TESTS_PACKAGES.forEach(pkg => ignores.add(pkg)); - const versionConfig = SKIP_TEST_PACKAGES[CURRENT_NODE_VERSION]; - if (versionConfig) { - versionConfig.ignoredPackages.forEach(dep => ignores.add(dep)); - } + const excludeFlags = Array.from(ignorePackages) + .map(dep => `--exclude="${dep}"`) + .join(' '); - if (RUN_AFFECTED) { - runAffectedWithIgnores(Array.from(ignores)); - } else { - runWithIgnores(Array.from(ignores)); - } + run(`yarn test:pr ${excludeFlags} ${additionalArgs}`); } runTests(); From 94ad46a5ef822b3c2ae9ec0928978f74a5702bf6 Mon Sep 17 00:00:00 2001 From: Andrei <168741329+andreiborza@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:18:52 +0200 Subject: [PATCH 09/25] fix(solidstart): Make back navigation test less flaky (#13374) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤞 Closes: #13345 --- .../solidstart/src/routes/back-navigation.tsx | 9 +++++++++ .../test-applications/solidstart/src/routes/index.tsx | 4 +--- .../solidstart/tests/performance.client.test.ts | 10 ++++++---- 3 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 dev-packages/e2e-tests/test-applications/solidstart/src/routes/back-navigation.tsx diff --git a/dev-packages/e2e-tests/test-applications/solidstart/src/routes/back-navigation.tsx b/dev-packages/e2e-tests/test-applications/solidstart/src/routes/back-navigation.tsx new file mode 100644 index 000000000000..ddd970944bf3 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/solidstart/src/routes/back-navigation.tsx @@ -0,0 +1,9 @@ +import { A } from '@solidjs/router'; + +export default function BackNavigation() { + return ( + + User 6 + + ); +} diff --git a/dev-packages/e2e-tests/test-applications/solidstart/src/routes/index.tsx b/dev-packages/e2e-tests/test-applications/solidstart/src/routes/index.tsx index 873d542e4bae..eed722cba4e3 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart/src/routes/index.tsx +++ b/dev-packages/e2e-tests/test-applications/solidstart/src/routes/index.tsx @@ -20,9 +20,7 @@ export default function Home() {
  • - - User 6 - + Test back navigation
  • diff --git a/dev-packages/e2e-tests/test-applications/solidstart/tests/performance.client.test.ts b/dev-packages/e2e-tests/test-applications/solidstart/tests/performance.client.test.ts index 6e5f43e016c8..52d9cb219401 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart/tests/performance.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart/tests/performance.client.test.ts @@ -54,8 +54,8 @@ test('updates the transaction when using the back button', async ({ page }) => { return transactionEvent?.transaction === '/users/6' && transactionEvent.contexts?.trace?.op === 'navigation'; }); - await page.goto(`/`); - await page.locator('#navLinkUserBack').click(); + await page.goto(`/back-navigation`); + await page.locator('#navLink').click(); const navigationTxn = await navigationTxnPromise; expect(navigationTxn).toMatchObject({ @@ -72,7 +72,9 @@ test('updates the transaction when using the back button', async ({ page }) => { }); const backNavigationTxnPromise = waitForTransaction('solidstart', async transactionEvent => { - return transactionEvent?.transaction === '/' && transactionEvent.contexts?.trace?.op === 'navigation'; + return ( + transactionEvent?.transaction === '/back-navigation' && transactionEvent.contexts?.trace?.op === 'navigation' + ); }); await page.goBack(); @@ -85,7 +87,7 @@ test('updates the transaction when using the back button', async ({ page }) => { origin: 'auto.navigation.solidstart.solidrouter', }, }, - transaction: '/', + transaction: '/back-navigation', transaction_info: { source: 'url', }, From 5e26092ce007240f2c2bf97feaf6e69bfa7461e6 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 14 Aug 2024 11:45:21 +0200 Subject: [PATCH 10/25] ci: Only store playwright cache on develop (#13358) Should reduce amount of cached data. --- .github/actions/install-playwright/action.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/actions/install-playwright/action.yml b/.github/actions/install-playwright/action.yml index 7f85f5e743ba..9de6e1a2b104 100644 --- a/.github/actions/install-playwright/action.yml +++ b/.github/actions/install-playwright/action.yml @@ -13,14 +13,23 @@ runs: run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT shell: bash - - name: Cache playwright binaries - uses: actions/cache@v4 + - name: Restore cached playwright binaries + uses: actions/cache/restore@v4 id: playwright-cache with: path: | ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }} + # Only store cache on develop branch + - name: Store cached playwright binaries + uses: actions/cache/save@v4 + if: github.event_name == 'push' && github.ref == 'refs/heads/develop' + with: + path: | + ~/.cache/ms-playwright + key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }} + # We always install all browsers, if uncached - name: Install Playwright dependencies (uncached) run: npx playwright install chromium webkit firefox --with-deps From d4c7a095709b6cb3c857667220e4ec9230ca198b Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 14 Aug 2024 11:55:57 +0200 Subject: [PATCH 11/25] feat: Add options for passing nonces to feedback integration (#13347) --- .../feedback/captureFeedbackCsp/init.js | 19 +++++ .../feedback/captureFeedbackCsp/template.html | 13 +++ .../feedback/captureFeedbackCsp/test.ts | 84 +++++++++++++++++++ .../browser/src/utils/lazyLoadIntegration.ts | 9 +- .../feedback/src/core/components/Actor.css.ts | 6 +- .../feedback/src/core/components/Actor.ts | 5 +- .../feedback/src/core/createMainStyles.ts | 11 ++- packages/feedback/src/core/integration.ts | 12 ++- .../src/modal/components/Dialog.css.ts | 6 +- packages/feedback/src/modal/integration.tsx | 2 +- .../components/ScreenshotEditor.tsx | 4 +- .../components/ScreenshotInput.css.ts | 6 +- packages/types/src/feedback/config.ts | 10 +++ 13 files changed, 175 insertions(+), 12 deletions(-) create mode 100644 dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/init.js create mode 100644 dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/template.html create mode 100644 dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/init.js b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/init.js new file mode 100644 index 000000000000..067dbec23fd4 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/init.js @@ -0,0 +1,19 @@ +import * as Sentry from '@sentry/browser'; +// Import this separately so that generatePlugin can handle it for CDN scenarios +import { feedbackIntegration } from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + integrations: [ + feedbackIntegration({ tags: { from: 'integration init' }, styleNonce: 'foo1234', scriptNonce: 'foo1234' }), + ], +}); + +document.addEventListener('securitypolicyviolation', () => { + const container = document.querySelector('#csp-violation'); + if (container) { + container.innerText = 'CSP Violation'; + } +}); diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/template.html b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/template.html new file mode 100644 index 000000000000..919f372ef468 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/template.html @@ -0,0 +1,13 @@ + + + + + + + +
    + + diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts new file mode 100644 index 000000000000..95a8a2eacee8 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts @@ -0,0 +1,84 @@ +import { expect } from '@playwright/test'; + +import { TEST_HOST, sentryTest } from '../../../utils/fixtures'; +import { envelopeRequestParser, getEnvelopeType, shouldSkipFeedbackTest } from '../../../utils/helpers'; + +sentryTest('should capture feedback', async ({ getLocalTestUrl, page }) => { + if (shouldSkipFeedbackTest()) { + sentryTest.skip(); + } + + const feedbackRequestPromise = page.waitForResponse(res => { + const req = res.request(); + + const postData = req.postData(); + if (!postData) { + return false; + } + + try { + return getEnvelopeType(req) === 'feedback'; + } catch (err) { + return false; + } + }); + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + await page.getByText('Report a Bug').click(); + expect(await page.locator(':visible:text-is("Report a Bug")').count()).toEqual(1); + await page.locator('[name="name"]').fill('Jane Doe'); + await page.locator('[name="email"]').fill('janedoe@example.org'); + await page.locator('[name="message"]').fill('my example feedback'); + await page.locator('[data-sentry-feedback] .btn--primary').click(); + + const feedbackEvent = envelopeRequestParser((await feedbackRequestPromise).request()); + expect(feedbackEvent).toEqual({ + type: 'feedback', + breadcrumbs: expect.any(Array), + contexts: { + feedback: { + contact_email: 'janedoe@example.org', + message: 'my example feedback', + name: 'Jane Doe', + source: 'widget', + url: `${TEST_HOST}/index.html`, + }, + trace: { + trace_id: expect.stringMatching(/\w{32}/), + span_id: expect.stringMatching(/\w{16}/), + }, + }, + level: 'info', + tags: { + from: 'integration init', + }, + timestamp: expect.any(Number), + event_id: expect.stringMatching(/\w{32}/), + environment: 'production', + sdk: { + integrations: expect.arrayContaining(['Feedback']), + version: expect.any(String), + name: 'sentry.javascript.browser', + packages: expect.anything(), + }, + request: { + url: `${TEST_HOST}/index.html`, + headers: { + 'User-Agent': expect.stringContaining(''), + }, + }, + platform: 'javascript', + }); + const cspContainer = await page.locator('#csp-violation'); + expect(cspContainer).not.toContainText('CSP Violation'); +}); diff --git a/packages/browser/src/utils/lazyLoadIntegration.ts b/packages/browser/src/utils/lazyLoadIntegration.ts index b023bc18aa95..168d1fd1013b 100644 --- a/packages/browser/src/utils/lazyLoadIntegration.ts +++ b/packages/browser/src/utils/lazyLoadIntegration.ts @@ -31,7 +31,10 @@ const WindowWithMaybeIntegration = WINDOW as { * Lazy load an integration from the CDN. * Rejects if the integration cannot be loaded. */ -export async function lazyLoadIntegration(name: keyof typeof LazyLoadableIntegrations): Promise { +export async function lazyLoadIntegration( + name: keyof typeof LazyLoadableIntegrations, + scriptNonce?: string, +): Promise { const bundle = LazyLoadableIntegrations[name]; // `window.Sentry` is only set when using a CDN bundle, but this method can also be used via the NPM package @@ -56,6 +59,10 @@ export async function lazyLoadIntegration(name: keyof typeof LazyLoadableIntegra script.crossOrigin = 'anonymous'; script.referrerPolicy = 'origin'; + if (scriptNonce) { + script.setAttribute('nonce', scriptNonce); + } + const waitForLoad = new Promise((resolve, reject) => { script.addEventListener('load', () => resolve()); script.addEventListener('error', reject); diff --git a/packages/feedback/src/core/components/Actor.css.ts b/packages/feedback/src/core/components/Actor.css.ts index 60ae7cebd08e..8a8b2c4efa29 100644 --- a/packages/feedback/src/core/components/Actor.css.ts +++ b/packages/feedback/src/core/components/Actor.css.ts @@ -3,7 +3,7 @@ import { DOCUMENT } from '../../constants'; /** * Creates + diff --git a/dev-packages/e2e-tests/test-applications/astro-4/sentry.client.config.js b/dev-packages/e2e-tests/test-applications/astro-4/sentry.client.config.js new file mode 100644 index 000000000000..2b79ec0ed337 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/sentry.client.config.js @@ -0,0 +1,8 @@ +import * as Sentry from '@sentry/astro'; + +Sentry.init({ + dsn: import.meta.env.PUBLIC_E2E_TEST_DSN, + environment: 'qa', + tracesSampleRate: 1.0, + tunnel: 'http://localhost:3031/', // proxy server +}); diff --git a/dev-packages/e2e-tests/test-applications/astro-4/sentry.server.config.js b/dev-packages/e2e-tests/test-applications/astro-4/sentry.server.config.js new file mode 100644 index 000000000000..0662d678dc7c --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/sentry.server.config.js @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/astro'; + +Sentry.init({ + dsn: import.meta.env.PUBLIC_E2E_TEST_DSN, + environment: 'qa', + tracesSampleRate: 1.0, + spotlight: true, + tunnel: 'http://localhost:3031/', // proxy server +}); diff --git a/dev-packages/e2e-tests/test-applications/astro-4/src/env.d.ts b/dev-packages/e2e-tests/test-applications/astro-4/src/env.d.ts new file mode 100644 index 000000000000..f964fe0cffd8 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/src/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/dev-packages/e2e-tests/test-applications/astro-4/src/layouts/Layout.astro b/dev-packages/e2e-tests/test-applications/astro-4/src/layouts/Layout.astro new file mode 100644 index 000000000000..c4e54b834656 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/src/layouts/Layout.astro @@ -0,0 +1,39 @@ +--- +interface Props { + title: string; +} + +const { title } = Astro.props; +--- + + + + + + + + + + {title} + + + + + + diff --git a/dev-packages/e2e-tests/test-applications/astro-4/src/pages/client-error/index.astro b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/client-error/index.astro new file mode 100644 index 000000000000..facd6f077a6e --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/client-error/index.astro @@ -0,0 +1,11 @@ +--- +import Layout from "../../layouts/Layout.astro"; +--- + + + + + + diff --git a/dev-packages/e2e-tests/test-applications/astro-4/src/pages/endpoint-error/api.ts b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/endpoint-error/api.ts new file mode 100644 index 000000000000..a76accdba010 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/endpoint-error/api.ts @@ -0,0 +1,15 @@ +import type { APIRoute } from 'astro'; + +export const prerender = false; + +export const GET: APIRoute = ({ request, url }) => { + if (url.searchParams.has('error')) { + throw new Error('Endpoint Error'); + } + return new Response( + JSON.stringify({ + search: url.search, + sp: url.searchParams, + }), + ); +}; diff --git a/dev-packages/e2e-tests/test-applications/astro-4/src/pages/endpoint-error/index.astro b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/endpoint-error/index.astro new file mode 100644 index 000000000000..f025c76f8365 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/endpoint-error/index.astro @@ -0,0 +1,9 @@ +--- +import Layout from "../../layouts/Layout.astro"; + +export const prerender = false; +--- + + + + diff --git a/dev-packages/e2e-tests/test-applications/astro-4/src/pages/index.astro b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/index.astro new file mode 100644 index 000000000000..088205fc4028 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/index.astro @@ -0,0 +1,36 @@ +--- +import Layout from '../layouts/Layout.astro'; +--- + + +
    +

    Astro E2E Test App

    + +
    +
    + + diff --git a/dev-packages/e2e-tests/test-applications/astro-4/src/pages/ssr-error/index.astro b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/ssr-error/index.astro new file mode 100644 index 000000000000..4ecb7466de70 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/ssr-error/index.astro @@ -0,0 +1,13 @@ +--- +import Layout from "../../layouts/Layout.astro"; + +const a = {} as any; +console.log(a.foo.x); +export const prerender = false; +--- + + + +

    Page with SSR error

    + +
    diff --git a/dev-packages/e2e-tests/test-applications/astro-4/src/pages/test-ssr/index.astro b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/test-ssr/index.astro new file mode 100644 index 000000000000..58f5d80198d7 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/test-ssr/index.astro @@ -0,0 +1,15 @@ +--- +import Layout from "../../layouts/Layout.astro" + +export const prerender = false +--- + + + +

    + This is a server page +

    + + + +
    diff --git a/dev-packages/e2e-tests/test-applications/astro-4/src/pages/test-static/index.astro b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/test-static/index.astro new file mode 100644 index 000000000000..f71bf00c9adf --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/src/pages/test-static/index.astro @@ -0,0 +1,15 @@ +--- +import Layout from "../../layouts/Layout.astro"; + +export const prerender = true; +--- + + + +

    + This is a static page +

    + + + +
    diff --git a/dev-packages/e2e-tests/test-applications/astro-4/start-event-proxy.mjs b/dev-packages/e2e-tests/test-applications/astro-4/start-event-proxy.mjs new file mode 100644 index 000000000000..a657dae0f425 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/start-event-proxy.mjs @@ -0,0 +1,6 @@ +import { startEventProxyServer } from '@sentry-internal/test-utils'; + +startEventProxyServer({ + port: 3031, + proxyServerName: 'astro-4', +}); diff --git a/dev-packages/e2e-tests/test-applications/astro-4/tests/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/astro-4/tests/errors.client.test.ts new file mode 100644 index 000000000000..4cbf4bf36604 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/tests/errors.client.test.ts @@ -0,0 +1,79 @@ +import { expect, test } from '@playwright/test'; +import { waitForError } from '@sentry-internal/test-utils'; + +test.describe('client-side errors', () => { + test('captures error thrown on click', async ({ page }) => { + const errorEventPromise = waitForError('astro-4', errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'client error'; + }); + + await page.goto('/client-error'); + + await page.getByText('Throw Error').click(); + + const errorEvent = await errorEventPromise; + + const errorEventFrames = errorEvent.exception?.values?.[0]?.stacktrace?.frames; + + expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( + expect.objectContaining({ + colno: expect.any(Number), + lineno: expect.any(Number), + filename: expect.stringContaining('/client-error'), + function: 'HTMLButtonElement.onclick', + in_app: true, + }), + ); + + expect(errorEvent).toMatchObject({ + exception: { + values: [ + { + mechanism: { + handled: false, + type: 'onerror', + }, + type: 'Error', + value: 'client error', + stacktrace: expect.any(Object), // detailed check above + }, + ], + }, + level: 'error', + platform: 'javascript', + request: { + url: expect.stringContaining('/client-error'), + headers: { + 'User-Agent': expect.any(String), + }, + }, + event_id: expect.stringMatching(/[a-f0-9]{32}/), + timestamp: expect.any(Number), + sdk: { + integrations: expect.arrayContaining([ + 'InboundFilters', + 'FunctionToString', + 'BrowserApiErrors', + 'Breadcrumbs', + 'GlobalHandlers', + 'LinkedErrors', + 'Dedupe', + 'HttpContext', + 'BrowserTracing', + ]), + name: 'sentry.javascript.astro', + version: expect.any(String), + packages: expect.any(Array), + }, + transaction: '/client-error', + contexts: { + trace: { + trace_id: expect.stringMatching(/[a-f0-9]{32}/), + parent_span_id: expect.stringMatching(/[a-f0-9]{16}/), + span_id: expect.stringMatching(/[a-f0-9]{16}/), + }, + }, + environment: 'qa', + }); + }); +}); diff --git a/dev-packages/e2e-tests/test-applications/astro-4/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/astro-4/tests/errors.server.test.ts new file mode 100644 index 000000000000..d5f07ebe239a --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/tests/errors.server.test.ts @@ -0,0 +1,115 @@ +import { expect, test } from '@playwright/test'; +import { waitForError } from '@sentry-internal/test-utils'; + +test.describe('server-side errors', () => { + test('captures SSR error', async ({ page }) => { + const errorEventPromise = waitForError('astro-4', errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === "Cannot read properties of undefined (reading 'x')"; + }); + + await page.goto('/ssr-error'); + + const errorEvent = await errorEventPromise; + + expect(errorEvent).toMatchObject({ + contexts: { + app: expect.any(Object), + cloud_resource: expect.any(Object), + culture: expect.any(Object), + device: expect.any(Object), + os: expect.any(Object), + runtime: expect.any(Object), + trace: { + span_id: '', //TODO: This is a bug! We should expect.stringMatching(/[a-f0-9]{16}/) instead of '' + trace_id: expect.stringMatching(/[a-f0-9]{32}/), + }, + }, + environment: 'qa', + event_id: expect.stringMatching(/[a-f0-9]{32}/), + exception: { + values: [ + { + mechanism: { + data: { + function: 'astroMiddleware', + }, + handled: false, + type: 'astro', + }, + stacktrace: expect.any(Object), + type: 'TypeError', + value: "Cannot read properties of undefined (reading 'x')", + }, + ], + }, + platform: 'node', + request: { + cookies: {}, + headers: expect.objectContaining({ + // demonstrates that requestData integration is getting data + host: 'localhost:3030', + 'user-agent': expect.any(String), + }), + method: 'GET', + url: expect.stringContaining('/ssr-error'), + }, + sdk: { + integrations: expect.any(Array), + name: 'sentry.javascript.astro', + packages: expect.any(Array), + version: expect.any(String), + }, + server_name: expect.any(String), + timestamp: expect.any(Number), + transaction: 'GET /ssr-error', + }); + }); + + test('captures endpoint error', async ({ page }) => { + const errorEventPromise = waitForError('astro-4', errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Endpoint Error'; + }); + + await page.goto('/endpoint-error'); + await page.getByText('Get Data').click(); + + const errorEvent = await errorEventPromise; + + expect(errorEvent).toMatchObject({ + contexts: { + trace: { + parent_span_id: expect.stringMatching(/[a-f0-9]{16}/), + span_id: expect.stringMatching(/[a-f0-9]{16}/), + trace_id: expect.stringMatching(/[a-f0-9]{32}/), + }, + }, + exception: { + values: [ + { + mechanism: { + data: { + function: 'astroMiddleware', + }, + handled: false, + type: 'astro', + }, + stacktrace: expect.any(Object), + type: 'Error', + value: 'Endpoint Error', + }, + ], + }, + platform: 'node', + request: { + cookies: {}, + headers: expect.objectContaining({ + accept: expect.any(String), + }), + method: 'GET', + query_string: 'error=1', + url: expect.stringContaining('endpoint-error/api?error=1'), + }, + transaction: 'GET /endpoint-error/api', + }); + }); +}); diff --git a/dev-packages/e2e-tests/test-applications/astro-4/tests/tracing.dynamic.test.ts b/dev-packages/e2e-tests/test-applications/astro-4/tests/tracing.dynamic.test.ts new file mode 100644 index 000000000000..9a295f677d96 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/tests/tracing.dynamic.test.ts @@ -0,0 +1,123 @@ +import { expect, test } from '@playwright/test'; +import { waitForTransaction } from '@sentry-internal/test-utils'; + +test.describe('tracing in dynamically rendered (ssr) routes', () => { + test('sends server and client pageload spans with the same trace id', async ({ page }) => { + const clientPageloadTxnPromise = waitForTransaction('astro-4', txnEvent => { + return txnEvent?.transaction === '/test-ssr'; + }); + + const serverPageRequestTxnPromise = waitForTransaction('astro-4', txnEvent => { + return txnEvent?.transaction === 'GET /test-ssr'; + }); + + await page.goto('/test-ssr'); + + const clientPageloadTxn = await clientPageloadTxnPromise; + const serverPageRequestTxn = await serverPageRequestTxnPromise; + + const clientPageloadTraceId = clientPageloadTxn.contexts?.trace?.trace_id; + const clientPageloadParentSpanId = clientPageloadTxn.contexts?.trace?.parent_span_id; + + const serverPageRequestTraceId = serverPageRequestTxn.contexts?.trace?.trace_id; + const serverPageloadSpanId = serverPageRequestTxn.contexts?.trace?.span_id; + + expect(clientPageloadTraceId).toEqual(serverPageRequestTraceId); + expect(clientPageloadParentSpanId).toEqual(serverPageloadSpanId); + + expect(clientPageloadTxn).toMatchObject({ + contexts: { + trace: { + data: expect.objectContaining({ + 'sentry.op': 'pageload', + 'sentry.origin': 'auto.pageload.browser', + 'sentry.sample_rate': 1, + 'sentry.source': 'url', + }), + op: 'pageload', + origin: 'auto.pageload.browser', + span_id: expect.stringMatching(/[a-f0-9]{16}/), + parent_span_id: expect.stringMatching(/[a-f0-9]{16}/), + trace_id: expect.stringMatching(/[a-f0-9]{32}/), + }, + }, + environment: 'qa', + event_id: expect.stringMatching(/[a-f0-9]{32}/), + measurements: expect.any(Object), + platform: 'javascript', + request: expect.any(Object), + sdk: { + integrations: expect.any(Array), + name: 'sentry.javascript.astro', + packages: expect.any(Array), + version: expect.any(String), + }, + spans: expect.any(Array), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + transaction: '/test-ssr', + transaction_info: { + source: 'url', + }, + type: 'transaction', + }); + + expect(serverPageRequestTxn).toMatchObject({ + breadcrumbs: expect.any(Array), + contexts: { + app: expect.any(Object), + cloud_resource: expect.any(Object), + culture: expect.any(Object), + device: expect.any(Object), + os: expect.any(Object), + otel: expect.any(Object), + runtime: expect.any(Object), + trace: { + data: { + 'http.response.status_code': 200, + method: 'GET', + 'sentry.op': 'http.server', + 'sentry.origin': 'auto.http.astro', + 'sentry.sample_rate': 1, + 'sentry.source': 'route', + url: expect.stringContaining('/test-ssr'), + }, + op: 'http.server', + origin: 'auto.http.astro', + status: 'ok', + span_id: expect.stringMatching(/[a-f0-9]{16}/), + trace_id: expect.stringMatching(/[a-f0-9]{32}/), + }, + }, + environment: 'qa', + event_id: expect.stringMatching(/[a-f0-9]{32}/), + platform: 'node', + request: { + cookies: {}, + headers: expect.objectContaining({ + // demonstrates that request data integration can extract headers + accept: expect.any(String), + 'accept-encoding': expect.any(String), + 'user-agent': expect.any(String), + }), + method: 'GET', + url: expect.stringContaining('/test-ssr'), + }, + sdk: { + integrations: expect.any(Array), + name: 'sentry.javascript.astro', + packages: expect.any(Array), + version: expect.any(String), + }, + server_name: expect.any(String), + spans: expect.any(Array), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + transaction: 'GET /test-ssr', + transaction_info: { + source: 'route', + }, + type: 'transaction', + }); + }); +}); diff --git a/dev-packages/e2e-tests/test-applications/astro-4/tests/tracing.static.test.ts b/dev-packages/e2e-tests/test-applications/astro-4/tests/tracing.static.test.ts new file mode 100644 index 000000000000..8817b2b22aa7 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/tests/tracing.static.test.ts @@ -0,0 +1,62 @@ +import { expect, test } from '@playwright/test'; +import { waitForTransaction } from '@sentry-internal/test-utils'; + +test.describe('tracing in static/pre-rendered routes', () => { + test('only sends client pageload span with traceId from pre-rendered tags', async ({ page }) => { + const clientPageloadTxnPromise = waitForTransaction('astro-4', txnEvent => { + return txnEvent?.transaction === '/test-static'; + }); + + waitForTransaction('astro-4', evt => { + if (evt.platform !== 'javascript') { + throw new Error('Server transaction should not be sent'); + } + return false; + }); + + await page.goto('/test-static'); + + const clientPageloadTxn = await clientPageloadTxnPromise; + + const clientPageloadTraceId = clientPageloadTxn.contexts?.trace?.trace_id; + const clientPageloadParentSpanId = clientPageloadTxn.contexts?.trace?.parent_span_id; + + const sentryTraceMetaTagContent = await page.locator('meta[name="sentry-trace"]').getAttribute('content'); + const baggageMetaTagContent = await page.locator('meta[name="baggage"]').getAttribute('content'); + + const [metaTraceId, metaParentSpanId, metaSampled] = sentryTraceMetaTagContent?.split('-') || []; + + expect(clientPageloadTraceId).toMatch(/[a-f0-9]{32}/); + expect(clientPageloadParentSpanId).toMatch(/[a-f0-9]{16}/); + expect(metaSampled).toBe('1'); + + expect(clientPageloadTxn).toMatchObject({ + contexts: { + trace: { + data: expect.objectContaining({ + 'sentry.op': 'pageload', + 'sentry.origin': 'auto.pageload.browser', + 'sentry.sample_rate': 1, + 'sentry.source': 'url', + }), + op: 'pageload', + origin: 'auto.pageload.browser', + parent_span_id: metaParentSpanId, + span_id: expect.stringMatching(/[a-f0-9]{16}/), + trace_id: metaTraceId, + }, + }, + platform: 'javascript', + transaction: '/test-static', + transaction_info: { + source: 'url', + }, + type: 'transaction', + }); + + expect(baggageMetaTagContent).toContain('sentry-transaction=GET%20%2Ftest-static%2F'); // URL-encoded for 'GET /test-static/' + expect(baggageMetaTagContent).toContain('sentry-sampled=true'); + + await page.waitForTimeout(1000); // wait another sec to ensure no server transaction is sent + }); +}); diff --git a/dev-packages/e2e-tests/test-applications/astro-4/tsconfig.json b/dev-packages/e2e-tests/test-applications/astro-4/tsconfig.json new file mode 100644 index 000000000000..77da9dd00982 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/astro-4/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "astro/tsconfigs/strict" +} \ No newline at end of file diff --git a/packages/astro/src/server/middleware.ts b/packages/astro/src/server/middleware.ts index 3752bd30d448..95d099ff0526 100644 --- a/packages/astro/src/server/middleware.ts +++ b/packages/astro/src/server/middleware.ts @@ -147,7 +147,7 @@ async function instrumentRequest( async span => { const originalResponse = await next(); - if (span && originalResponse.status) { + if (originalResponse.status) { setHttpStatus(span, originalResponse.status); } From 2f11b7ef17c1105ba6be5cd1dd19e25dffc597aa Mon Sep 17 00:00:00 2001 From: Nicolas Charpentier Date: Fri, 16 Aug 2024 03:24:37 -0400 Subject: [PATCH 18/25] docs: Fix v7 changelog format and link (#13395) Minor changes: I realized that the formatting was broken for `v8` and that the migration guide wasn't linking to the specific section like other changelogs. --- docs/changelog/v7.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog/v7.md b/docs/changelog/v7.md index 16072a8f8121..e784702015e0 100644 --- a/docs/changelog/v7.md +++ b/docs/changelog/v7.md @@ -1,7 +1,7 @@ # Changelog for Sentry SDK 7.x Support for Sentry SDK v7 will be dropped soon. We recommend migrating to the latest version of the SDK. You can migrate -from `v7` to `v8 of the SDK by following the [migration guide](../../MIGRATION.md). +from `v7` of the SDK to `v8` by following the [migration guide](../../MIGRATION.md#upgrading-from-7x-to-8x). ## 7.118.0 From a7aa35c5b90d220221075edc43d73a54db75c9d8 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Fri, 16 Aug 2024 09:55:55 +0200 Subject: [PATCH 19/25] ci: Fix crypto not being available (#13385) CI is angery. Crypto is only on global from Node 19 onwards. --- dev-packages/browser-integration-tests/utils/fixtures.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-packages/browser-integration-tests/utils/fixtures.ts b/dev-packages/browser-integration-tests/utils/fixtures.ts index 42585a3756f0..e154ddc25988 100644 --- a/dev-packages/browser-integration-tests/utils/fixtures.ts +++ b/dev-packages/browser-integration-tests/utils/fixtures.ts @@ -1,3 +1,4 @@ +import crypto from 'crypto'; import fs from 'fs'; import path from 'path'; /* eslint-disable no-empty-pattern */ From ba9a704f039f49fe8ed7546378b8325f1384ea4d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:44:46 +0200 Subject: [PATCH 20/25] ref: Add external contributor to CHANGELOG.md (#13400) This PR adds the external contributor to the CHANGELOG.md file, so that they are credited for their contribution. See #13395 Co-authored-by: mydea <2411343+mydea@users.noreply.github.com> --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index be7298ed213a..7864efac6871 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +Work in this release was contributed by @charpeni. Thank you for your contribution! + ## 8.26.0 ### Important Changes From 0d3d2a1cfe9e0a131c72f85a898df583b0b225eb Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 26 Aug 2024 10:45:36 -0400 Subject: [PATCH 21/25] docs(cloudflare): Fix spacing in README snippet (#13368) Fixes spacing in readme snippet --- packages/cloudflare/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/cloudflare/README.md b/packages/cloudflare/README.md index f7de52a56e88..398153563f1c 100644 --- a/packages/cloudflare/README.md +++ b/packages/cloudflare/README.md @@ -114,16 +114,16 @@ Currently only ESM handlers are supported. import * as Sentry from '@sentry/cloudflare'; export default withSentry( - (env) => ({ - dsn: env.SENTRY_DSN, + env => ({ + dsn: env.SENTRY_DSN, // Set tracesSampleRate to 1.0 to capture 100% of spans for tracing. - tracesSampleRate: 1.0, - }), - { - async fetch(request, env, ctx) { - return new Response('Hello World!'); - }, - } satisfies ExportedHandler + tracesSampleRate: 1.0, + }), + { + async fetch(request, env, ctx) { + return new Response('Hello World!'); + }, + } satisfies ExportedHandler, ); ``` From fba8cc70da8e69d0a73e1488ad01913e1f1b7e82 Mon Sep 17 00:00:00 2001 From: Catherine Lee <55311782+c298lee@users.noreply.github.com> Date: Mon, 26 Aug 2024 10:58:41 -0400 Subject: [PATCH 22/25] feat(feedback): Improve error message for 403 errors (#13441) If the domain is not in `Allowed Domains` in the Sentry project settings, it would cause a 403 error. The default setting is `*` so this only occurs when the user changes these settings. Fixes https://github.com/getsentry/sentry-javascript/issues/9856 --- packages/feedback/src/core/sendFeedback.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/feedback/src/core/sendFeedback.ts b/packages/feedback/src/core/sendFeedback.ts index ca9875284c6e..c0b8ccaa2704 100644 --- a/packages/feedback/src/core/sendFeedback.ts +++ b/packages/feedback/src/core/sendFeedback.ts @@ -64,6 +64,12 @@ export const sendFeedback: SendFeedback = ( ); } + if (response && typeof response.statusCode === 'number' && response.statusCode === 403) { + return reject( + 'Unable to send Feedback. This could be because this domain is not in your list of allowed domains.', + ); + } + return reject( 'Unable to send Feedback. This could be because of network issues, or because you are using an ad-blocker', ); From f1182d33ea07eb05a7643fbfd08895802df7ac04 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Tue, 13 Aug 2024 10:47:41 -0400 Subject: [PATCH 23/25] feat(node): add genericPool integration using opentelemetry instrumentation Signed-off-by: Kaung Zin Hein --- .../.yalc/@sentry/core/LICENSE | 21 +++ .../.yalc/@sentry/core/README.md | 23 ++++ .../.yalc/@sentry/core/package.json | 70 ++++++++++ .../.yalc/@sentry/core/yalc.sig | 1 + .../.yalc/@sentry/node/LICENSE | 21 +++ .../.yalc/@sentry/node/README.md | 77 +++++++++++ .../.yalc/@sentry/node/package.json | 128 ++++++++++++++++++ .../.yalc/@sentry/node/yalc.sig | 1 + .../.yalc/@sentry/types/LICENSE | 21 +++ .../.yalc/@sentry/types/README.md | 20 +++ .../.yalc/@sentry/types/package.json | 63 +++++++++ .../.yalc/@sentry/types/yalc.sig | 1 + .../.yalc/@sentry/utils/LICENSE | 21 +++ .../.yalc/@sentry/utils/README.md | 23 ++++ .../.yalc/@sentry/utils/package.json | 70 ++++++++++ .../.yalc/@sentry/utils/yalc.sig | 1 + .../suites/tracing/genericPool/scenario.js | 100 ++++++++++++++ .../suites/tracing/genericPool/test.ts | 24 ++++ dev-packages/node-integration-tests/yalc.lock | 24 ++++ 19 files changed, 710 insertions(+) create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/core/LICENSE create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/core/README.md create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/core/package.json create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/core/yalc.sig create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/node/LICENSE create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/node/README.md create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/node/package.json create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/node/yalc.sig create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/types/LICENSE create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/types/README.md create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/types/package.json create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/types/yalc.sig create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/utils/LICENSE create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/utils/README.md create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/utils/package.json create mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/utils/yalc.sig create mode 100644 dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js create mode 100644 dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts create mode 100644 dev-packages/node-integration-tests/yalc.lock diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/core/LICENSE b/dev-packages/node-integration-tests/.yalc/@sentry/core/LICENSE new file mode 100644 index 000000000000..d5b40b7c4219 --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/core/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2024 Functional Software, Inc. dba Sentry + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/core/README.md b/dev-packages/node-integration-tests/.yalc/@sentry/core/README.md new file mode 100644 index 000000000000..3e44a1dfc7fa --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/core/README.md @@ -0,0 +1,23 @@ +

    + + Sentry + +

    + +# Sentry JavaScript SDK Core + +[![npm version](https://img.shields.io/npm/v/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) +[![npm dm](https://img.shields.io/npm/dm/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) +[![npm dt](https://img.shields.io/npm/dt/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) + +## Links + +- [Official SDK Docs](https://docs.sentry.io/quickstart/) +- [TypeDoc](http://getsentry.github.io/sentry-javascript/) + +## General + +This package contains interface definitions, base classes and utilities for building Sentry JavaScript SDKs, like +`@sentry/node` or `@sentry/browser`. + +Please consider all classes and exported functions and interfaces `internal`. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/core/package.json b/dev-packages/node-integration-tests/.yalc/@sentry/core/package.json new file mode 100644 index 000000000000..431de389caf0 --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/core/package.json @@ -0,0 +1,70 @@ +{ + "name": "@sentry/core", + "version": "8.25.0+b6304601", + "description": "Base implementation for all Sentry JavaScript SDKs", + "repository": "git://github.com/getsentry/sentry-javascript.git", + "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/core", + "author": "Sentry", + "license": "MIT", + "engines": { + "node": ">=14.18" + }, + "files": [ + "/build" + ], + "main": "build/cjs/index.js", + "module": "build/esm/index.js", + "types": "build/types/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./build/types/index.d.ts", + "default": "./build/esm/index.js" + }, + "require": { + "types": "./build/types/index.d.ts", + "default": "./build/cjs/index.js" + } + } + }, + "typesVersions": { + "<4.9": { + "build/types/index.d.ts": [ + "build/types-ts3.8/index.d.ts" + ] + } + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" + }, + "scripts": { + "build": "run-p build:transpile build:types", + "build:dev": "yarn build", + "build:transpile": "rollup -c rollup.npm.config.mjs", + "build:types": "run-s build:types:core build:types:downlevel", + "build:types:core": "tsc -p tsconfig.types.json", + "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8", + "build:watch": "run-p build:transpile:watch build:types:watch", + "build:dev:watch": "yarn build:watch", + "build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch", + "build:types:watch": "tsc -p tsconfig.types.json --watch", + "build:tarball": "npm pack", + "circularDepCheck": "madge --circular src/index.ts", + "clean": "rimraf build coverage sentry-core-*.tgz", + "fix": "eslint . --format stylish --fix", + "lint": "eslint . --format stylish", + "test": "jest", + "test:watch": "jest --watch", + "yalc:publish": "yalc publish --push --sig" + }, + "volta": { + "extends": "../../package.json" + }, + "sideEffects": false, + "yalcSig": "b63046016939e0e6e9861c3fe8b39843" +} diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/core/yalc.sig b/dev-packages/node-integration-tests/.yalc/@sentry/core/yalc.sig new file mode 100644 index 000000000000..6d0256ed73bf --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/core/yalc.sig @@ -0,0 +1 @@ +b63046016939e0e6e9861c3fe8b39843 \ No newline at end of file diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/node/LICENSE b/dev-packages/node-integration-tests/.yalc/@sentry/node/LICENSE new file mode 100644 index 000000000000..6bfafc44539c --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/node/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-2024 Functional Software, Inc. dba Sentry + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/node/README.md b/dev-packages/node-integration-tests/.yalc/@sentry/node/README.md new file mode 100644 index 000000000000..6471538fb4f0 --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/node/README.md @@ -0,0 +1,77 @@ +

    + + Sentry + +

    + +# Official Sentry SDK for Node + +[![npm version](https://img.shields.io/npm/v/@sentry/node.svg)](https://www.npmjs.com/package/@sentry/node) +[![npm dm](https://img.shields.io/npm/dm/@sentry/node.svg)](https://www.npmjs.com/package/@sentry/node) +[![npm dt](https://img.shields.io/npm/dt/@sentry/node.svg)](https://www.npmjs.com/package/@sentry/node) + +## Installation + +```bash +npm install @sentry/node + +# Or yarn +yarn add @sentry/node +``` + +## Usage + +Sentry should be initialized as early in your app as possible. It is essential that you call `Sentry.init` before you +require any other modules in your application, otherwise auto-instrumentation of these modules will **not** work. + +You need to create a file named `instrument.js` that imports and initializes Sentry: + +```js +// CJS Syntax +const Sentry = require('@sentry/node'); +// ESM Syntax +import * as Sentry from '@sentry/node'; + +Sentry.init({ + dsn: '__DSN__', + // ... +}); +``` + +You need to require or import the `instrument.js` file before importing any other modules in your application. This is +necessary to ensure that Sentry can automatically instrument all modules in your application: + +```js +// Import this first! +import './instrument'; + +// Now import other modules +import http from 'http'; + +// Your application code goes here +``` + +### ESM Support + +When running your application in ESM mode, you should use the Node.js +[`--import`](https://nodejs.org/api/cli.html#--importmodule) command line option to ensure that Sentry is loaded before +the application code is evaluated. + +Adjust the Node.js call for your application to use the `--import` parameter and point it at `instrument.js`, which +contains your `Sentry.init`() code: + +```bash +# Note: This is only available for Node v18.19.0 onwards. +node --import ./instrument.mjs app.mjs +``` + +If it is not possible for you to pass the `--import` flag to the Node.js binary, you can alternatively use the +`NODE_OPTIONS` environment variable as follows: + +```bash +NODE_OPTIONS="--import ./instrument.mjs" npm run start +``` + +## Links + +- [Official SDK Docs](https://docs.sentry.io/quickstart/) diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/node/package.json b/dev-packages/node-integration-tests/.yalc/@sentry/node/package.json new file mode 100644 index 000000000000..43473a72ed2d --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/node/package.json @@ -0,0 +1,128 @@ +{ + "name": "@sentry/node", + "version": "8.25.0+fdee85f9", + "description": "Sentry Node SDK using OpenTelemetry for performance instrumentation", + "repository": "git://github.com/getsentry/sentry-javascript.git", + "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/node", + "author": "Sentry", + "license": "MIT", + "engines": { + "node": ">=14.18" + }, + "files": [ + "/build" + ], + "main": "build/cjs/index.js", + "module": "build/esm/index.js", + "types": "build/types/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./build/types/index.d.ts", + "default": "./build/esm/index.js" + }, + "require": { + "types": "./build/types/index.d.ts", + "default": "./build/cjs/index.js" + } + }, + "./import": { + "import": { + "default": "./build/import-hook.mjs" + } + }, + "./loader": { + "import": { + "default": "./build/loader-hook.mjs" + } + }, + "./init": { + "import": { + "default": "./build/esm/init.js" + }, + "require": { + "default": "./build/cjs/init.js" + } + }, + "./preload": { + "import": { + "default": "./build/esm/preload.js" + }, + "require": { + "default": "./build/cjs/preload.js" + } + } + }, + "typesVersions": { + "<4.9": { + "build/types/index.d.ts": [ + "build/types-ts3.8/index.d.ts" + ] + } + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.25.1", + "@opentelemetry/core": "^1.25.1", + "@opentelemetry/instrumentation": "^0.52.1", + "@opentelemetry/instrumentation-connect": "0.38.0", + "@opentelemetry/instrumentation-express": "0.41.1", + "@opentelemetry/instrumentation-fastify": "0.38.0", + "@opentelemetry/instrumentation-fs": "0.14.0", + "@opentelemetry/instrumentation-generic-pool": "^0.38.0", + "@opentelemetry/instrumentation-graphql": "0.42.0", + "@opentelemetry/instrumentation-hapi": "0.40.0", + "@opentelemetry/instrumentation-http": "0.52.1", + "@opentelemetry/instrumentation-ioredis": "0.42.0", + "@opentelemetry/instrumentation-koa": "0.42.0", + "@opentelemetry/instrumentation-mongodb": "0.46.0", + "@opentelemetry/instrumentation-mongoose": "0.40.0", + "@opentelemetry/instrumentation-mysql": "0.40.0", + "@opentelemetry/instrumentation-mysql2": "0.40.0", + "@opentelemetry/instrumentation-nestjs-core": "0.39.0", + "@opentelemetry/instrumentation-pg": "0.43.0", + "@opentelemetry/instrumentation-redis-4": "0.41.0", + "@opentelemetry/resources": "^1.25.1", + "@opentelemetry/sdk-trace-base": "^1.25.1", + "@opentelemetry/semantic-conventions": "^1.25.1", + "@prisma/instrumentation": "5.17.0", + "@sentry/core": "8.25.0", + "@sentry/opentelemetry": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0", + "import-in-the-middle": "^1.11.0" + }, + "optionalDependencies": { + "opentelemetry-instrumentation-fetch-node": "1.2.3" + }, + "scripts": { + "build": "run-p build:transpile build:types", + "build:dev": "yarn build", + "build:transpile": "rollup -c rollup.npm.config.mjs", + "build:types": "run-s build:types:core build:types:downlevel", + "build:types:core": "tsc -p tsconfig.types.json", + "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8", + "build:watch": "run-p build:transpile:watch build:types:watch", + "build:dev:watch": "yarn build:watch", + "build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch", + "build:types:watch": "tsc -p tsconfig.types.json --watch", + "build:tarball": "npm pack", + "circularDepCheck": "madge --circular src/index.ts", + "clean": "rimraf build coverage sentry-node-*.tgz", + "fix": "eslint . --format stylish --fix", + "lint": "eslint . --format stylish", + "test": "yarn test:jest", + "test:jest": "jest", + "test:watch": "jest --watch", + "yalc:publish": "yalc publish --push --sig" + }, + "volta": { + "extends": "../../package.json" + }, + "sideEffects": false, + "yalcSig": "fdee85f9c066418865de6221a8dc7314" +} diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/node/yalc.sig b/dev-packages/node-integration-tests/.yalc/@sentry/node/yalc.sig new file mode 100644 index 000000000000..f4e4ec128ba9 --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/node/yalc.sig @@ -0,0 +1 @@ +fdee85f9c066418865de6221a8dc7314 \ No newline at end of file diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/types/LICENSE b/dev-packages/node-integration-tests/.yalc/@sentry/types/LICENSE new file mode 100644 index 000000000000..d5b40b7c4219 --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/types/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2024 Functional Software, Inc. dba Sentry + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/types/README.md b/dev-packages/node-integration-tests/.yalc/@sentry/types/README.md new file mode 100644 index 000000000000..4c0e2d9cbc34 --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/types/README.md @@ -0,0 +1,20 @@ +

    + + Sentry + +

    + +# Sentry JavaScript SDK Types + +[![npm version](https://img.shields.io/npm/v/@sentry/types.svg)](https://www.npmjs.com/package/@sentry/types) +[![npm dm](https://img.shields.io/npm/dm/@sentry/types.svg)](https://www.npmjs.com/package/@sentry/types) +[![npm dt](https://img.shields.io/npm/dt/@sentry/types.svg)](https://www.npmjs.com/package/@sentry/types) + +## Links + +- [Official SDK Docs](https://docs.sentry.io/quickstart/) +- [TypeDoc](http://getsentry.github.io/sentry-javascript/) + +## General + +Common types used by the Sentry JavaScript SDKs. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/types/package.json b/dev-packages/node-integration-tests/.yalc/@sentry/types/package.json new file mode 100644 index 000000000000..b97ec606c395 --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/types/package.json @@ -0,0 +1,63 @@ +{ + "name": "@sentry/types", + "version": "8.25.0+09174750", + "description": "Types for all Sentry JavaScript SDKs", + "repository": "git://github.com/getsentry/sentry-javascript.git", + "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/types", + "author": "Sentry", + "license": "MIT", + "engines": { + "node": ">=14.18" + }, + "files": [ + "/build" + ], + "main": "build/cjs/index.js", + "module": "build/esm/index.js", + "types": "build/types/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./build/types/index.d.ts", + "default": "./build/esm/index.js" + }, + "require": { + "types": "./build/types/index.d.ts", + "default": "./build/cjs/index.js" + } + } + }, + "typesVersions": { + "<4.9": { + "build/types/index.d.ts": [ + "build/types-ts3.8/index.d.ts" + ] + } + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "run-p build:transpile build:types", + "build:dev": "yarn build", + "build:transpile": "rollup -c rollup.npm.config.mjs", + "build:types": "run-s build:types:core build:types:downlevel", + "build:types:core": "tsc -p tsconfig.types.json", + "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8", + "build:watch": "run-p build:transpile:watch build:types:watch", + "build:dev:watch": "yarn build:watch", + "build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch", + "build:types:watch": "tsc -p tsconfig.types.json --watch", + "build:tarball": "npm pack", + "clean": "rimraf build sentry-types-*.tgz", + "lint": "eslint . --format stylish", + "fix": "eslint . --format stylish --fix", + "yalc:publish": "yalc publish --push --sig" + }, + "volta": { + "extends": "../../package.json" + }, + "sideEffects": false, + "yalcSig": "091747500ba09e4fef7b4e461001fdbf" +} diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/types/yalc.sig b/dev-packages/node-integration-tests/.yalc/@sentry/types/yalc.sig new file mode 100644 index 000000000000..46fbf9051f5c --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/types/yalc.sig @@ -0,0 +1 @@ +091747500ba09e4fef7b4e461001fdbf \ No newline at end of file diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/utils/LICENSE b/dev-packages/node-integration-tests/.yalc/@sentry/utils/LICENSE new file mode 100644 index 000000000000..d5b40b7c4219 --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/utils/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2024 Functional Software, Inc. dba Sentry + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/utils/README.md b/dev-packages/node-integration-tests/.yalc/@sentry/utils/README.md new file mode 100644 index 000000000000..812bb86a3525 --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/utils/README.md @@ -0,0 +1,23 @@ +

    + + Sentry + +

    + +# Sentry JavaScript SDK Utilities + +[![npm version](https://img.shields.io/npm/v/@sentry/utils.svg)](https://www.npmjs.com/package/@sentry/utils) +[![npm dm](https://img.shields.io/npm/dm/@sentry/utils.svg)](https://www.npmjs.com/package/@sentry/utils) +[![npm dt](https://img.shields.io/npm/dt/@sentry/utils.svg)](https://www.npmjs.com/package/@sentry/utils) + +## Links + +- [Official SDK Docs](https://docs.sentry.io/quickstart/) +- [TypeDoc](http://getsentry.github.io/sentry-javascript/) + +## General + +Common utilities used by the Sentry JavaScript SDKs. + +Note: This package is only meant to be used internally, and as such is not part of our public API contract and does not +follow semver. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/utils/package.json b/dev-packages/node-integration-tests/.yalc/@sentry/utils/package.json new file mode 100644 index 000000000000..ec5720de4c0c --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/utils/package.json @@ -0,0 +1,70 @@ +{ + "name": "@sentry/utils", + "version": "8.25.0+eb0f5131", + "description": "Utilities for all Sentry JavaScript SDKs", + "repository": "git://github.com/getsentry/sentry-javascript.git", + "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/utils", + "author": "Sentry", + "license": "MIT", + "engines": { + "node": ">=14.18" + }, + "files": [ + "/build" + ], + "main": "build/cjs/index.js", + "module": "build/esm/index.js", + "types": "build/types/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./build/types/index.d.ts", + "default": "./build/esm/index.js" + }, + "require": { + "types": "./build/types/index.d.ts", + "default": "./build/cjs/index.js" + } + } + }, + "typesVersions": { + "<4.9": { + "build/types/index.d.ts": [ + "build/types-ts3.8/index.d.ts" + ] + } + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@sentry/types": "8.25.0" + }, + "scripts": { + "build": "run-p build:transpile build:types", + "build:dev": "yarn build", + "build:transpile": "yarn ts-node scripts/buildRollup.ts", + "build:types": "run-s build:types:core build:types:downlevel", + "build:types:core": "tsc -p tsconfig.types.json", + "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8", + "build:watch": "run-p build:transpile:watch build:types:watch", + "build:dev:watch": "yarn build:watch", + "build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch", + "build:types:watch": "tsc -p tsconfig.types.json --watch", + "build:tarball": "npm pack", + "circularDepCheck": "madge --circular src/index.ts", + "clean": "rimraf build coverage cjs esm sentry-utils-*.tgz", + "fix": "eslint . --format stylish --fix", + "lint": "eslint . --format stylish", + "test": "jest", + "test:watch": "jest --watch", + "version": "node ../../scripts/versionbump.js src/version.ts", + "yalc:publish": "yalc publish --push --sig" + }, + "volta": { + "extends": "../../package.json" + }, + "sideEffects": false, + "yalcSig": "eb0f51315465ec6df6c436ceddac5cbd" +} diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/utils/yalc.sig b/dev-packages/node-integration-tests/.yalc/@sentry/utils/yalc.sig new file mode 100644 index 000000000000..0bfb8a6900e4 --- /dev/null +++ b/dev-packages/node-integration-tests/.yalc/@sentry/utils/yalc.sig @@ -0,0 +1 @@ +eb0f51315465ec6df6c436ceddac5cbd \ No newline at end of file diff --git a/dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js b/dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js new file mode 100644 index 000000000000..5de286fcefb0 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js @@ -0,0 +1,100 @@ +const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +const Sentry = require('@sentry/node'); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); + +// Stop the process from exiting before the transaction is sent +setInterval(() => {}, 1000); + +const mysql = require('mysql'); +const genericPool = require('generic-pool'); + +const factory = { + create: function () { + return mysql.createConnection({ + user: 'root', + password: 'docker', + }); + }, + destroy: function (client) { + client.end(err => { + if (err) { + console.error('Error while disconnecting MySQL:', err); + } + }); + }, +}; + +const opts = { + max: 10, // maximum size of the pool + min: 2, // minimum size of the pool +}; + +const myPool = genericPool.createPool(factory, opts); + +// const connection = mysql.createConnection({ +// user: 'root', +// password: 'docker', +// }); + +// connection.connect(function (err) { +// if (err) { +// return; +// } +// }); + +// mysql 2 +// mysql +// .createConnection({ +// user: 'root', +// password: 'password', +// host: 'localhost', +// port: 3306, +// }) +// .then(connection => { +// return Sentry.startSpan( +// { +// op: 'transaction', +// name: 'Test Transaction', +// }, +// async _ => { +// await connection.query('SELECT 1 + 1 AS solution'); +// await connection.query('SELECT NOW()', ['1', '2']); +// }, +// ); +// }); + +Sentry.startSpan( + { + op: 'transaction', + name: 'Test Transaction', + }, + span => { + // connection.query('SELECT 1 + 1 AS solution', function () { + // connection.query('SELECT NOW()', ['1', '2'], () => { + // span.end(); + // connection.end(); + // }); + // }); + const resourcePromise = myPool.acquire(); + // span.end(); + + resourcePromise + .then(function (client) { + client.query('SELECT NOW()', function () { + span.end(); + // client.query('SELECT 1 + 1 AS solution'); + + myPool.release(client); + }); + }) + .catch(function (err) { + console.error('Error while pooling MySQL:', err); + }); + }, +); diff --git a/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts b/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts new file mode 100644 index 000000000000..026a36c6b8b1 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts @@ -0,0 +1,24 @@ +import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; + +describe('mysql auto instrumentation', () => { + afterAll(() => { + cleanupChildProcesses(); + }); + + test('should auto-instrument `genericPool` package when using pool.require()', done => { + const EXPECTED_TRANSACTION = { + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + // op: 'transaction', + data: expect.objectContaining({ + description: 'generic-pool.aquire', + origin: 'manual', + }), + }), + ]), + }; + + createRunner(__dirname, 'scenario.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done); + }); +}); diff --git a/dev-packages/node-integration-tests/yalc.lock b/dev-packages/node-integration-tests/yalc.lock new file mode 100644 index 000000000000..49a940cbf30a --- /dev/null +++ b/dev-packages/node-integration-tests/yalc.lock @@ -0,0 +1,24 @@ +{ + "version": "v1", + "packages": { + "@sentry/node": { + "signature": "fdee85f9c066418865de6221a8dc7314", + "file": true, + "replaced": "8.25.0" + }, + "@sentry/core": { + "signature": "b63046016939e0e6e9861c3fe8b39843", + "file": true + }, + "@sentry/types": { + "signature": "091747500ba09e4fef7b4e461001fdbf", + "file": true, + "replaced": "8.25.0" + }, + "@sentry/utils": { + "signature": "eb0f51315465ec6df6c436ceddac5cbd", + "file": true, + "replaced": "8.25.0" + } + } +} \ No newline at end of file From 43c40f8d644c3ef639f9723932f493cf18714f93 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Tue, 13 Aug 2024 10:47:41 -0400 Subject: [PATCH 24/25] feat(node): Add genericPool integration using opentelemetry instrumentation Set up initial code and include this instrumentation as a default integration. Signed-off-by: Kaung Zin Hein From 37cc42eaba012367562bc7b86a50196cb6e14ff2 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Mon, 26 Aug 2024 13:29:12 -0400 Subject: [PATCH 25/25] test(node): Add tests for genericPoolIntegration Signed-off-by: Kaung Zin Hein --- .../.yalc/@sentry/core/LICENSE | 21 --- .../.yalc/@sentry/core/README.md | 23 ---- .../.yalc/@sentry/core/package.json | 70 ---------- .../.yalc/@sentry/core/yalc.sig | 1 - .../.yalc/@sentry/node/LICENSE | 21 --- .../.yalc/@sentry/node/README.md | 77 ----------- .../.yalc/@sentry/node/package.json | 128 ------------------ .../.yalc/@sentry/node/yalc.sig | 1 - .../.yalc/@sentry/types/LICENSE | 21 --- .../.yalc/@sentry/types/README.md | 20 --- .../.yalc/@sentry/types/package.json | 63 --------- .../.yalc/@sentry/types/yalc.sig | 1 - .../.yalc/@sentry/utils/LICENSE | 21 --- .../.yalc/@sentry/utils/README.md | 23 ---- .../.yalc/@sentry/utils/package.json | 70 ---------- .../.yalc/@sentry/utils/yalc.sig | 1 - .../suites/tracing/genericPool/scenario.js | 89 ++++-------- .../suites/tracing/genericPool/test.ts | 24 +++- dev-packages/node-integration-tests/yalc.lock | 24 ---- packages/node/src/index.ts | 1 + .../src/integrations/tracing/genericPool.ts | 2 +- 21 files changed, 49 insertions(+), 653 deletions(-) delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/core/LICENSE delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/core/README.md delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/core/package.json delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/core/yalc.sig delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/node/LICENSE delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/node/README.md delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/node/package.json delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/node/yalc.sig delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/types/LICENSE delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/types/README.md delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/types/package.json delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/types/yalc.sig delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/utils/LICENSE delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/utils/README.md delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/utils/package.json delete mode 100644 dev-packages/node-integration-tests/.yalc/@sentry/utils/yalc.sig delete mode 100644 dev-packages/node-integration-tests/yalc.lock diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/core/LICENSE b/dev-packages/node-integration-tests/.yalc/@sentry/core/LICENSE deleted file mode 100644 index d5b40b7c4219..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/core/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019-2024 Functional Software, Inc. dba Sentry - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/core/README.md b/dev-packages/node-integration-tests/.yalc/@sentry/core/README.md deleted file mode 100644 index 3e44a1dfc7fa..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/core/README.md +++ /dev/null @@ -1,23 +0,0 @@ -

    - - Sentry - -

    - -# Sentry JavaScript SDK Core - -[![npm version](https://img.shields.io/npm/v/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) -[![npm dm](https://img.shields.io/npm/dm/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) -[![npm dt](https://img.shields.io/npm/dt/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core) - -## Links - -- [Official SDK Docs](https://docs.sentry.io/quickstart/) -- [TypeDoc](http://getsentry.github.io/sentry-javascript/) - -## General - -This package contains interface definitions, base classes and utilities for building Sentry JavaScript SDKs, like -`@sentry/node` or `@sentry/browser`. - -Please consider all classes and exported functions and interfaces `internal`. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/core/package.json b/dev-packages/node-integration-tests/.yalc/@sentry/core/package.json deleted file mode 100644 index 431de389caf0..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/core/package.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "name": "@sentry/core", - "version": "8.25.0+b6304601", - "description": "Base implementation for all Sentry JavaScript SDKs", - "repository": "git://github.com/getsentry/sentry-javascript.git", - "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/core", - "author": "Sentry", - "license": "MIT", - "engines": { - "node": ">=14.18" - }, - "files": [ - "/build" - ], - "main": "build/cjs/index.js", - "module": "build/esm/index.js", - "types": "build/types/index.d.ts", - "exports": { - "./package.json": "./package.json", - ".": { - "import": { - "types": "./build/types/index.d.ts", - "default": "./build/esm/index.js" - }, - "require": { - "types": "./build/types/index.d.ts", - "default": "./build/cjs/index.js" - } - } - }, - "typesVersions": { - "<4.9": { - "build/types/index.d.ts": [ - "build/types-ts3.8/index.d.ts" - ] - } - }, - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" - }, - "scripts": { - "build": "run-p build:transpile build:types", - "build:dev": "yarn build", - "build:transpile": "rollup -c rollup.npm.config.mjs", - "build:types": "run-s build:types:core build:types:downlevel", - "build:types:core": "tsc -p tsconfig.types.json", - "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8", - "build:watch": "run-p build:transpile:watch build:types:watch", - "build:dev:watch": "yarn build:watch", - "build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch", - "build:types:watch": "tsc -p tsconfig.types.json --watch", - "build:tarball": "npm pack", - "circularDepCheck": "madge --circular src/index.ts", - "clean": "rimraf build coverage sentry-core-*.tgz", - "fix": "eslint . --format stylish --fix", - "lint": "eslint . --format stylish", - "test": "jest", - "test:watch": "jest --watch", - "yalc:publish": "yalc publish --push --sig" - }, - "volta": { - "extends": "../../package.json" - }, - "sideEffects": false, - "yalcSig": "b63046016939e0e6e9861c3fe8b39843" -} diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/core/yalc.sig b/dev-packages/node-integration-tests/.yalc/@sentry/core/yalc.sig deleted file mode 100644 index 6d0256ed73bf..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/core/yalc.sig +++ /dev/null @@ -1 +0,0 @@ -b63046016939e0e6e9861c3fe8b39843 \ No newline at end of file diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/node/LICENSE b/dev-packages/node-integration-tests/.yalc/@sentry/node/LICENSE deleted file mode 100644 index 6bfafc44539c..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/node/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023-2024 Functional Software, Inc. dba Sentry - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/node/README.md b/dev-packages/node-integration-tests/.yalc/@sentry/node/README.md deleted file mode 100644 index 6471538fb4f0..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/node/README.md +++ /dev/null @@ -1,77 +0,0 @@ -

    - - Sentry - -

    - -# Official Sentry SDK for Node - -[![npm version](https://img.shields.io/npm/v/@sentry/node.svg)](https://www.npmjs.com/package/@sentry/node) -[![npm dm](https://img.shields.io/npm/dm/@sentry/node.svg)](https://www.npmjs.com/package/@sentry/node) -[![npm dt](https://img.shields.io/npm/dt/@sentry/node.svg)](https://www.npmjs.com/package/@sentry/node) - -## Installation - -```bash -npm install @sentry/node - -# Or yarn -yarn add @sentry/node -``` - -## Usage - -Sentry should be initialized as early in your app as possible. It is essential that you call `Sentry.init` before you -require any other modules in your application, otherwise auto-instrumentation of these modules will **not** work. - -You need to create a file named `instrument.js` that imports and initializes Sentry: - -```js -// CJS Syntax -const Sentry = require('@sentry/node'); -// ESM Syntax -import * as Sentry from '@sentry/node'; - -Sentry.init({ - dsn: '__DSN__', - // ... -}); -``` - -You need to require or import the `instrument.js` file before importing any other modules in your application. This is -necessary to ensure that Sentry can automatically instrument all modules in your application: - -```js -// Import this first! -import './instrument'; - -// Now import other modules -import http from 'http'; - -// Your application code goes here -``` - -### ESM Support - -When running your application in ESM mode, you should use the Node.js -[`--import`](https://nodejs.org/api/cli.html#--importmodule) command line option to ensure that Sentry is loaded before -the application code is evaluated. - -Adjust the Node.js call for your application to use the `--import` parameter and point it at `instrument.js`, which -contains your `Sentry.init`() code: - -```bash -# Note: This is only available for Node v18.19.0 onwards. -node --import ./instrument.mjs app.mjs -``` - -If it is not possible for you to pass the `--import` flag to the Node.js binary, you can alternatively use the -`NODE_OPTIONS` environment variable as follows: - -```bash -NODE_OPTIONS="--import ./instrument.mjs" npm run start -``` - -## Links - -- [Official SDK Docs](https://docs.sentry.io/quickstart/) diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/node/package.json b/dev-packages/node-integration-tests/.yalc/@sentry/node/package.json deleted file mode 100644 index 43473a72ed2d..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/node/package.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "name": "@sentry/node", - "version": "8.25.0+fdee85f9", - "description": "Sentry Node SDK using OpenTelemetry for performance instrumentation", - "repository": "git://github.com/getsentry/sentry-javascript.git", - "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/node", - "author": "Sentry", - "license": "MIT", - "engines": { - "node": ">=14.18" - }, - "files": [ - "/build" - ], - "main": "build/cjs/index.js", - "module": "build/esm/index.js", - "types": "build/types/index.d.ts", - "exports": { - "./package.json": "./package.json", - ".": { - "import": { - "types": "./build/types/index.d.ts", - "default": "./build/esm/index.js" - }, - "require": { - "types": "./build/types/index.d.ts", - "default": "./build/cjs/index.js" - } - }, - "./import": { - "import": { - "default": "./build/import-hook.mjs" - } - }, - "./loader": { - "import": { - "default": "./build/loader-hook.mjs" - } - }, - "./init": { - "import": { - "default": "./build/esm/init.js" - }, - "require": { - "default": "./build/cjs/init.js" - } - }, - "./preload": { - "import": { - "default": "./build/esm/preload.js" - }, - "require": { - "default": "./build/cjs/preload.js" - } - } - }, - "typesVersions": { - "<4.9": { - "build/types/index.d.ts": [ - "build/types-ts3.8/index.d.ts" - ] - } - }, - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^1.25.1", - "@opentelemetry/core": "^1.25.1", - "@opentelemetry/instrumentation": "^0.52.1", - "@opentelemetry/instrumentation-connect": "0.38.0", - "@opentelemetry/instrumentation-express": "0.41.1", - "@opentelemetry/instrumentation-fastify": "0.38.0", - "@opentelemetry/instrumentation-fs": "0.14.0", - "@opentelemetry/instrumentation-generic-pool": "^0.38.0", - "@opentelemetry/instrumentation-graphql": "0.42.0", - "@opentelemetry/instrumentation-hapi": "0.40.0", - "@opentelemetry/instrumentation-http": "0.52.1", - "@opentelemetry/instrumentation-ioredis": "0.42.0", - "@opentelemetry/instrumentation-koa": "0.42.0", - "@opentelemetry/instrumentation-mongodb": "0.46.0", - "@opentelemetry/instrumentation-mongoose": "0.40.0", - "@opentelemetry/instrumentation-mysql": "0.40.0", - "@opentelemetry/instrumentation-mysql2": "0.40.0", - "@opentelemetry/instrumentation-nestjs-core": "0.39.0", - "@opentelemetry/instrumentation-pg": "0.43.0", - "@opentelemetry/instrumentation-redis-4": "0.41.0", - "@opentelemetry/resources": "^1.25.1", - "@opentelemetry/sdk-trace-base": "^1.25.1", - "@opentelemetry/semantic-conventions": "^1.25.1", - "@prisma/instrumentation": "5.17.0", - "@sentry/core": "8.25.0", - "@sentry/opentelemetry": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", - "import-in-the-middle": "^1.11.0" - }, - "optionalDependencies": { - "opentelemetry-instrumentation-fetch-node": "1.2.3" - }, - "scripts": { - "build": "run-p build:transpile build:types", - "build:dev": "yarn build", - "build:transpile": "rollup -c rollup.npm.config.mjs", - "build:types": "run-s build:types:core build:types:downlevel", - "build:types:core": "tsc -p tsconfig.types.json", - "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8", - "build:watch": "run-p build:transpile:watch build:types:watch", - "build:dev:watch": "yarn build:watch", - "build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch", - "build:types:watch": "tsc -p tsconfig.types.json --watch", - "build:tarball": "npm pack", - "circularDepCheck": "madge --circular src/index.ts", - "clean": "rimraf build coverage sentry-node-*.tgz", - "fix": "eslint . --format stylish --fix", - "lint": "eslint . --format stylish", - "test": "yarn test:jest", - "test:jest": "jest", - "test:watch": "jest --watch", - "yalc:publish": "yalc publish --push --sig" - }, - "volta": { - "extends": "../../package.json" - }, - "sideEffects": false, - "yalcSig": "fdee85f9c066418865de6221a8dc7314" -} diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/node/yalc.sig b/dev-packages/node-integration-tests/.yalc/@sentry/node/yalc.sig deleted file mode 100644 index f4e4ec128ba9..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/node/yalc.sig +++ /dev/null @@ -1 +0,0 @@ -fdee85f9c066418865de6221a8dc7314 \ No newline at end of file diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/types/LICENSE b/dev-packages/node-integration-tests/.yalc/@sentry/types/LICENSE deleted file mode 100644 index d5b40b7c4219..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/types/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019-2024 Functional Software, Inc. dba Sentry - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/types/README.md b/dev-packages/node-integration-tests/.yalc/@sentry/types/README.md deleted file mode 100644 index 4c0e2d9cbc34..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/types/README.md +++ /dev/null @@ -1,20 +0,0 @@ -

    - - Sentry - -

    - -# Sentry JavaScript SDK Types - -[![npm version](https://img.shields.io/npm/v/@sentry/types.svg)](https://www.npmjs.com/package/@sentry/types) -[![npm dm](https://img.shields.io/npm/dm/@sentry/types.svg)](https://www.npmjs.com/package/@sentry/types) -[![npm dt](https://img.shields.io/npm/dt/@sentry/types.svg)](https://www.npmjs.com/package/@sentry/types) - -## Links - -- [Official SDK Docs](https://docs.sentry.io/quickstart/) -- [TypeDoc](http://getsentry.github.io/sentry-javascript/) - -## General - -Common types used by the Sentry JavaScript SDKs. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/types/package.json b/dev-packages/node-integration-tests/.yalc/@sentry/types/package.json deleted file mode 100644 index b97ec606c395..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/types/package.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "@sentry/types", - "version": "8.25.0+09174750", - "description": "Types for all Sentry JavaScript SDKs", - "repository": "git://github.com/getsentry/sentry-javascript.git", - "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/types", - "author": "Sentry", - "license": "MIT", - "engines": { - "node": ">=14.18" - }, - "files": [ - "/build" - ], - "main": "build/cjs/index.js", - "module": "build/esm/index.js", - "types": "build/types/index.d.ts", - "exports": { - "./package.json": "./package.json", - ".": { - "import": { - "types": "./build/types/index.d.ts", - "default": "./build/esm/index.js" - }, - "require": { - "types": "./build/types/index.d.ts", - "default": "./build/cjs/index.js" - } - } - }, - "typesVersions": { - "<4.9": { - "build/types/index.d.ts": [ - "build/types-ts3.8/index.d.ts" - ] - } - }, - "publishConfig": { - "access": "public" - }, - "scripts": { - "build": "run-p build:transpile build:types", - "build:dev": "yarn build", - "build:transpile": "rollup -c rollup.npm.config.mjs", - "build:types": "run-s build:types:core build:types:downlevel", - "build:types:core": "tsc -p tsconfig.types.json", - "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8", - "build:watch": "run-p build:transpile:watch build:types:watch", - "build:dev:watch": "yarn build:watch", - "build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch", - "build:types:watch": "tsc -p tsconfig.types.json --watch", - "build:tarball": "npm pack", - "clean": "rimraf build sentry-types-*.tgz", - "lint": "eslint . --format stylish", - "fix": "eslint . --format stylish --fix", - "yalc:publish": "yalc publish --push --sig" - }, - "volta": { - "extends": "../../package.json" - }, - "sideEffects": false, - "yalcSig": "091747500ba09e4fef7b4e461001fdbf" -} diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/types/yalc.sig b/dev-packages/node-integration-tests/.yalc/@sentry/types/yalc.sig deleted file mode 100644 index 46fbf9051f5c..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/types/yalc.sig +++ /dev/null @@ -1 +0,0 @@ -091747500ba09e4fef7b4e461001fdbf \ No newline at end of file diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/utils/LICENSE b/dev-packages/node-integration-tests/.yalc/@sentry/utils/LICENSE deleted file mode 100644 index d5b40b7c4219..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/utils/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019-2024 Functional Software, Inc. dba Sentry - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/utils/README.md b/dev-packages/node-integration-tests/.yalc/@sentry/utils/README.md deleted file mode 100644 index 812bb86a3525..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/utils/README.md +++ /dev/null @@ -1,23 +0,0 @@ -

    - - Sentry - -

    - -# Sentry JavaScript SDK Utilities - -[![npm version](https://img.shields.io/npm/v/@sentry/utils.svg)](https://www.npmjs.com/package/@sentry/utils) -[![npm dm](https://img.shields.io/npm/dm/@sentry/utils.svg)](https://www.npmjs.com/package/@sentry/utils) -[![npm dt](https://img.shields.io/npm/dt/@sentry/utils.svg)](https://www.npmjs.com/package/@sentry/utils) - -## Links - -- [Official SDK Docs](https://docs.sentry.io/quickstart/) -- [TypeDoc](http://getsentry.github.io/sentry-javascript/) - -## General - -Common utilities used by the Sentry JavaScript SDKs. - -Note: This package is only meant to be used internally, and as such is not part of our public API contract and does not -follow semver. diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/utils/package.json b/dev-packages/node-integration-tests/.yalc/@sentry/utils/package.json deleted file mode 100644 index ec5720de4c0c..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/utils/package.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "name": "@sentry/utils", - "version": "8.25.0+eb0f5131", - "description": "Utilities for all Sentry JavaScript SDKs", - "repository": "git://github.com/getsentry/sentry-javascript.git", - "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/utils", - "author": "Sentry", - "license": "MIT", - "engines": { - "node": ">=14.18" - }, - "files": [ - "/build" - ], - "main": "build/cjs/index.js", - "module": "build/esm/index.js", - "types": "build/types/index.d.ts", - "exports": { - "./package.json": "./package.json", - ".": { - "import": { - "types": "./build/types/index.d.ts", - "default": "./build/esm/index.js" - }, - "require": { - "types": "./build/types/index.d.ts", - "default": "./build/cjs/index.js" - } - } - }, - "typesVersions": { - "<4.9": { - "build/types/index.d.ts": [ - "build/types-ts3.8/index.d.ts" - ] - } - }, - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@sentry/types": "8.25.0" - }, - "scripts": { - "build": "run-p build:transpile build:types", - "build:dev": "yarn build", - "build:transpile": "yarn ts-node scripts/buildRollup.ts", - "build:types": "run-s build:types:core build:types:downlevel", - "build:types:core": "tsc -p tsconfig.types.json", - "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8", - "build:watch": "run-p build:transpile:watch build:types:watch", - "build:dev:watch": "yarn build:watch", - "build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch", - "build:types:watch": "tsc -p tsconfig.types.json --watch", - "build:tarball": "npm pack", - "circularDepCheck": "madge --circular src/index.ts", - "clean": "rimraf build coverage cjs esm sentry-utils-*.tgz", - "fix": "eslint . --format stylish --fix", - "lint": "eslint . --format stylish", - "test": "jest", - "test:watch": "jest --watch", - "version": "node ../../scripts/versionbump.js src/version.ts", - "yalc:publish": "yalc publish --push --sig" - }, - "volta": { - "extends": "../../package.json" - }, - "sideEffects": false, - "yalcSig": "eb0f51315465ec6df6c436ceddac5cbd" -} diff --git a/dev-packages/node-integration-tests/.yalc/@sentry/utils/yalc.sig b/dev-packages/node-integration-tests/.yalc/@sentry/utils/yalc.sig deleted file mode 100644 index 0bfb8a6900e4..000000000000 --- a/dev-packages/node-integration-tests/.yalc/@sentry/utils/yalc.sig +++ /dev/null @@ -1 +0,0 @@ -eb0f51315465ec6df6c436ceddac5cbd \ No newline at end of file diff --git a/dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js b/dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js index 5de286fcefb0..74d5f73693f5 100644 --- a/dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/genericPool/scenario.js @@ -24,6 +24,7 @@ const factory = { destroy: function (client) { client.end(err => { if (err) { + // eslint-disable-next-line no-console console.error('Error while disconnecting MySQL:', err); } }); @@ -31,70 +32,40 @@ const factory = { }; const opts = { - max: 10, // maximum size of the pool - min: 2, // minimum size of the pool + max: 10, + min: 2, }; const myPool = genericPool.createPool(factory, opts); -// const connection = mysql.createConnection({ -// user: 'root', -// password: 'docker', -// }); +async function run() { + await Sentry.startSpan( + { + op: 'transaction', + name: 'Test Transaction', + }, + async () => { + try { + const client1 = await myPool.acquire(); + const client2 = await myPool.acquire(); -// connection.connect(function (err) { -// if (err) { -// return; -// } -// }); - -// mysql 2 -// mysql -// .createConnection({ -// user: 'root', -// password: 'password', -// host: 'localhost', -// port: 3306, -// }) -// .then(connection => { -// return Sentry.startSpan( -// { -// op: 'transaction', -// name: 'Test Transaction', -// }, -// async _ => { -// await connection.query('SELECT 1 + 1 AS solution'); -// await connection.query('SELECT NOW()', ['1', '2']); -// }, -// ); -// }); - -Sentry.startSpan( - { - op: 'transaction', - name: 'Test Transaction', - }, - span => { - // connection.query('SELECT 1 + 1 AS solution', function () { - // connection.query('SELECT NOW()', ['1', '2'], () => { - // span.end(); - // connection.end(); - // }); - // }); - const resourcePromise = myPool.acquire(); - // span.end(); - - resourcePromise - .then(function (client) { - client.query('SELECT NOW()', function () { - span.end(); - // client.query('SELECT 1 + 1 AS solution'); + client1.query('SELECT NOW()', function () { + myPool.release(client1); + }); - myPool.release(client); + client2.query('SELECT 1 + 1 AS solution', function () { + myPool.release(client2); }); - }) - .catch(function (err) { + } catch (err) { + // eslint-disable-next-line no-console console.error('Error while pooling MySQL:', err); - }); - }, -); + } finally { + await myPool.drain(); + await myPool.clear(); + } + }, + ); +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts b/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts index 026a36c6b8b1..129e142f2808 100644 --- a/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/genericPool/test.ts @@ -1,20 +1,30 @@ import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; -describe('mysql auto instrumentation', () => { +describe('genericPool auto instrumentation', () => { afterAll(() => { cleanupChildProcesses(); }); - test('should auto-instrument `genericPool` package when using pool.require()', done => { + test('should auto-instrument `genericPool` package when calling pool.require()', done => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction', spans: expect.arrayContaining([ expect.objectContaining({ - // op: 'transaction', - data: expect.objectContaining({ - description: 'generic-pool.aquire', - origin: 'manual', - }), + description: 'generic-pool.aquire', + origin: 'auto.db.otel.generic-pool', + data: { + 'sentry.origin': 'auto.db.otel.generic-pool', + }, + status: 'ok', + }), + + expect.objectContaining({ + description: 'generic-pool.aquire', + origin: 'auto.db.otel.generic-pool', + data: { + 'sentry.origin': 'auto.db.otel.generic-pool', + }, + status: 'ok', }), ]), }; diff --git a/dev-packages/node-integration-tests/yalc.lock b/dev-packages/node-integration-tests/yalc.lock deleted file mode 100644 index 49a940cbf30a..000000000000 --- a/dev-packages/node-integration-tests/yalc.lock +++ /dev/null @@ -1,24 +0,0 @@ -{ - "version": "v1", - "packages": { - "@sentry/node": { - "signature": "fdee85f9c066418865de6221a8dc7314", - "file": true, - "replaced": "8.25.0" - }, - "@sentry/core": { - "signature": "b63046016939e0e6e9861c3fe8b39843", - "file": true - }, - "@sentry/types": { - "signature": "091747500ba09e4fef7b4e461001fdbf", - "file": true, - "replaced": "8.25.0" - }, - "@sentry/utils": { - "signature": "eb0f51315465ec6df6c436ceddac5cbd", - "file": true, - "replaced": "8.25.0" - } - } -} \ No newline at end of file diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 9ef89ab42fb7..c079a9535342 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -26,6 +26,7 @@ export { hapiIntegration, setupHapiErrorHandler } from './integrations/tracing/h export { koaIntegration, setupKoaErrorHandler } from './integrations/tracing/koa'; export { connectIntegration, setupConnectErrorHandler } from './integrations/tracing/connect'; export { spotlightIntegration } from './integrations/spotlight'; +export { genericPoolIntegration } from './integrations/tracing/genericPool'; export { SentryContextManager } from './otel/contextManager'; export { generateInstrumentOnce } from './otel/instrument'; diff --git a/packages/node/src/integrations/tracing/genericPool.ts b/packages/node/src/integrations/tracing/genericPool.ts index 1c7725f95e45..4cda8bd9479d 100644 --- a/packages/node/src/integrations/tracing/genericPool.ts +++ b/packages/node/src/integrations/tracing/genericPool.ts @@ -17,7 +17,7 @@ const _genericPoolIntegration = (() => { setup(client) { client.on('spanStart', span => { const spanJSON = spanToJSON(span); - if (spanJSON.description === 'generic-pool.acquire') { + if (spanJSON.description === 'generic-pool.aquire') { span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.generic-pool'); } });