Skip to content

Commit af9d0f7

Browse files
committed
fix(otel): Add transaction source logic to otel spans
1 parent 1f3fc98 commit af9d0f7

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

packages/opentelemetry-node/src/spanprocessor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,9 @@ function updateSpanWithOtelData(sentrySpan: SentrySpan, otelSpan: OtelSpan): voi
171171
function updateTransactionWithOtelData(transaction: Transaction, otelSpan: OtelSpan): void {
172172
transaction.setStatus(mapOtelStatus(otelSpan));
173173

174-
const { op, description } = parseSpanDescription(otelSpan);
174+
const { op, description, source } = parseSpanDescription(otelSpan);
175175
transaction.op = op;
176-
transaction.name = description;
176+
transaction.setName(description, source);
177177
}
178178

179179
function convertOtelTimeToSeconds([seconds, nano]: [number, number]): number {

packages/opentelemetry-node/src/utils/parse-otel-span-description.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { AttributeValue, SpanKind } from '@opentelemetry/api';
22
import { Span as OtelSpan } from '@opentelemetry/sdk-trace-base';
33
import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
4+
import { TransactionSource } from '@sentry/types';
45

56
interface SpanDescription {
67
op: string | undefined;
78
description: string;
9+
source: TransactionSource;
810
}
911

1012
/**
@@ -36,6 +38,7 @@ export function parseSpanDescription(otelSpan: OtelSpan): SpanDescription {
3638
return {
3739
op: 'rpc',
3840
description: name,
41+
source: 'route',
3942
};
4043
}
4144

@@ -45,16 +48,17 @@ export function parseSpanDescription(otelSpan: OtelSpan): SpanDescription {
4548
return {
4649
op: 'message',
4750
description: name,
51+
source: 'route',
4852
};
4953
}
5054

5155
// If faas.trigger exists then this is a function as a service span.
5256
const faasTrigger = attributes[SemanticAttributes.FAAS_TRIGGER];
5357
if (faasTrigger) {
54-
return { op: faasTrigger.toString(), description: name };
58+
return { op: faasTrigger.toString(), description: name, source: 'route' };
5559
}
5660

57-
return { op: undefined, description: name };
61+
return { op: undefined, description: name, source: 'custom' };
5862
}
5963

6064
function descriptionForDbSystem(otelSpan: OtelSpan, _dbSystem: AttributeValue): SpanDescription {
@@ -65,7 +69,7 @@ function descriptionForDbSystem(otelSpan: OtelSpan, _dbSystem: AttributeValue):
6569

6670
const description = statement ? statement.toString() : name;
6771

68-
return { op: 'db', description };
72+
return { op: 'db', description, source: 'task' };
6973
}
7074

7175
function descriptionForHttpMethod(otelSpan: OtelSpan, httpMethod: AttributeValue): SpanDescription {
@@ -82,15 +86,19 @@ function descriptionForHttpMethod(otelSpan: OtelSpan, httpMethod: AttributeValue
8286
break;
8387
}
8488

89+
const httpTarget = attributes[SemanticAttributes.HTTP_TARGET];
90+
const httpRoute = attributes[SemanticAttributes.HTTP_ROUTE];
91+
8592
// Ex. /api/users
86-
const httpPath = attributes[SemanticAttributes.HTTP_ROUTE] || attributes[SemanticAttributes.HTTP_TARGET];
93+
const httpPath = httpRoute || httpTarget;
8794

8895
if (!httpPath) {
89-
return { op: opParts.join('.'), description: name };
96+
return { op: opParts.join('.'), description: name, source: 'custom' };
9097
}
9198

9299
// Ex. description="GET /api/users".
93100
const description = `${httpMethod} ${httpPath}`;
101+
const source: TransactionSource = httpRoute ? 'route' : 'url';
94102

95-
return { op: opParts.join('.'), description };
103+
return { op: opParts.join('.'), description, source };
96104
}

packages/opentelemetry-node/test/spanprocessor.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,36 @@ describe('SentrySpanProcessor', () => {
462462
});
463463
});
464464

465+
it('adds transaction source `url` for HTTP_TARGET', async () => {
466+
const tracer = provider.getTracer('default');
467+
468+
tracer.startActiveSpan('GET /users', otelSpan => {
469+
const sentrySpan = getSpanForOtelSpan(otelSpan);
470+
471+
otelSpan.setAttribute(SemanticAttributes.HTTP_METHOD, 'GET');
472+
otelSpan.setAttribute(SemanticAttributes.HTTP_TARGET, '/my/route/123');
473+
474+
otelSpan.end();
475+
476+
expect(sentrySpan?.transaction?.metadata.source).toBe('url');
477+
});
478+
});
479+
480+
it('adds transaction source `url` for HTTP_ROUTE', async () => {
481+
const tracer = provider.getTracer('default');
482+
483+
tracer.startActiveSpan('GET /users', otelSpan => {
484+
const sentrySpan = getSpanForOtelSpan(otelSpan);
485+
486+
otelSpan.setAttribute(SemanticAttributes.HTTP_METHOD, 'GET');
487+
otelSpan.setAttribute(SemanticAttributes.HTTP_ROUTE, '/my/route/:id');
488+
489+
otelSpan.end();
490+
491+
expect(sentrySpan?.transaction?.metadata.source).toBe('route');
492+
});
493+
});
494+
465495
it('updates based on attributes for DB_SYSTEM', async () => {
466496
const tracer = provider.getTracer('default');
467497

0 commit comments

Comments
 (0)