Skip to content

Commit 65d9150

Browse files
authored
feat(core): Remove deprecated props from Span interface (#10854)
Instead, in places we need it we cast to a `SentrySpan` which still has the things in place, for now. With this, our span interface is _almost_ the same as for otel spans - missing are only: * Aligning `traceFlags` - this has apparently been updated in OTEL to have type `number` only, which makes this a bit easier. * Aligning `setStatus` which has a different signature in OTEL. I'll do these in follow ups! The biggest work here was fixing tests - I tried to rewrite tests to do less mocking where possible, which IMHO should cover actual functionality better than before (e.g. in svelte).
1 parent 006b096 commit 65d9150

File tree

33 files changed

+335
-335
lines changed

33 files changed

+335
-335
lines changed

packages/astro/test/server/meta.test.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
import * as SentryCore from '@sentry/core';
2+
import { SentrySpan } from '@sentry/core';
3+
import type { Transaction } from '@sentry/types';
24
import { vi } from 'vitest';
35

46
import { getTracingMetaTags, isValidBaggageString } from '../../src/server/meta';
57

68
const TRACE_FLAG_SAMPLED = 0x1;
79

8-
const mockedSpan = {
9-
isRecording: () => true,
10-
spanContext: () => {
11-
return {
12-
traceId: '12345678901234567890123456789012',
13-
spanId: '1234567890123456',
14-
traceFlags: TRACE_FLAG_SAMPLED,
15-
};
16-
},
17-
transaction: {
18-
getDynamicSamplingContext: () => ({
19-
environment: 'production',
20-
}),
21-
},
22-
} as any;
10+
const mockedSpan = new SentrySpan({
11+
traceId: '12345678901234567890123456789012',
12+
spanId: '1234567890123456',
13+
sampled: true,
14+
});
15+
// eslint-disable-next-line deprecation/deprecation
16+
mockedSpan.transaction = {
17+
getDynamicSamplingContext: () => ({
18+
environment: 'production',
19+
}),
20+
} as Transaction;
2321

2422
const mockedClient = {} as any;
2523

packages/core/src/scope.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type {
2626
import { dateTimestampInSeconds, isPlainObject, logger, uuid4 } from '@sentry/utils';
2727

2828
import { updateSession } from './session';
29+
import type { SentrySpan } from './tracing/sentrySpan';
2930

3031
/**
3132
* Default value for maximum number of breadcrumbs added to an event.
@@ -329,10 +330,15 @@ export class Scope implements ScopeInterface {
329330
// Often, this span (if it exists at all) will be a transaction, but it's not guaranteed to be. Regardless, it will
330331
// have a pointer to the currently-active transaction.
331332
const span = this._span;
333+
332334
// Cannot replace with getRootSpan because getRootSpan returns a span, not a transaction
333335
// Also, this method will be removed anyway.
334336
// eslint-disable-next-line deprecation/deprecation
335-
return span && span.transaction;
337+
if (span && (span as SentrySpan).transaction) {
338+
// eslint-disable-next-line deprecation/deprecation
339+
return (span as SentrySpan).transaction;
340+
}
341+
return undefined;
336342
}
337343

338344
/**

packages/core/src/tracing/errors.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ import { getActiveTransaction } from './utils';
1010

1111
let errorsInstrumented = false;
1212

13+
/** Only exposed for testing */
14+
export function _resetErrorsInstrumented(): void {
15+
errorsInstrumented = false;
16+
}
17+
1318
/**
1419
* Configures global error listeners
1520
*/

packages/core/src/tracing/sentrySpan.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type {
22
Primitive,
3-
Span as SpanInterface,
3+
Span,
44
SpanAttributeValue,
55
SpanAttributes,
66
SpanContext,
@@ -62,7 +62,7 @@ export class SpanRecorder {
6262
/**
6363
* Span contains all data about a span
6464
*/
65-
export class SentrySpan implements SpanInterface {
65+
export class SentrySpan implements Span {
6666
/**
6767
* Tags for the span.
6868
* @deprecated Use `spanToJSON(span).atttributes` instead.
@@ -277,7 +277,7 @@ export class SentrySpan implements SpanInterface {
277277
*/
278278
public startChild(
279279
spanContext?: Pick<SpanContext, Exclude<keyof SpanContext, 'sampled' | 'traceId' | 'parentSpanId'>>,
280-
): SpanInterface {
280+
): Span {
281281
const childSpan = new SentrySpan({
282282
...spanContext,
283283
parentSpanId: this._spanId,

packages/core/src/tracing/trace.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Hub, Scope, Span, SpanTimeInput, StartSpanOptions, TransactionContext } from '@sentry/types';
22

33
import { dropUndefinedKeys, logger, tracingContextFromHeaders } from '@sentry/utils';
4-
54
import { getCurrentScope, getIsolationScope, withScope } from '../currentScopes';
65

76
import { DEBUG_BUILD } from '../debug-build';
@@ -10,6 +9,7 @@ import { handleCallbackErrors } from '../utils/handleCallbackErrors';
109
import { hasTracingEnabled } from '../utils/hasTracingEnabled';
1110
import { spanIsSampled, spanTimeInputToSeconds, spanToJSON } from '../utils/spanUtils';
1211
import { getDynamicSamplingContextFromSpan } from './dynamicSamplingContext';
12+
import type { SentrySpan } from './sentrySpan';
1313
import { addChildSpanToSpan, getActiveSpan, setCapturedScopesOnSpan } from './utils';
1414

1515
/**
@@ -30,7 +30,7 @@ export function startSpan<T>(context: StartSpanOptions, callback: (span: Span |
3030
// eslint-disable-next-line deprecation/deprecation
3131
const hub = getCurrentHub();
3232
// eslint-disable-next-line deprecation/deprecation
33-
const parentSpan = scope.getSpan();
33+
const parentSpan = scope.getSpan() as SentrySpan | undefined;
3434

3535
const shouldSkipSpan = context.onlyIfParent && !parentSpan;
3636
const activeSpan = shouldSkipSpan
@@ -79,7 +79,7 @@ export function startSpanManual<T>(
7979
// eslint-disable-next-line deprecation/deprecation
8080
const hub = getCurrentHub();
8181
// eslint-disable-next-line deprecation/deprecation
82-
const parentSpan = scope.getSpan();
82+
const parentSpan = scope.getSpan() as SentrySpan | undefined;
8383

8484
const shouldSkipSpan = context.onlyIfParent && !parentSpan;
8585
const activeSpan = shouldSkipSpan
@@ -130,8 +130,8 @@ export function startInactiveSpan(context: StartSpanOptions): Span | undefined {
130130
const hub = getCurrentHub();
131131
const parentSpan = context.scope
132132
? // eslint-disable-next-line deprecation/deprecation
133-
context.scope.getSpan()
134-
: getActiveSpan();
133+
(context.scope.getSpan() as SentrySpan | undefined)
134+
: (getActiveSpan() as SentrySpan | undefined);
135135

136136
const shouldSkipSpan = context.onlyIfParent && !parentSpan;
137137

@@ -264,7 +264,7 @@ function createChildSpanOrTransaction(
264264
forceTransaction,
265265
scope,
266266
}: {
267-
parentSpan: Span | undefined;
267+
parentSpan: SentrySpan | undefined;
268268
spanContext: TransactionContext;
269269
forceTransaction?: boolean;
270270
scope: Scope;

packages/core/src/utils/getRootSpan.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Span } from '@sentry/types';
2+
import type { SentrySpan } from './../tracing/sentrySpan';
23

34
/**
45
* Returns the root span of a given span.
@@ -11,5 +12,5 @@ import type { Span } from '@sentry/types';
1112
export function getRootSpan(span: Span): Span | undefined {
1213
// TODO (v8): Remove this check and just return span
1314
// eslint-disable-next-line deprecation/deprecation
14-
return span.transaction;
15+
return (span as SentrySpan).transaction ? (span as SentrySpan).transaction : undefined;
1516
}

packages/core/src/utils/prepareEvent.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,7 @@ function normalizeEvent(event: Event | null, depth: number, maxBreadth: number):
332332

333333
if (data) {
334334
// This is a bit weird, as we generally have `Span` instances here, but to be safe we do not assume so
335-
// eslint-disable-next-line deprecation/deprecation
336-
span.data = normalize(data, depth, maxBreadth);
335+
span.setAttributes(normalize(data, depth, maxBreadth));
337336
}
338337

339338
return span;

packages/core/src/utils/spanUtils.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,27 +62,28 @@ function ensureTimestampInSeconds(timestamp: number): number {
6262
return isMs ? timestamp / 1000 : timestamp;
6363
}
6464

65+
type SpanWithToJSON = Span & { toJSON: () => SpanJSON };
66+
6567
/**
6668
* Convert a span to a JSON representation.
6769
* Note that all fields returned here are optional and need to be guarded against.
6870
*
6971
* Note: Because of this, we currently have a circular type dependency (which we opted out of in package.json).
7072
* This is not avoidable as we need `spanToJSON` in `spanUtils.ts`, which in turn is needed by `span.ts` for backwards compatibility.
7173
* And `spanToJSON` needs the Span class from `span.ts` to check here.
72-
* TODO v8: When we remove the deprecated stuff from `span.ts`, we can remove the circular dependency again.
7374
*/
7475
export function spanToJSON(span: Span): Partial<SpanJSON> {
7576
if (spanIsSentrySpan(span)) {
7677
return span.getSpanJSON();
7778
}
7879

7980
// Fallback: We also check for `.toJSON()` here...
80-
// eslint-disable-next-line deprecation/deprecation
81-
if (typeof span.toJSON === 'function') {
82-
// eslint-disable-next-line deprecation/deprecation
83-
return span.toJSON();
81+
if (typeof (span as SpanWithToJSON).toJSON === 'function') {
82+
return (span as SpanWithToJSON).toJSON();
8483
}
8584

85+
// TODO: Also handle OTEL spans here!
86+
8687
return {};
8788
}
8889

packages/core/test/lib/hint.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { captureEvent, getCurrentScope } from '@sentry/core';
21
import { GLOBAL_OBJ } from '@sentry/utils';
32

3+
import { captureEvent, getCurrentScope } from '../../src';
44
import { initAndBind } from '../../src/sdk';
55
import { TestClient, getDefaultTestClientOptions } from '../mocks/client';
66
import { AddAttachmentTestIntegration } from '../mocks/integration';

packages/core/test/lib/integrations/requestdata.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import type { IncomingMessage } from 'http';
2-
import type { RequestDataIntegrationOptions } from '@sentry/core';
3-
import { setCurrentClient } from '@sentry/core';
4-
import { RequestData } from '@sentry/core';
52
import type { Event, EventProcessor } from '@sentry/types';
63
import * as sentryUtils from '@sentry/utils';
4+
import type { RequestDataIntegrationOptions } from '../../../src';
5+
import { RequestData, setCurrentClient } from '../../../src';
76

87
import { TestClient, getDefaultTestClientOptions } from '../../mocks/client';
98

packages/core/test/lib/scope.test.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -961,18 +961,16 @@ describe('withActiveSpan()', () => {
961961
});
962962
});
963963

964-
it('should create child spans when calling startSpan within the callback', done => {
965-
expect.assertions(2);
964+
it('should create child spans when calling startSpan within the callback', () => {
966965
const inactiveSpan = startInactiveSpan({ name: 'inactive-span' });
967966

968-
withActiveSpan(inactiveSpan!, () => {
969-
startSpan({ name: 'child-span' }, childSpan => {
970-
// eslint-disable-next-line deprecation/deprecation
971-
expect(childSpan?.parentSpanId).toBe(inactiveSpan?.spanContext().spanId);
972-
expect(spanToJSON(childSpan!).parent_span_id).toBe(inactiveSpan?.spanContext().spanId);
973-
done();
967+
const parentSpanId = withActiveSpan(inactiveSpan!, () => {
968+
return startSpan({ name: 'child-span' }, childSpan => {
969+
return spanToJSON(childSpan!).parent_span_id;
974970
});
975971
});
972+
973+
expect(parentSpanId).toBe(inactiveSpan?.spanContext().spanId);
976974
});
977975

978976
it('when `null` is passed, no span should be active within the callback', () => {

packages/core/test/lib/sdk.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { captureCheckIn, getCurrentScope, setCurrentClient } from '@sentry/core';
21
import type { Client, Integration, IntegrationFnResult } from '@sentry/types';
2+
import { captureCheckIn, getCurrentScope, setCurrentClient } from '../../src';
33

44
import { installedIntegrations } from '../../src/integration';
55
import { initAndBind } from '../../src/sdk';

packages/core/test/lib/tracing/errors.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import { addTracingExtensions, setCurrentClient, spanToJSON, startInactiveSpan, startSpan } from '@sentry/core';
21
import type { HandlerDataError, HandlerDataUnhandledRejection } from '@sentry/types';
2+
import { addTracingExtensions, setCurrentClient, spanToJSON, startInactiveSpan, startSpan } from '../../../src';
33

4-
import { registerErrorInstrumentation } from '../../../src/tracing/errors';
4+
import { _resetErrorsInstrumented, registerErrorInstrumentation } from '../../../src/tracing/errors';
55
import { TestClient, getDefaultTestClientOptions } from '../../mocks/client';
66

77
const mockAddGlobalErrorInstrumentationHandler = jest.fn();
88
const mockAddGlobalUnhandledRejectionInstrumentationHandler = jest.fn();
99
let mockErrorCallback: (data: HandlerDataError) => void = () => {};
1010
let mockUnhandledRejectionCallback: (data: HandlerDataUnhandledRejection) => void = () => {};
11+
1112
jest.mock('@sentry/utils', () => {
1213
const actual = jest.requireActual('@sentry/utils');
1314
return {
@@ -36,6 +37,7 @@ describe('registerErrorHandlers()', () => {
3637
const client = new TestClient(options);
3738
setCurrentClient(client);
3839
client.init();
40+
_resetErrorsInstrumented();
3941
});
4042

4143
it('registers error instrumentation', () => {

packages/core/test/lib/tracing/idletransaction.test.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
/* eslint-disable deprecation/deprecation */
2+
import { TestClient, getDefaultTestClientOptions } from '../../mocks/client';
3+
14
import {
5+
IdleTransaction,
6+
SentrySpan,
27
TRACING_DEFAULTS,
38
Transaction,
9+
getClient,
410
getCurrentHub,
511
getCurrentScope,
612
getGlobalScope,
@@ -10,11 +16,7 @@ import {
1016
startInactiveSpan,
1117
startSpan,
1218
startSpanManual,
13-
} from '@sentry/core';
14-
/* eslint-disable deprecation/deprecation */
15-
import { TestClient, getDefaultTestClientOptions } from '../../mocks/client';
16-
17-
import { IdleTransaction, SentrySpan, getClient } from '../../../src';
19+
} from '../../../src';
1820
import { IdleTransactionSpanRecorder } from '../../../src/tracing/idletransaction';
1921

2022
const dsn = 'https://[email protected]/42';
@@ -47,6 +49,7 @@ describe('IdleTransaction', () => {
4749
transaction.initSpanRecorder(10);
4850

4951
const scope = getCurrentScope();
52+
5053
// eslint-disable-next-line deprecation/deprecation
5154
expect(scope.getTransaction()).toBe(transaction);
5255
});

packages/core/test/lib/tracing/trace.test.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -287,10 +287,7 @@ describe('startSpan', () => {
287287
expect(getCurrentScope()).not.toBe(initialScope);
288288
expect(getCurrentScope()).toBe(manualScope);
289289
expect(getActiveSpan()).toBe(span);
290-
291290
expect(spanToJSON(span!).parent_span_id).toBe('parent-span-id');
292-
// eslint-disable-next-line deprecation/deprecation
293-
expect(span?.parentSpanId).toBe('parent-span-id');
294291
});
295292

296293
expect(getCurrentScope()).toBe(initialScope);
@@ -565,8 +562,6 @@ describe('startSpanManual', () => {
565562
expect(getCurrentScope()).toBe(manualScope);
566563
expect(getActiveSpan()).toBe(span);
567564
expect(spanToJSON(span!).parent_span_id).toBe('parent-span-id');
568-
// eslint-disable-next-line deprecation/deprecation
569-
expect(span?.parentSpanId).toBe('parent-span-id');
570565

571566
finish();
572567

@@ -789,8 +784,6 @@ describe('startInactiveSpan', () => {
789784

790785
expect(span).toBeDefined();
791786
expect(spanToJSON(span!).parent_span_id).toBe('parent-span-id');
792-
// eslint-disable-next-line deprecation/deprecation
793-
expect(span?.parentSpanId).toBe('parent-span-id');
794787
expect(getActiveSpan()).toBeUndefined();
795788

796789
span?.end();

packages/node/src/integrations/http.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable max-lines */
22
import type * as http from 'http';
33
import type * as https from 'https';
4-
import type { Hub } from '@sentry/core';
4+
import type { Hub, SentrySpan } from '@sentry/core';
55
import { defineIntegration, getIsolationScope, hasTracingEnabled } from '@sentry/core';
66
import {
77
addBreadcrumb,
@@ -319,7 +319,7 @@ function _createWrappedRequestMethodFactory(
319319

320320
const scope = getCurrentScope();
321321
const isolationScope = getIsolationScope();
322-
const parentSpan = getActiveSpan();
322+
const parentSpan = getActiveSpan() as SentrySpan;
323323

324324
const data = getRequestSpanData(requestUrl, requestOptions);
325325

packages/node/src/integrations/undici/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { SentrySpan } from '@sentry/core';
12
import {
23
addBreadcrumb,
34
defineIntegration,
@@ -183,7 +184,7 @@ export class Undici implements Integration {
183184
const clientOptions = client.getOptions();
184185
const scope = getCurrentScope();
185186
const isolationScope = getIsolationScope();
186-
const parentSpan = getActiveSpan();
187+
const parentSpan = getActiveSpan() as SentrySpan;
187188

188189
const span = this._shouldCreateSpan(stringUrl) ? createRequestSpan(parentSpan, request, stringUrl) : undefined;
189190
if (span) {
@@ -320,7 +321,7 @@ function setHeadersOnRequest(
320321
}
321322

322323
function createRequestSpan(
323-
activeSpan: Span | undefined,
324+
activeSpan: SentrySpan | undefined,
324325
request: RequestWithSentry,
325326
stringUrl: string,
326327
): Span | undefined {

0 commit comments

Comments
 (0)