From 8cea515909943ca8096a4b401248ac8570c11bce Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 10 Sep 2026 15:17:33 +0200 Subject: [PATCH 1/2] feat(nestjs): Add `code.function.name` attribute to `function` spans for description inference --- .../nestjs-11-static/tests/span-decorator.test.ts | 2 ++ packages/nestjs/src/decorators.ts | 2 ++ packages/nestjs/src/integrations/wrap-route.ts | 9 ++++++++- packages/nestjs/test/decorators.test.ts | 4 ++++ .../test/integrations/orchestrion-subscriber.test.ts | 1 + 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/dev-packages/e2e-tests/test-applications/nestjs-11-static/tests/span-decorator.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-11-static/tests/span-decorator.test.ts index 9fcf9b4c6216..c4b646b7abc3 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-11-static/tests/span-decorator.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-11-static/tests/span-decorator.test.ts @@ -24,6 +24,7 @@ test('Transaction includes span and correct value for decorated async function', data: { 'sentry.origin': 'auto.function.nestjs.sentry_traced', 'sentry.op': 'wait and return a string', + 'code.function.name': 'wait', }, description: 'wait', parent_span_id: expect.stringMatching(/[a-f0-9]{16}/), @@ -59,6 +60,7 @@ test('Transaction includes span and correct value for decorated sync function', data: { 'sentry.origin': 'auto.function.nestjs.sentry_traced', 'sentry.op': 'return a string', + 'code.function.name': 'getString', }, description: 'getString', parent_span_id: expect.stringMatching(/[a-f0-9]{16}/), diff --git a/packages/nestjs/src/decorators.ts b/packages/nestjs/src/decorators.ts index f50c3c9bcc68..e4690c988d7a 100644 --- a/packages/nestjs/src/decorators.ts +++ b/packages/nestjs/src/decorators.ts @@ -1,4 +1,5 @@ import type { MonitorConfig } from '@sentry/core'; +import { CODE_FUNCTION_NAME } from '@sentry/conventions/attributes'; import { captureException, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; import * as Sentry from '@sentry/node'; import { startSpan } from '@sentry/node'; @@ -43,6 +44,7 @@ export function SentryTraced(op: string = 'function') { attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nestjs.sentry_traced', [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op, + [CODE_FUNCTION_NAME]: propertyKey, }, }, () => { diff --git a/packages/nestjs/src/integrations/wrap-route.ts b/packages/nestjs/src/integrations/wrap-route.ts index 10971ab25441..c65b6e2b69ce 100644 --- a/packages/nestjs/src/integrations/wrap-route.ts +++ b/packages/nestjs/src/integrations/wrap-route.ts @@ -1,4 +1,10 @@ -import { HTTP_REQUEST_METHOD, HTTP_ROUTE, SENTRY_OP, URL_FULL } from '@sentry/conventions/attributes'; +import { + CODE_FUNCTION_NAME, + HTTP_REQUEST_METHOD, + HTTP_ROUTE, + SENTRY_OP, + URL_FULL, +} from '@sentry/conventions/attributes'; import { FUNCTION, HANDLER } from '@sentry/conventions/op'; import type { SpanAttributes } from '@sentry/core'; import { @@ -107,6 +113,7 @@ export function wrapRequestContextHandler( component: NESTJS_COMPONENT, [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: HTTP_ORIGIN, [SENTRY_OP]: FUNCTION, + [CODE_FUNCTION_NAME]: spanName, [AttributeNames.TYPE]: NestType.REQUEST_CONTEXT, [AttributeNames.CONTROLLER]: instanceName, [AttributeNames.CALLBACK]: callbackName, diff --git a/packages/nestjs/test/decorators.test.ts b/packages/nestjs/test/decorators.test.ts index b5d17451a9f2..9640244de437 100644 --- a/packages/nestjs/test/decorators.test.ts +++ b/packages/nestjs/test/decorators.test.ts @@ -1,4 +1,5 @@ import 'reflect-metadata'; +import { CODE_FUNCTION_NAME } from '@sentry/conventions/attributes'; import * as core from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; import { beforeEach, describe, expect, it, vi } from 'vitest'; @@ -42,6 +43,7 @@ describe('SentryTraced decorator', () => { attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nestjs.sentry_traced', [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'test-operation', + [CODE_FUNCTION_NAME]: 'testMethod', }, }, expect.any(Function), @@ -75,6 +77,7 @@ describe('SentryTraced decorator', () => { attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nestjs.sentry_traced', [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function', + [CODE_FUNCTION_NAME]: 'testDefaultOp', }, }, expect.any(Function), @@ -108,6 +111,7 @@ describe('SentryTraced decorator', () => { attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nestjs.sentry_traced', [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'sync-operation', + [CODE_FUNCTION_NAME]: 'syncMethod', }, }, expect.any(Function), diff --git a/packages/nestjs/test/integrations/orchestrion-subscriber.test.ts b/packages/nestjs/test/integrations/orchestrion-subscriber.test.ts index 0a75619770ad..5b7d79fb53a8 100644 --- a/packages/nestjs/test/integrations/orchestrion-subscriber.test.ts +++ b/packages/nestjs/test/integrations/orchestrion-subscriber.test.ts @@ -237,6 +237,7 @@ describe('NestJS orchestrion subscriber: request_context / request_handler', () expect(contextSpanJson!.attributes['sentry.origin']).toBe('auto.http.nestjs'); expect(contextSpanJson!.attributes).toMatchObject({ component: '@nestjs/core', + 'code.function.name': 'CatsController.getCats', 'nestjs.type': 'request_context', 'nestjs.controller': 'CatsController', 'nestjs.callback': 'getCats', From c022bd86cfc08a1590c42d1cb6ac8a946dbb2853 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 10 Sep 2026 15:28:49 +0200 Subject: [PATCH 2/2] fix tests --- .../test-applications/nestjs-11/tests/span-decorator.test.ts | 2 ++ .../test-applications/nestjs-12/tests/span-decorator.test.ts | 1 + .../test-applications/nestjs-8/tests/span-decorator.test.ts | 2 ++ .../test-applications/nestjs-basic/tests/span-decorator.test.ts | 1 + .../nestjs-fastify/tests/span-decorator.test.ts | 2 ++ .../test-applications/nestjs-fastify/tests/transactions.test.ts | 2 ++ 6 files changed, 10 insertions(+) diff --git a/dev-packages/e2e-tests/test-applications/nestjs-11/tests/span-decorator.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-11/tests/span-decorator.test.ts index 1fca6f35dcd2..73d76e08e7c7 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-11/tests/span-decorator.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-11/tests/span-decorator.test.ts @@ -21,6 +21,7 @@ test('Trace includes span and correct value for decorated async function', async attributes: expect.objectContaining({ 'sentry.origin': { type: 'string', value: 'auto.function.nestjs.sentry_traced' }, 'sentry.op': { type: 'string', value: 'wait and return a string' }, + 'code.function.name': { type: 'string', value: 'wait' }, }), }), ); @@ -44,6 +45,7 @@ test('Trace includes span and correct value for decorated sync function', async attributes: expect.objectContaining({ 'sentry.origin': { type: 'string', value: 'auto.function.nestjs.sentry_traced' }, 'sentry.op': { type: 'string', value: 'return a string' }, + 'code.function.name': { type: 'string', value: 'getString' }, }), }), ); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-12/tests/span-decorator.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-12/tests/span-decorator.test.ts index 7a15277dce3a..576e75864ac4 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-12/tests/span-decorator.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-12/tests/span-decorator.test.ts @@ -31,6 +31,7 @@ function tracedSpan(segmentSpan: SerializedStreamedSpan, name: string, op: strin : {}), 'sentry.origin': { type: 'string', value: 'auto.function.nestjs.sentry_traced' }, 'sentry.op': { type: 'string', value: op }, + 'code.function.name': { type: 'string', value: name }, }, }; } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-8/tests/span-decorator.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-8/tests/span-decorator.test.ts index f83819502854..4df3a399a754 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-8/tests/span-decorator.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-8/tests/span-decorator.test.ts @@ -21,6 +21,7 @@ test('Trace includes span and correct value for decorated async function', async attributes: expect.objectContaining({ 'sentry.origin': { type: 'string', value: 'auto.function.nestjs.sentry_traced' }, 'sentry.op': { type: 'string', value: 'wait and return a string' }, + 'code.function.name': { type: 'string', value: 'wait' }, }), }), ); @@ -44,6 +45,7 @@ test('Trace includes span and correct value for decorated sync function', async attributes: expect.objectContaining({ 'sentry.origin': { type: 'string', value: 'auto.function.nestjs.sentry_traced' }, 'sentry.op': { type: 'string', value: 'return a string' }, + 'code.function.name': { type: 'string', value: 'getString' }, }), }), ); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/span-decorator.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/span-decorator.test.ts index b79dde1bc23b..1e47226e92f2 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/span-decorator.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/span-decorator.test.ts @@ -31,6 +31,7 @@ function tracedSpan(segmentSpan: SerializedStreamedSpan, name: string, op: strin : {}), 'sentry.origin': { type: 'string', value: 'auto.function.nestjs.sentry_traced' }, 'sentry.op': { type: 'string', value: op }, + 'code.function.name': { type: 'string', value: name }, }, }; } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/span-decorator.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/span-decorator.test.ts index 5730bed459c9..5a37aa4c1039 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/span-decorator.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/span-decorator.test.ts @@ -21,6 +21,7 @@ test('Trace includes span and correct value for decorated async function', async attributes: expect.objectContaining({ 'sentry.origin': { type: 'string', value: 'auto.function.nestjs.sentry_traced' }, 'sentry.op': { type: 'string', value: 'wait and return a string' }, + 'code.function.name': { type: 'string', value: 'wait' }, }), }), ); @@ -44,6 +45,7 @@ test('Trace includes span and correct value for decorated sync function', async attributes: expect.objectContaining({ 'sentry.origin': { type: 'string', value: 'auto.function.nestjs.sentry_traced' }, 'sentry.op': { type: 'string', value: 'return a string' }, + 'code.function.name': { type: 'string', value: 'getString' }, }), }), ); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/transactions.test.ts index 5986b8d2f66e..554d99558bc9 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/transactions.test.ts @@ -91,6 +91,7 @@ test('Sends streamed spans for an API route', async ({ baseURL }) => { 'sentry.origin': { type: 'string', value: 'auto.http.nestjs' }, component: { type: 'string', value: '@nestjs/core' }, 'nestjs.type': { type: 'string', value: 'request_context' }, + 'code.function.name': { type: 'string', value: 'AppController.testTransaction' }, 'nestjs.controller': { type: 'string', value: 'AppController' }, 'nestjs.callback': { type: 'string', value: 'testTransaction' }, 'http.route': { type: 'string', value: '/test-transaction' }, @@ -429,6 +430,7 @@ test('Sets error status on nest spans when a handler throws', async ({ baseURL } 'sentry.op': { type: 'string', value: 'function' }, 'sentry.status.message': { type: 'string', value: 'internal_error' }, 'nestjs.type': { type: 'string', value: 'request_context' }, + 'code.function.name': { type: 'string', value: 'AppController.testException' }, }), });