Skip to content

Commit 1418582

Browse files
authored
fix(otel): Make sure we use correct hub on finish (#7577)
1 parent 1121507 commit 1418582

File tree

3 files changed

+63
-25
lines changed

3 files changed

+63
-25
lines changed

packages/core/src/tracing/transaction.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class Transaction extends SpanClass implements TransactionInterface {
2323
/**
2424
* The reference to the current hub.
2525
*/
26-
public readonly _hub: Hub;
26+
public _hub: Hub;
2727

2828
private _name: string;
2929

@@ -280,4 +280,14 @@ export class Transaction extends SpanClass implements TransactionInterface {
280280

281281
return dsc;
282282
}
283+
284+
/**
285+
* Override the current hub with a new one.
286+
* Used if you want another hub to finish the transaction.
287+
*
288+
* @internal
289+
*/
290+
public setHub(hub: Hub): void {
291+
this._hub = hub;
292+
}
283293
}

packages/opentelemetry-node/src/spanprocessor.ts

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,6 @@ export class SentrySpanProcessor implements OtelSpanProcessor {
5050
* @inheritDoc
5151
*/
5252
public onStart(otelSpan: OtelSpan, parentContext: Context): void {
53-
const hub = getCurrentHub();
54-
if (!hub) {
55-
__DEBUG_BUILD__ && logger.error('SentrySpanProcessor has triggered onStart before a hub has been setup.');
56-
return;
57-
}
58-
const scope = hub.getScope();
59-
if (!scope) {
60-
__DEBUG_BUILD__ && logger.error('SentrySpanProcessor has triggered onStart before a scope has been setup.');
61-
return;
62-
}
63-
6453
const otelSpanId = otelSpan.spanContext().spanId;
6554
const otelParentSpanId = otelSpan.parentSpanId;
6655

@@ -79,7 +68,7 @@ export class SentrySpanProcessor implements OtelSpanProcessor {
7968
SENTRY_SPAN_PROCESSOR_MAP.set(otelSpanId, sentryChildSpan);
8069
} else {
8170
const traceCtx = getTraceData(otelSpan, parentContext);
82-
const transaction = hub.startTransaction({
71+
const transaction = getCurrentHub().startTransaction({
8372
name: otelSpan.name,
8473
...traceCtx,
8574
instrumenter: 'otel',
@@ -95,12 +84,6 @@ export class SentrySpanProcessor implements OtelSpanProcessor {
9584
* @inheritDoc
9685
*/
9786
public onEnd(otelSpan: OtelSpan): void {
98-
const hub = getCurrentHub();
99-
if (!hub) {
100-
__DEBUG_BUILD__ && logger.error('SentrySpanProcessor has triggered onEnd before a hub has been setup.');
101-
return;
102-
}
103-
10487
const otelSpanId = otelSpan.spanContext().spanId;
10588
const sentrySpan = SENTRY_SPAN_PROCESSOR_MAP.get(otelSpanId);
10689

@@ -143,7 +126,7 @@ export class SentrySpanProcessor implements OtelSpanProcessor {
143126
syntheticError.name = type;
144127
}
145128

146-
hub.captureException(syntheticError, {
129+
getCurrentHub().captureException(syntheticError, {
147130
captureContext: {
148131
contexts: {
149132
otel: {
@@ -162,6 +145,7 @@ export class SentrySpanProcessor implements OtelSpanProcessor {
162145

163146
if (sentrySpan instanceof Transaction) {
164147
updateTransactionWithOtelData(sentrySpan, otelSpan);
148+
sentrySpan.setHub(getCurrentHub());
165149
} else {
166150
updateSpanWithOtelData(sentrySpan, otelSpan);
167151
}

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

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@ import type { Span as OtelSpan } from '@opentelemetry/sdk-trace-base';
55
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
66
import { SemanticAttributes, SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
77
import type { SpanStatusType } from '@sentry/core';
8-
import { addTracingExtensions, createTransport, Hub, makeMain, Span as SentrySpan, Transaction } from '@sentry/core';
8+
import {
9+
addTracingExtensions,
10+
createTransport,
11+
Hub,
12+
makeMain,
13+
Scope,
14+
Span as SentrySpan,
15+
Transaction,
16+
} from '@sentry/core';
917
import { NodeClient } from '@sentry/node';
1018
import { resolvedSyncPromise } from '@sentry/utils';
1119

@@ -79,13 +87,9 @@ describe('SentrySpanProcessor', () => {
7987
expect(sentrySpanTransaction?.parentSpanId).toEqual(otelSpan.parentSpanId);
8088
expect(sentrySpanTransaction?.spanId).toEqual(otelSpan.spanContext().spanId);
8189

82-
expect(hub.getScope()?.getSpan()).toBeUndefined();
83-
8490
otelSpan.end(endTime);
8591

8692
expect(sentrySpanTransaction?.endTimestamp).toBe(endTimestampMs / 1000);
87-
88-
expect(hub.getScope()?.getSpan()).toBeUndefined();
8993
});
9094

9195
it('creates a child span if there is a running transaction', () => {
@@ -789,6 +793,46 @@ describe('SentrySpanProcessor', () => {
789793
trace_id: otelSpan.spanContext().traceId,
790794
});
791795
});
796+
797+
// Regression test for https://github.com/getsentry/sentry-javascript/issues/7538
798+
// Since otel context does not map to when Sentry hubs are cloned
799+
// we can't rely on the original hub at transaction creation to contain all
800+
// the scope information we want. Let's test to make sure that the information is
801+
// grabbed from the new hub.
802+
it('handles when a different hub creates the transaction', () => {
803+
let sentryTransaction: any;
804+
805+
client = new NodeClient({
806+
...DEFAULT_NODE_CLIENT_OPTIONS,
807+
tracesSampleRate: 1.0,
808+
});
809+
810+
client.on('finishTransaction', transaction => {
811+
sentryTransaction = transaction;
812+
});
813+
814+
hub = new Hub(client);
815+
makeMain(hub);
816+
817+
const newHub = new Hub(client, Scope.clone(hub.getScope()));
818+
newHub.configureScope(scope => {
819+
scope.setTag('foo', 'bar');
820+
});
821+
822+
const tracer = provider.getTracer('default');
823+
824+
tracer.startActiveSpan('GET /users', parentOtelSpan => {
825+
tracer.startActiveSpan('SELECT * FROM users;', child => {
826+
makeMain(newHub);
827+
child.end();
828+
});
829+
830+
parentOtelSpan.end();
831+
});
832+
833+
// @ts-ignore Accessing private attributes
834+
expect(sentryTransaction._hub.getScope()._tags.foo).toEqual('bar');
835+
});
792836
});
793837

794838
// OTEL expects a custom date format

0 commit comments

Comments
 (0)