diff --git a/dev-packages/e2e-tests/test-applications/node-koa-app/index.js b/dev-packages/e2e-tests/test-applications/node-koa-app/index.js index 3ee16ab7200e..9d58bd6ca3b6 100644 --- a/dev-packages/e2e-tests/test-applications/node-koa-app/index.js +++ b/dev-packages/e2e-tests/test-applications/node-koa-app/index.js @@ -75,6 +75,10 @@ router1.get('/test-exception', async ctx => { throw new Error('This is an exception'); }); +router1.get('/test-exception/:id', async ctx => { + throw new Error(`This is an exception with id ${ctx.params.id}`); +}); + router1.get('/test-outgoing-fetch-external-allowed', async ctx => { const fetchResponse = await fetch(`http://localhost:${port2}/external-allowed`); const data = await fetchResponse.json(); diff --git a/dev-packages/e2e-tests/test-applications/node-koa-app/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/node-koa-app/tests/errors.test.ts index 1d6cf604f176..5759c2bad543 100644 --- a/dev-packages/e2e-tests/test-applications/node-koa-app/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-koa-app/tests/errors.test.ts @@ -41,11 +41,11 @@ test('Sends exception to Sentry', async ({ baseURL }) => { test('Sends correct error event', async ({ baseURL }) => { const errorEventPromise = waitForError('node-koa-app', event => { - return !event.type && event.exception?.values?.[0]?.value === 'This is an exception'; + return !event.type && event.exception?.values?.[0]?.value === 'This is an exception with id 123'; }); try { - await axios.get(`${baseURL}/test-exception`); + await axios.get(`${baseURL}/test-exception/123`); } catch { // this results in an error, but we don't care - we want to check the error event } @@ -53,16 +53,16 @@ test('Sends correct error event', async ({ baseURL }) => { const errorEvent = await errorEventPromise; expect(errorEvent.exception?.values).toHaveLength(1); - expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an exception'); + expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an exception with id 123'); expect(errorEvent.request).toEqual({ method: 'GET', cookies: {}, headers: expect.any(Object), - url: 'http://localhost:3030/test-exception', + url: 'http://localhost:3030/test-exception/123', }); - expect(errorEvent.transaction).toEqual('GET /test-exception'); + expect(errorEvent.transaction).toEqual('GET /test-exception/:id'); expect(errorEvent.contexts?.trace).toEqual({ trace_id: expect.any(String), diff --git a/packages/node/src/integrations/tracing/koa.ts b/packages/node/src/integrations/tracing/koa.ts index 2c3a57ebed3f..938e815e2b2f 100644 --- a/packages/node/src/integrations/tracing/koa.ts +++ b/packages/node/src/integrations/tracing/koa.ts @@ -1,14 +1,39 @@ import { registerInstrumentations } from '@opentelemetry/instrumentation'; import { KoaInstrumentation } from '@opentelemetry/instrumentation-koa'; -import { captureException, defineIntegration } from '@sentry/core'; +import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; +import { + captureException, + defineIntegration, + getDefaultIsolationScope, + getIsolationScope, + spanToJSON, +} from '@sentry/core'; import type { IntegrationFn } from '@sentry/types'; +import { logger } from '@sentry/utils'; +import { DEBUG_BUILD } from '../../debug-build'; const _koaIntegration = (() => { return { name: 'Koa', setupOnce() { registerInstrumentations({ - instrumentations: [new KoaInstrumentation()], + instrumentations: [ + new KoaInstrumentation({ + requestHook(span, info) { + if (getIsolationScope() === getDefaultIsolationScope()) { + DEBUG_BUILD && + logger.warn('Isolation scope is default isolation scope - skipping setting transactionName'); + return; + } + const attributes = spanToJSON(span).data; + const route = attributes && attributes[SemanticAttributes.HTTP_ROUTE]; + const method = info.context.request.method.toUpperCase() || 'GET'; + if (route) { + getIsolationScope().setTransactionName(`${method} ${route}`); + } + }, + }), + ], }); }, };