Skip to content

Commit 51bbf32

Browse files
authored
fix(opentelemetry): Do not overwrite http span name if kind is internal (#13282)
If the kind of a http span is neither client nor server, it implies it is most likely being started with `startSpan()` manually, in which case we rather not want to overwrite the name.
1 parent 16996bb commit 51bbf32

File tree

4 files changed

+44
-5
lines changed

4 files changed

+44
-5
lines changed

dev-packages/node-integration-tests/suites/tracing/nestjs/scenario.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Sentry.init({
1313
});
1414

1515
import { Controller, Get, Injectable, Module } from '@nestjs/common';
16-
import { NestFactory } from '@nestjs/core';
16+
import { BaseExceptionFilter, HttpAdapterHost, NestFactory } from '@nestjs/core';
1717

1818
const port = 3450;
1919

@@ -48,6 +48,9 @@ class AppModule {}
4848
async function run(): Promise<void> {
4949
const app = await NestFactory.create(AppModule);
5050
await app.listen(port);
51+
52+
const { httpAdapter } = app.get(HttpAdapterHost);
53+
Sentry.setupNestErrorHandler(app, new BaseExceptionFilter(httpAdapter));
5154
sendPortToRunner(port);
5255
}
5356

dev-packages/node-integration-tests/suites/tracing/nestjs/test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ conditionalTest({ min: 16 })('nestjs auto instrumentation', () => {
2525
'nestjs.callback': 'getHello',
2626
'nestjs.controller': 'AppController',
2727
'nestjs.type': 'request_context',
28-
'sentry.op': 'http',
28+
'sentry.op': 'request_context.nestjs',
29+
'sentry.origin': 'auto.http.otel.nestjs',
30+
component: '@nestjs/core',
31+
'http.method': 'GET',
32+
'http.route': '/',
33+
'http.url': '/',
2934
}),
3035
}),
3136
]),

packages/opentelemetry/src/utils/parseSpanDescription.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
import type { SpanAttributes, TransactionSource } from '@sentry/types';
1515
import { getSanitizedUrlString, parseUrl, stripUrlQueryAndFragment } from '@sentry/utils';
1616

17-
import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '@sentry/core';
17+
import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
1818
import { SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION } from '../semanticAttributes';
1919
import type { AbstractSpan } from '../types';
2020
import { getSpanKind } from './getSpanKind';
@@ -163,10 +163,22 @@ export function descriptionForHttpMethod(
163163
data['http.fragment'] = fragment;
164164
}
165165

166+
// If the span kind is neither client nor server, we use the original name
167+
// this infers that somebody manually started this span, in which case we don't want to overwrite the name
168+
const isClientOrServerKind = kind === SpanKind.CLIENT || kind === SpanKind.SERVER;
169+
170+
// If the span is an auto-span (=it comes from one of our instrumentations),
171+
// we always want to infer the name
172+
// this is necessary because some of the auto-instrumentation we use uses kind=INTERNAL
173+
const origin = attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] || 'manual';
174+
const isManualSpan = !`${origin}`.startsWith('auto');
175+
176+
const useInferredDescription = isClientOrServerKind || !isManualSpan;
177+
166178
return {
167179
op: opParts.join('.'),
168-
description,
169-
source,
180+
description: useInferredDescription ? description : name,
181+
source: useInferredDescription ? source : 'custom',
170182
data,
171183
};
172184
}

packages/opentelemetry/test/utils/parseSpanDescription.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,25 @@ describe('descriptionForHttpMethod', () => {
231231
source: 'route',
232232
},
233233
],
234+
[
235+
'works with basic client GET with SpanKind.INTERNAL',
236+
'GET',
237+
{
238+
[SEMATTRS_HTTP_METHOD]: 'GET',
239+
[SEMATTRS_HTTP_URL]: 'https://www.example.com/my-path',
240+
[SEMATTRS_HTTP_TARGET]: '/my-path',
241+
},
242+
'test name',
243+
SpanKind.INTERNAL,
244+
{
245+
op: 'http',
246+
description: 'test name',
247+
data: {
248+
url: 'https://www.example.com/my-path',
249+
},
250+
source: 'custom',
251+
},
252+
],
234253
])('%s', (_, httpMethod, attributes, name, kind, expected) => {
235254
const actual = descriptionForHttpMethod({ attributes, kind, name }, httpMethod);
236255
expect(actual).toEqual(expected);

0 commit comments

Comments
 (0)