Skip to content

Commit 8d0b779

Browse files
authored
feat(opentelemetry): Do not use SentrySpan & Transaction classes (#10982)
Instead, we build the transaction event manually in the span exporter now. We also ensure to emit `spanStart` & `spanEnd` hooks now in the span processor. With this, we can actually remove all the hub stuff from the otel package - I'll do this in a follow up!
1 parent 8b775cb commit 8d0b779

File tree

10 files changed

+261
-423
lines changed

10 files changed

+261
-423
lines changed

packages/core/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export {
9191
spanIsSampled,
9292
spanToTraceContext,
9393
getSpanDescendants,
94+
getStatusMessage,
9495
} from './utils/spanUtils';
9596
export { getRootSpan } from './utils/getRootSpan';
9697
export { applySdkMetadata } from './utils/sdkMetadata';
@@ -114,4 +115,5 @@ export { metrics } from './metrics/exports';
114115
export type { MetricData } from './metrics/exports';
115116
export { metricsDefault } from './metrics/exports-default';
116117
export { BrowserMetricsAggregator } from './metrics/browser-aggregator';
118+
export { getMetricSummaryJsonForSpan } from './metrics/metric-summary';
117119
export { addTracingHeadersToFetchRequest, instrumentFetchRequest } from './fetch';

packages/node-experimental/test/integration/transactions.test.ts

Lines changed: 77 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,17 @@ describe('Integration | Transactions', () => {
1515
});
1616

1717
it('correctly creates transaction & spans', async () => {
18-
const beforeSendTransaction = jest.fn(() => null);
18+
const transactions: TransactionEvent[] = [];
19+
const beforeSendTransaction = jest.fn(event => {
20+
transactions.push(event);
21+
return null;
22+
});
1923

20-
mockSdkInit({ enableTracing: true, beforeSendTransaction });
24+
mockSdkInit({
25+
enableTracing: true,
26+
beforeSendTransaction,
27+
release: '8.0.0',
28+
});
2129

2230
const client = Sentry.getClient()!;
2331

@@ -58,86 +66,75 @@ describe('Integration | Transactions', () => {
5866

5967
await client.flush();
6068

61-
expect(beforeSendTransaction).toHaveBeenCalledTimes(1);
62-
expect(beforeSendTransaction).toHaveBeenLastCalledWith(
63-
expect.objectContaining({
64-
breadcrumbs: [
65-
{ message: 'test breadcrumb 1', timestamp: 123456 },
66-
{ message: 'test breadcrumb 2', timestamp: 123456 },
67-
{ message: 'test breadcrumb 3', timestamp: 123456 },
68-
],
69-
contexts: {
70-
otel: {
71-
attributes: {
72-
'test.outer': 'test value',
73-
'sentry.op': 'test op',
74-
'sentry.origin': 'auto.test',
75-
'sentry.source': 'task',
76-
},
77-
resource: {
78-
'service.name': 'node',
79-
'service.namespace': 'sentry',
80-
'service.version': expect.any(String),
81-
'telemetry.sdk.language': 'nodejs',
82-
'telemetry.sdk.name': 'opentelemetry',
83-
'telemetry.sdk.version': expect.any(String),
84-
},
85-
},
86-
runtime: { name: 'node', version: expect.any(String) },
87-
trace: {
88-
data: {
89-
'otel.kind': 'INTERNAL',
90-
'sentry.op': 'test op',
91-
'sentry.origin': 'auto.test',
92-
'sentry.source': 'task',
93-
'sentry.sample_rate': 1,
94-
'test.outer': 'test value',
95-
},
96-
op: 'test op',
97-
span_id: expect.any(String),
98-
status: 'ok',
99-
trace_id: expect.any(String),
100-
origin: 'auto.test',
101-
},
102-
},
103-
environment: 'production',
104-
event_id: expect.any(String),
105-
platform: 'node',
106-
sdkProcessingMetadata: expect.objectContaining({
107-
dynamicSamplingContext: expect.objectContaining({
108-
environment: 'production',
109-
public_key: expect.any(String),
110-
sample_rate: '1',
111-
sampled: 'true',
112-
trace_id: expect.any(String),
113-
transaction: 'test name',
114-
}),
115-
sampleRate: 1,
116-
spanMetadata: expect.any(Object),
117-
requestPath: 'test-path',
118-
}),
119-
server_name: expect.any(String),
120-
// spans are circular (they have a reference to the transaction), which leads to jest choking on this
121-
// instead we compare them in detail below
122-
spans: [expect.any(Object), expect.any(Object)],
123-
start_timestamp: expect.any(Number),
124-
tags: {
125-
'outer.tag': 'test value',
126-
'test.tag': 'test value',
127-
},
128-
timestamp: expect.any(Number),
129-
transaction: 'test name',
130-
transaction_info: { source: 'task' },
131-
type: 'transaction',
132-
}),
133-
{
134-
event_id: expect.any(String),
69+
expect(transactions).toHaveLength(1);
70+
const transaction = transactions[0];
71+
72+
expect(transaction.breadcrumbs).toEqual([
73+
{ message: 'test breadcrumb 1', timestamp: 123456 },
74+
{ message: 'test breadcrumb 2', timestamp: 123456 },
75+
{ message: 'test breadcrumb 3', timestamp: 123456 },
76+
]);
77+
78+
expect(transaction.contexts?.otel).toEqual({
79+
attributes: {
80+
'test.outer': 'test value',
81+
'sentry.op': 'test op',
82+
'sentry.origin': 'auto.test',
83+
'sentry.source': 'task',
13584
},
136-
);
85+
resource: {
86+
'service.name': 'node',
87+
'service.namespace': 'sentry',
88+
'service.version': expect.any(String),
89+
'telemetry.sdk.language': 'nodejs',
90+
'telemetry.sdk.name': 'opentelemetry',
91+
'telemetry.sdk.version': expect.any(String),
92+
},
93+
});
13794

138-
// Checking the spans here, as they are circular to the transaction...
139-
const runArgs = beforeSendTransaction.mock.calls[0] as unknown as [TransactionEvent, unknown];
140-
const spans = runArgs[0].spans || [];
95+
expect(transaction.contexts?.trace).toEqual({
96+
data: {
97+
'otel.kind': 'INTERNAL',
98+
'sentry.op': 'test op',
99+
'sentry.origin': 'auto.test',
100+
'sentry.source': 'task',
101+
'sentry.sample_rate': 1,
102+
'test.outer': 'test value',
103+
},
104+
op: 'test op',
105+
span_id: expect.any(String),
106+
status: 'ok',
107+
trace_id: expect.any(String),
108+
origin: 'auto.test',
109+
});
110+
111+
expect(transaction.sdkProcessingMetadata?.sampleRate).toEqual(1);
112+
expect(transaction.sdkProcessingMetadata?.requestPath).toEqual('test-path');
113+
expect(transaction.sdkProcessingMetadata?.dynamicSamplingContext).toEqual({
114+
environment: 'production',
115+
public_key: expect.any(String),
116+
sample_rate: '1',
117+
sampled: 'true',
118+
release: '8.0.0',
119+
trace_id: expect.any(String),
120+
transaction: 'test name',
121+
});
122+
123+
expect(transaction.environment).toEqual('production');
124+
expect(transaction.event_id).toEqual(expect.any(String));
125+
expect(transaction.start_timestamp).toEqual(expect.any(Number));
126+
expect(transaction.timestamp).toEqual(expect.any(Number));
127+
expect(transaction.transaction).toEqual('test name');
128+
129+
expect(transaction.tags).toEqual({
130+
'outer.tag': 'test value',
131+
'test.tag': 'test value',
132+
});
133+
expect(transaction.transaction_info).toEqual({ source: 'task' });
134+
expect(transaction.type).toEqual('transaction');
135+
136+
expect(transaction.spans).toHaveLength(2);
137+
const spans = transaction.spans || [];
141138

142139
// note: Currently, spans do not have any context/span added to them
143140
// This is the same behavior as for the "regular" SDKs

packages/opentelemetry/src/custom/hubextensions.ts

Lines changed: 0 additions & 33 deletions
This file was deleted.

packages/opentelemetry/src/custom/transaction.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

packages/opentelemetry/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ export { startSpan, startSpanManual, startInactiveSpan, withActiveSpan } from '.
3434
export { setupGlobalHub } from './custom/hub';
3535
// eslint-disable-next-line deprecation/deprecation
3636
export { getCurrentHub } from './custom/getCurrentHub';
37-
export { addTracingExtensions } from './custom/hubextensions';
3837
export { setupEventContextTrace } from './setupEventContextTrace';
3938

4039
export { setOpenTelemetryContextAsyncContextStrategy } from './asyncContextStrategy';

0 commit comments

Comments
 (0)