Skip to content

Commit edf9f41

Browse files
authored
fix(otel): Ensure we properly set the context for transactions (#6159)
Previously, due to timing issues with async event processors the context was sometimes not set properly. As a side effect, that also makes testing this way nicer, yayy!
1 parent 1f3fc98 commit edf9f41

File tree

2 files changed

+8
-33
lines changed

2 files changed

+8
-33
lines changed

packages/opentelemetry-node/src/spanprocessor.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Context } from '@opentelemetry/api';
22
import { Span as OtelSpan, SpanProcessor as OtelSpanProcessor } from '@opentelemetry/sdk-trace-base';
3-
import { getCurrentHub, withScope } from '@sentry/core';
3+
import { getCurrentHub } from '@sentry/core';
44
import { Transaction } from '@sentry/tracing';
55
import { DynamicSamplingContext, Span as SentrySpan, TraceparentData, TransactionContext } from '@sentry/types';
66
import { logger } from '@sentry/utils';
@@ -90,12 +90,12 @@ export class SentrySpanProcessor implements OtelSpanProcessor {
9090

9191
if (sentrySpan instanceof Transaction) {
9292
updateTransactionWithOtelData(sentrySpan, otelSpan);
93-
finishTransactionWithContextFromOtelData(sentrySpan, otelSpan);
9493
} else {
9594
updateSpanWithOtelData(sentrySpan, otelSpan);
96-
sentrySpan.finish(convertOtelTimeToSeconds(otelSpan.endTime));
9795
}
9896

97+
sentrySpan.finish(convertOtelTimeToSeconds(otelSpan.endTime));
98+
9999
SENTRY_SPAN_PROCESSOR_MAP.delete(otelSpanId);
100100
}
101101

@@ -141,17 +141,6 @@ function getTraceData(otelSpan: OtelSpan, parentContext: Context): Partial<Trans
141141
};
142142
}
143143

144-
function finishTransactionWithContextFromOtelData(transaction: Transaction, otelSpan: OtelSpan): void {
145-
withScope(scope => {
146-
scope.setContext('otel', {
147-
attributes: otelSpan.attributes,
148-
resource: otelSpan.resource.attributes,
149-
});
150-
151-
transaction.finish(convertOtelTimeToSeconds(otelSpan.endTime));
152-
});
153-
}
154-
155144
function updateSpanWithOtelData(sentrySpan: SentrySpan, otelSpan: OtelSpan): void {
156145
const { attributes, kind } = otelSpan;
157146

@@ -169,6 +158,11 @@ function updateSpanWithOtelData(sentrySpan: SentrySpan, otelSpan: OtelSpan): voi
169158
}
170159

171160
function updateTransactionWithOtelData(transaction: Transaction, otelSpan: OtelSpan): void {
161+
transaction.setContext('otel', {
162+
attributes: otelSpan.attributes,
163+
resource: otelSpan.resource.attributes,
164+
});
165+
172166
transaction.setStatus(mapOtelStatus(otelSpan));
173167

174168
const { op, description } = parseSpanDescription(otelSpan);

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

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { SemanticAttributes, SemanticResourceAttributes } from '@opentelemetry/s
77
import { createTransport, Hub, makeMain } from '@sentry/core';
88
import { NodeClient } from '@sentry/node';
99
import { addExtensionMethods, Span as SentrySpan, SpanStatusType, Transaction } from '@sentry/tracing';
10-
import { Scope } from '@sentry/types';
1110
import { resolvedSyncPromise } from '@sentry/utils';
1211

1312
import { SENTRY_SPAN_PROCESSOR_MAP, SentrySpanProcessor } from '../src/spanprocessor';
@@ -60,22 +59,6 @@ describe('SentrySpanProcessor', () => {
6059
return transactionWithContext._contexts;
6160
}
6261

63-
// monkey-patch finish to store the context at finish time
64-
function monkeyPatchTransactionFinish(transaction: Transaction) {
65-
const monkeyPatchedTransaction = transaction as Transaction;
66-
67-
// eslint-disable-next-line @typescript-eslint/unbound-method
68-
const originalFinish = monkeyPatchedTransaction.finish;
69-
// @ts-ignore accessing private property
70-
monkeyPatchedTransaction._contexts = {};
71-
monkeyPatchedTransaction.finish = function (endTimestamp?: number | undefined) {
72-
// @ts-ignore accessing private property
73-
monkeyPatchedTransaction._contexts = (transaction._hub.getScope() as unknown as Scope)._contexts;
74-
75-
return originalFinish.apply(monkeyPatchedTransaction, [endTimestamp]);
76-
};
77-
}
78-
7962
it('creates a transaction', async () => {
8063
const startTimestampMs = 1667381672875;
8164
const endTimestampMs = 1667381672309;
@@ -173,7 +156,6 @@ describe('SentrySpanProcessor', () => {
173156
const otelSpan = provider.getTracer('default').startSpan('GET /users');
174157

175158
const transaction = getSpanForOtelSpan(otelSpan) as Transaction;
176-
monkeyPatchTransactionFinish(transaction);
177159

178160
// context is only set after end
179161
expect(getContext(transaction)).toEqual({});
@@ -196,7 +178,6 @@ describe('SentrySpanProcessor', () => {
196178
const otelSpan2 = provider.getTracer('default').startSpan('GET /companies');
197179

198180
const transaction2 = getSpanForOtelSpan(otelSpan2) as Transaction;
199-
monkeyPatchTransactionFinish(transaction2);
200181

201182
expect(getContext(transaction2)).toEqual({});
202183

0 commit comments

Comments
 (0)