Skip to content

Commit 41f8840

Browse files
nicohrubecclaude
andauthored
ref(nestjs): Set nest span op/origin at span creation (#21531)
Now that we have vendored the nestjs instrumentation we can set these attributes directly in the instrumentation instead of registering a `client.startSpan` hook. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 1f55918 commit 41f8840

2 files changed

Lines changed: 14 additions & 35 deletions

File tree

packages/nestjs/src/integrations/vendored/instrumentation.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
} from '@opentelemetry/instrumentation';
2828
import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';
2929
import type { SpanAttributes } from '@sentry/core';
30-
import { SDK_VERSION, startSpan } from '@sentry/core';
30+
import { SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';
3131
import { AttributeNames, NestType } from './enums';
3232

3333
const PACKAGE_NAME = '@sentry/instrumentation-nestjs-core';
@@ -137,8 +137,10 @@ function createWrapNestFactoryCreate(moduleVersion?: string) {
137137
return startSpan(
138138
{
139139
name: 'Create Nest App',
140+
op: `${NestType.APP_CREATION}.nestjs`,
140141
attributes: {
141142
...NestInstrumentation.COMMON_ATTRIBUTES,
143+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.nestjs',
142144
[AttributeNames.TYPE]: NestType.APP_CREATION,
143145
[AttributeNames.VERSION]: moduleVersion,
144146
[AttributeNames.MODULE]: nestModule.name,
@@ -165,6 +167,7 @@ function createWrapCreateHandler(moduleVersion: string | undefined) {
165167
const req = handlerArgs[0] as NestRequest;
166168
const attributes: SpanAttributes = {
167169
...NestInstrumentation.COMMON_ATTRIBUTES,
170+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.nestjs',
168171
[AttributeNames.VERSION]: moduleVersion,
169172
[AttributeNames.TYPE]: NestType.REQUEST_CONTEXT,
170173
[ATTR_HTTP_ROUTE]: req.route?.path || req.routeOptions?.url || req.routerPath,
@@ -173,7 +176,9 @@ function createWrapCreateHandler(moduleVersion: string | undefined) {
173176
};
174177
attributes['http.method'] = req.method;
175178
attributes['http.url'] = req.originalUrl || req.url;
176-
return startSpan({ name: spanName, attributes }, () => handler.apply(this, handlerArgs));
179+
return startSpan({ name: spanName, op: `${NestType.REQUEST_CONTEXT}.nestjs`, attributes }, () =>
180+
handler.apply(this, handlerArgs),
181+
);
177182
};
178183
};
179184
};
@@ -183,12 +188,15 @@ function createWrapHandler(moduleVersion: string | undefined, handler: AnyFn): A
183188
const spanName = handler.name || 'anonymous nest handler';
184189
const attributes: SpanAttributes = {
185190
...NestInstrumentation.COMMON_ATTRIBUTES,
191+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.nestjs',
186192
[AttributeNames.VERSION]: moduleVersion,
187193
[AttributeNames.TYPE]: NestType.REQUEST_HANDLER,
188194
[AttributeNames.CALLBACK]: handler.name,
189195
};
190196
const wrappedHandler = function (this: unknown, ...args: unknown[]) {
191-
return startSpan({ name: spanName, attributes }, () => handler.apply(this, args));
197+
return startSpan({ name: spanName, op: `${NestType.REQUEST_HANDLER}.nestjs`, attributes }, () =>
198+
handler.apply(this, args),
199+
);
192200
};
193201

194202
if (handler.name) {

packages/nestjs/src/sdk.ts

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import type { Integration } from '@sentry/core';
2-
import {
3-
applySdkMetadata,
4-
SEMANTIC_ATTRIBUTE_SENTRY_OP,
5-
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
6-
spanToJSON,
7-
} from '@sentry/core';
8-
import type { NodeClient, NodeOptions, Span } from '@sentry/node';
2+
import { applySdkMetadata } from '@sentry/core';
3+
import type { NodeClient, NodeOptions } from '@sentry/node';
94
import { getDefaultIntegrations as getDefaultNodeIntegrations, init as nodeInit } from '@sentry/node';
105
import { nestIntegration } from './integrations/nest';
116

@@ -20,34 +15,10 @@ export function init(options: NodeOptions | undefined = {}): NodeClient | undefi
2015

2116
applySdkMetadata(opts, 'nestjs', ['nestjs', 'node']);
2217

23-
const client = nodeInit(opts);
24-
25-
if (client) {
26-
client.on('spanStart', span => {
27-
// The NestInstrumentation has no requestHook, so we add NestJS-specific attributes here
28-
addNestSpanAttributes(span);
29-
});
30-
}
31-
32-
return client;
18+
return nodeInit(opts);
3319
}
3420

3521
/** Get the default integrations for the NestJS SDK. */
3622
export function getDefaultIntegrations(options: NodeOptions): Integration[] | undefined {
3723
return [nestIntegration(), ...getDefaultNodeIntegrations(options)];
3824
}
39-
40-
function addNestSpanAttributes(span: Span): void {
41-
const attributes = spanToJSON(span).data;
42-
43-
// this is one of: app_creation, request_context, handler
44-
const type = attributes['nestjs.type'];
45-
46-
// Only set the NestJS attributes for spans that are created by the NestJS instrumentation and for spans that do not have an op already.
47-
if (type && !attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP]) {
48-
span.setAttributes({
49-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.nestjs',
50-
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: `${type}.nestjs`,
51-
});
52-
}
53-
}

0 commit comments

Comments
 (0)