diff --git a/packages/node-experimental/src/index.ts b/packages/node-experimental/src/index.ts index 016fda4df497..4ff17bfe167a 100644 --- a/packages/node-experimental/src/index.ts +++ b/packages/node-experimental/src/index.ts @@ -33,7 +33,6 @@ export { captureException, captureEvent, captureMessage, - addGlobalEventProcessor, addEventProcessor, setContext, setExtra, @@ -45,19 +44,18 @@ export { withIsolationScope, withActiveSpan, getCurrentScope, - getGlobalScope, getIsolationScope, setIsolationScope, setCurrentScope, } from './sdk/api'; export { getCurrentHub, makeMain } from './sdk/hub'; -export { Scope } from './sdk/scope'; export { addBreadcrumb, makeNodeTransport, defaultStackParser, getSentryRelease, + getGlobalScope, addRequestDataToEvent, DEFAULT_USER_INCLUDES, extractRequestData, diff --git a/packages/node-experimental/src/integrations/http.ts b/packages/node-experimental/src/integrations/http.ts index 6894ddc4ab2e..0e24798ef173 100644 --- a/packages/node-experimental/src/integrations/http.ts +++ b/packages/node-experimental/src/integrations/http.ts @@ -3,6 +3,7 @@ import type { Span } from '@opentelemetry/api'; import { SpanKind } from '@opentelemetry/api'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; + import { addBreadcrumb, defineIntegration, hasTracingEnabled, isSentryRequestUrl } from '@sentry/core'; import { _INTERNAL, getClient, getSpanKind, setSpanMetadata } from '@sentry/opentelemetry'; import type { EventProcessor, Hub, Integration, IntegrationFn } from '@sentry/types'; diff --git a/packages/node-experimental/src/sdk/api.ts b/packages/node-experimental/src/sdk/api.ts index 658e78028137..253f14aa103d 100644 --- a/packages/node-experimental/src/sdk/api.ts +++ b/packages/node-experimental/src/sdk/api.ts @@ -10,6 +10,7 @@ import type { Extra, Extras, Primitive, + Scope, SeverityLevel, User, } from '@sentry/types'; @@ -17,10 +18,9 @@ import { getContextFromScope, getScopesFromContext, setScopesOnContext } from '. import type { ExclusiveEventHintOrCaptureContext } from '../utils/prepareEvent'; import { parseEventHintOrCaptureContext } from '../utils/prepareEvent'; -import type { Scope } from './scope'; -import { getClient, getCurrentScope, getGlobalScope, getIsolationScope, isInitialized } from './scope'; +import { getClient, getCurrentScope, getIsolationScope, isInitialized } from './scope'; -export { getCurrentScope, getGlobalScope, getIsolationScope, getClient, isInitialized }; +export { getCurrentScope, getIsolationScope, getClient, isInitialized }; export { setCurrentScope, setIsolationScope } from './scope'; /** @@ -113,13 +113,6 @@ export function captureEvent(event: Event, hint?: EventHint): string { return getCurrentScope().captureEvent(event, hint); } -/** - * Add a global event processor. - */ -export function addGlobalEventProcessor(eventProcessor: EventProcessor): void { - getGlobalScope().addEventProcessor(eventProcessor); -} - /** * Add an event processor to the current isolation scope. */ diff --git a/packages/node-experimental/src/sdk/client.ts b/packages/node-experimental/src/sdk/client.ts index 5e4ccafaa5d3..4aa88d121414 100644 --- a/packages/node-experimental/src/sdk/client.ts +++ b/packages/node-experimental/src/sdk/client.ts @@ -4,8 +4,6 @@ import type { Tracer } from '@opentelemetry/api'; import { trace } from '@opentelemetry/api'; import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'; import { applySdkMetadata } from '@sentry/core'; -import type { CaptureContext, Event, EventHint } from '@sentry/types'; -import { Scope } from './scope'; /** A client for using Sentry with Node & OpenTelemetry. */ export class NodeExperimentalClient extends NodeClient { @@ -45,31 +43,4 @@ export class NodeExperimentalClient extends NodeClient { return super.flush(timeout); } - - /** - * Extends the base `_prepareEvent` so that we can properly handle `captureContext`. - * This uses `new Scope()`, which we need to replace with our own Scope for this client. - */ - protected _prepareEvent( - event: Event, - hint: EventHint, - scope?: Scope, - isolationScope?: Scope, - ): PromiseLike { - let actualScope = scope; - - // Remove `captureContext` hint and instead clone already here - if (hint && hint.captureContext) { - actualScope = getScopeForEvent(scope, hint.captureContext); - delete hint.captureContext; - } - - return super._prepareEvent(event, hint, actualScope, isolationScope); - } -} - -function getScopeForEvent(scope: Scope | undefined, captureContext: CaptureContext): Scope | undefined { - const finalScope = scope ? scope.clone() : new Scope(); - finalScope.update(captureContext); - return finalScope; } diff --git a/packages/node-experimental/src/sdk/hub.ts b/packages/node-experimental/src/sdk/hub.ts index fe9124dbe40f..30a6ce05de0d 100644 --- a/packages/node-experimental/src/sdk/hub.ts +++ b/packages/node-experimental/src/sdk/hub.ts @@ -5,6 +5,7 @@ import type { Hub, Integration, IntegrationClass, + Scope, SeverityLevel, TransactionContext, } from '@sentry/types'; @@ -23,7 +24,6 @@ import { withScope, } from './api'; import { callExtensionMethod, getGlobalCarrier } from './globals'; -import type { Scope } from './scope'; import { getIsolationScope } from './scope'; import type { SentryCarrier } from './types'; diff --git a/packages/node-experimental/src/sdk/init.ts b/packages/node-experimental/src/sdk/init.ts index d15c28dc3f98..519eb151752a 100644 --- a/packages/node-experimental/src/sdk/init.ts +++ b/packages/node-experimental/src/sdk/init.ts @@ -22,7 +22,7 @@ import { httpIntegration } from '../integrations/http'; import { nativeNodeFetchIntegration } from '../integrations/node-fetch'; import { setOpenTelemetryContextAsyncContextStrategy } from '../otel/asyncContextStrategy'; import type { NodeExperimentalClientOptions, NodeExperimentalOptions } from '../types'; -import { getClient, getCurrentScope, getGlobalScope, getIsolationScope } from './api'; +import { getClient, getCurrentScope, getIsolationScope } from './api'; import { NodeExperimentalClient } from './client'; import { getGlobalCarrier } from './globals'; import { setLegacyHubOnCarrier } from './hub'; @@ -70,9 +70,8 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void { scope.update(options.initialScope); const client = new NodeExperimentalClient(clientOptions); - // The client is on the global scope, from where it generally is inherited - // unless somebody specifically sets a different one on a scope/isolations cope - getGlobalScope().setClient(client); + // The client is on the current scope, from where it generally is inherited + getCurrentScope().setClient(client); if (isEnabled(client)) { client.init(); diff --git a/packages/node-experimental/src/sdk/scope.ts b/packages/node-experimental/src/sdk/scope.ts index a92403c3e664..80764261f1e7 100644 --- a/packages/node-experimental/src/sdk/scope.ts +++ b/packages/node-experimental/src/sdk/scope.ts @@ -1,10 +1,9 @@ -import { getGlobalScope as _getGlobalScope, setGlobalScope } from '@sentry/core'; -import { OpenTelemetryScope } from '@sentry/opentelemetry'; -import type { Client, Event, EventHint, SeverityLevel } from '@sentry/types'; -import { uuid4 } from '@sentry/utils'; +import { Scope as ScopeClass, getGlobalScope } from '@sentry/core'; +import type { Client } from '@sentry/types'; +import type { Scope } from '@sentry/types'; import { getGlobalCarrier } from './globals'; -import type { CurrentScopes, Scope as ScopeInterface, ScopeData, SentryCarrier } from './types'; +import type { CurrentScopes, SentryCarrier } from './types'; /** Get the current scope. */ export function getCurrentScope(): Scope { @@ -19,24 +18,6 @@ export function setCurrentScope(scope: Scope): void { getScopes().scope = scope; } -/** - * Get the global scope. - * We overwrite this from the core implementation to make sure we get the correct Scope class. - */ -export function getGlobalScope(): Scope { - const globalScope = _getGlobalScope(); - - // If we have a default Scope here by chance, make sure to "upgrade" it to our custom Scope - if (!(globalScope instanceof Scope)) { - const newScope = new Scope(); - newScope.update(globalScope); - setGlobalScope(newScope); - return newScope; - } - - return globalScope; -} - /** Get the currently active isolation scope. */ export function getIsolationScope(): Scope { return getScopes().isolationScope as Scope; @@ -70,103 +51,6 @@ export function isInitialized(): boolean { return !!getClient().getDsn(); } -/** A fork of the classic scope with some otel specific stuff. */ -export class Scope extends OpenTelemetryScope implements ScopeInterface { - protected _client: Client | undefined; - - /** - * @inheritDoc - */ - public clone(): Scope { - const newScope = new Scope(); - newScope._breadcrumbs = [...this['_breadcrumbs']]; - newScope._tags = { ...this['_tags'] }; - newScope._extra = { ...this['_extra'] }; - newScope._contexts = { ...this['_contexts'] }; - newScope._user = { ...this['_user'] }; - newScope._level = this['_level']; - newScope._span = this['_span']; - newScope._session = this['_session']; - newScope._transactionName = this['_transactionName']; - newScope._fingerprint = this['_fingerprint']; - newScope._eventProcessors = [...this['_eventProcessors']]; - newScope._requestSession = this['_requestSession']; - newScope._attachments = [...this['_attachments']]; - newScope._sdkProcessingMetadata = { ...this['_sdkProcessingMetadata'] }; - newScope._propagationContext = { ...this['_propagationContext'] }; - newScope._client = this._client; - - return newScope; - } - - /** Update the client on the scope. */ - public setClient(client: Client): void { - this._client = client; - } - - /** - * Get the client assigned to this scope. - * Should generally not be used by users - use top-level `Sentry.getClient()` instead! - * @internal - */ - public getClient(): Client | undefined { - return this._client; - } - - /** Capture an exception for this scope. */ - public captureException(exception: unknown, hint?: EventHint): string { - const eventId = hint && hint.event_id ? hint.event_id : uuid4(); - const syntheticException = new Error('Sentry syntheticException'); - - getClient().captureException( - exception, - { - originalException: exception, - syntheticException, - ...hint, - event_id: eventId, - }, - this, - ); - - return eventId; - } - - /** Capture a message for this scope. */ - public captureMessage(message: string, level?: SeverityLevel, hint?: EventHint): string { - const eventId = hint && hint.event_id ? hint.event_id : uuid4(); - const syntheticException = new Error(message); - - getClient().captureMessage( - message, - level, - { - originalException: message, - syntheticException, - ...hint, - event_id: eventId, - }, - this, - ); - - return eventId; - } - - /** Capture a message for this scope. */ - public captureEvent(event: Event, hint?: EventHint): string { - const eventId = hint && hint.event_id ? hint.event_id : uuid4(); - - getClient().captureEvent(event, { ...hint, event_id: eventId }, this); - - return eventId; - } - - /** Get scope data for this scope only. */ - public getOwnScopeData(): ScopeData { - return super.getScopeData(); - } -} - function getScopes(): CurrentScopes { const carrier = getGlobalCarrier(); @@ -184,8 +68,8 @@ function getScopes(): CurrentScopes { function getGlobalCurrentScopes(carrier: SentryCarrier): CurrentScopes { if (!carrier.scopes) { carrier.scopes = { - scope: new Scope(), - isolationScope: new Scope(), + scope: new ScopeClass(), + isolationScope: new ScopeClass(), }; } diff --git a/packages/node-experimental/src/sdk/spanProcessor.ts b/packages/node-experimental/src/sdk/spanProcessor.ts index f298d049f94b..4cc782d804f1 100644 --- a/packages/node-experimental/src/sdk/spanProcessor.ts +++ b/packages/node-experimental/src/sdk/spanProcessor.ts @@ -6,16 +6,11 @@ import { SentrySpanProcessor, getClient } from '@sentry/opentelemetry'; import type { Http } from '../integrations/http'; import type { NodeFetch } from '../integrations/node-fetch'; import type { NodeExperimentalClient } from '../types'; -import { Scope } from './scope'; /** * Implement custom code to avoid sending spans in certain cases. */ export class NodeExperimentalSentrySpanProcessor extends SentrySpanProcessor { - public constructor() { - super({ scopeClass: Scope }); - } - /** @inheritDoc */ protected _shouldSendSpanToSentry(span: Span): boolean { const client = getClient(); diff --git a/packages/node-experimental/src/sdk/types.ts b/packages/node-experimental/src/sdk/types.ts index ee6642dadb9c..c493353fe12c 100644 --- a/packages/node-experimental/src/sdk/types.ts +++ b/packages/node-experimental/src/sdk/types.ts @@ -8,7 +8,7 @@ import type { Integration, Primitive, PropagationContext, - Scope as BaseScope, + Scope, SeverityLevel, User, } from '@sentry/types'; @@ -27,12 +27,6 @@ export interface ScopeData { level?: SeverityLevel; } -export interface Scope extends BaseScope { - // @ts-expect-error typeof this is what we want here - clone(scope?: Scope): typeof this; - getScopeData(): ScopeData; -} - export interface CurrentScopes { scope: Scope; isolationScope: Scope; diff --git a/packages/node-experimental/test/integration/breadcrumbs.test.ts b/packages/node-experimental/test/integration/breadcrumbs.test.ts index 9c09b12efcc1..e3862962338f 100644 --- a/packages/node-experimental/test/integration/breadcrumbs.test.ts +++ b/packages/node-experimental/test/integration/breadcrumbs.test.ts @@ -26,7 +26,6 @@ describe('Integration | breadcrumbs', () => { addBreadcrumb({ timestamp: 123455, message: 'test3' }); const error = new Error('test'); - // eslint-disable-next-line deprecation/deprecation captureException(error); await client.flush(); @@ -117,7 +116,6 @@ describe('Integration | breadcrumbs', () => { addBreadcrumb({ timestamp: 123455, message: 'test3' }); }); - // eslint-disable-next-line deprecation/deprecation captureException(error); }); @@ -170,7 +168,6 @@ describe('Integration | breadcrumbs', () => { addBreadcrumb({ timestamp: 123457, message: 'test2-b' }); }); - // eslint-disable-next-line deprecation/deprecation captureException(error); }); }); @@ -213,7 +210,6 @@ describe('Integration | breadcrumbs', () => { addBreadcrumb({ timestamp: 123457, message: 'test2' }); }); - // eslint-disable-next-line deprecation/deprecation captureException(error); }); @@ -260,7 +256,6 @@ describe('Integration | breadcrumbs', () => { startSpan({ name: 'inner3' }, () => { addBreadcrumb({ timestamp: 123457, message: 'test4' }); - // eslint-disable-next-line deprecation/deprecation captureException(error); startSpan({ name: 'inner4' }, () => { @@ -320,7 +315,6 @@ describe('Integration | breadcrumbs', () => { await new Promise(resolve => setTimeout(resolve, 10)); - // eslint-disable-next-line deprecation/deprecation captureException(error); }); }); diff --git a/packages/node-experimental/test/integration/scope.test.ts b/packages/node-experimental/test/integration/scope.test.ts index 9eb9773e6f53..e800de4d41d0 100644 --- a/packages/node-experimental/test/integration/scope.test.ts +++ b/packages/node-experimental/test/integration/scope.test.ts @@ -234,7 +234,6 @@ describe('Integration | Scope', () => { it('works before calling init', () => { const globalScope = Sentry.getGlobalScope(); expect(globalScope).toBeDefined(); - expect(globalScope).toBeInstanceOf(Sentry.Scope); // No client attached expect(globalScope.getClient()).toBeUndefined(); // Repeatedly returns the same instance @@ -248,7 +247,7 @@ describe('Integration | Scope', () => { // Now when we call init, the global scope remains intact Sentry.init({ dsn: 'https://username@domain/123', defaultIntegrations: false }); - expect(globalScope.getClient()).toBeDefined(); + expect(globalScope.getClient()).toBeUndefined(); expect(Sentry.getGlobalScope()).toBe(globalScope); expect(globalScope.getScopeData().tags).toEqual({ tag1: 'val1', tag2: 'val2' }); }); @@ -292,7 +291,6 @@ describe('Integration | Scope', () => { it('works before calling init', () => { const isolationScope = Sentry.getIsolationScope(); expect(isolationScope).toBeDefined(); - expect(isolationScope).toBeInstanceOf(Sentry.Scope); // No client attached expect(isolationScope.getClient()).toBeUndefined(); // Repeatedly returns the same instance @@ -444,7 +442,6 @@ describe('Integration | Scope', () => { it('works before calling init', () => { const currentScope = Sentry.getCurrentScope(); expect(currentScope).toBeDefined(); - expect(currentScope).toBeInstanceOf(Sentry.Scope); // No client attached expect(currentScope.getClient()).toBeUndefined(); // Repeatedly returns the same instance @@ -458,8 +455,8 @@ describe('Integration | Scope', () => { // Now when we call init, the current scope remains intact Sentry.init({ dsn: 'https://username@domain/123', defaultIntegrations: false }); - // client is only attached to global scope by default - expect(currentScope.getClient()).toBeUndefined(); + // client is attached to current scope + expect(currentScope.getClient()).toBeDefined(); // current scope remains intact expect(Sentry.getCurrentScope()).toBe(currentScope); expect(currentScope.getScopeData().tags).toEqual({ tag1: 'val1', tag2: 'val2' }); diff --git a/packages/node-experimental/test/sdk/scope.test.ts b/packages/node-experimental/test/sdk/scope.test.ts index 076188d9c9b7..09f21aac067d 100644 --- a/packages/node-experimental/test/sdk/scope.test.ts +++ b/packages/node-experimental/test/sdk/scope.test.ts @@ -1,7 +1,6 @@ -import { prepareEvent } from '@sentry/core'; +import { Scope, getGlobalScope, prepareEvent } from '@sentry/core'; import type { Attachment, Breadcrumb, Client, ClientOptions, EventProcessor } from '@sentry/types'; -import { Scope, getIsolationScope } from '../../src'; -import { getGlobalScope } from '../../src/sdk/scope'; +import { getIsolationScope } from '../../src'; import { mockSdkInit } from '../helpers/mockSdkInit'; describe('Unit | Scope', () => { @@ -164,7 +163,7 @@ describe('Unit | Scope', () => { scope.addAttachment(attachment1); const globalScope = getGlobalScope(); - const isolationScope = getIsolationScope(); + const isolationScope = getIsolationScope() as Scope; globalScope.addBreadcrumb(breadcrumb2); globalScope.addEventProcessor(eventProcessor2); diff --git a/packages/opentelemetry/README.md b/packages/opentelemetry/README.md index 7a86456f7b09..593c5a280868 100644 --- a/packages/opentelemetry/README.md +++ b/packages/opentelemetry/README.md @@ -38,7 +38,6 @@ This package exposes a few building blocks you can add to your OpenTelemetry set This is how you can use this in your app: -1. Setup the global hub for OpenTelemetry compatibility - ensure `setupGlobalHub()` is called before anything else! 1. Initialize Sentry, e.g. `@sentry/node` - make sure to set `instrumenter: 'otel'` in the SDK `init({})`! 1. Call `setupEventContextTrace(client)` 1. Add `SentrySampler` as sampler @@ -52,8 +51,6 @@ For example, you could set this up as follows: ```js import * as Sentry from '@sentry/node'; import { - getCurrentHub, - setupGlobalHub, SentryPropagator, SentrySampler, SentrySpanProcessor, @@ -64,14 +61,12 @@ import { import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; function setupSentry() { - setupGlobalHub(); - Sentry.init({ dsn: 'xxx', instrumenter: 'otel' }); - const client = getCurrentHub().getClient(); + const client = Sentry.getClient(); setupEventContextTrace(client); const provider = new BasicTracerProvider({ diff --git a/packages/opentelemetry/src/contextManager.ts b/packages/opentelemetry/src/contextManager.ts index 14c682da9fb4..78065cc31679 100644 --- a/packages/opentelemetry/src/contextManager.ts +++ b/packages/opentelemetry/src/contextManager.ts @@ -1,8 +1,7 @@ import type { Context, ContextManager } from '@opentelemetry/api'; -import type { Hub } from '@sentry/core'; +import { Hub } from '@sentry/core'; import { getCurrentHub } from '@sentry/core'; import { SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY } from './constants'; -import { OpenTelemetryHub } from './custom/hub'; import { setHubOnContext } from './utils/contextData'; @@ -15,14 +14,12 @@ function createNewHub(parent: Hub | undefined, shouldForkIsolationScope: boolean // eslint-disable-next-line deprecation/deprecation const isolationScope = parent.getIsolationScope(); - return new OpenTelemetryHub( - client, - scope.clone(), - shouldForkIsolationScope ? isolationScope.clone() : isolationScope, - ); + // eslint-disable-next-line deprecation/deprecation + return new Hub(client, scope.clone(), shouldForkIsolationScope ? isolationScope.clone() : isolationScope); } - return new OpenTelemetryHub(); + // eslint-disable-next-line deprecation/deprecation + return new Hub(); } // Typescript complains if we do not use `...args: any[]` for the mixin, with: diff --git a/packages/opentelemetry/src/custom/client.ts b/packages/opentelemetry/src/custom/client.ts index 62088f8295f1..b10659bd488a 100644 --- a/packages/opentelemetry/src/custom/client.ts +++ b/packages/opentelemetry/src/custom/client.ts @@ -1,12 +1,11 @@ import type { Tracer } from '@opentelemetry/api'; import { trace } from '@opentelemetry/api'; import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'; -import type { BaseClient, Scope } from '@sentry/core'; +import type { BaseClient } from '@sentry/core'; import { SDK_VERSION } from '@sentry/core'; -import type { CaptureContext, Client, Event, EventHint } from '@sentry/types'; +import type { Client } from '@sentry/types'; import type { OpenTelemetryClient as OpenTelemetryClientInterface } from '../types'; -import { OpenTelemetryScope } from './scope'; // Typescript complains if we do not use `...args: any[]` for the mixin, with: // A mixin class must have a constructor with a single rest parameter of type 'any[]'.ts(2545) @@ -62,35 +61,8 @@ export function wrapClientClass< return super.flush(timeout); } - - /** - * Extends the base `_prepareEvent` so that we can properly handle `captureContext`. - * This uses `Scope.clone()`, which we need to replace with `OpenTelemetryScope.clone()` for this client. - */ - protected _prepareEvent( - event: Event, - hint: EventHint, - scope?: Scope, - isolationScope?: Scope, - ): PromiseLike { - let actualScope = scope; - - // Remove `captureContext` hint and instead clone already here - if (hint && hint.captureContext) { - actualScope = getFinalScope(scope, hint.captureContext); - delete hint.captureContext; - } - - return super._prepareEvent(event, hint, actualScope, isolationScope); - } } return OpenTelemetryClient as unknown as WrappedClassConstructor; } /* eslint-enable @typescript-eslint/no-explicit-any */ - -function getFinalScope(scope: Scope | undefined, captureContext: CaptureContext): Scope | undefined { - const finalScope = scope ? scope.clone() : new OpenTelemetryScope(); - finalScope.update(captureContext); - return finalScope; -} diff --git a/packages/opentelemetry/src/custom/hub.ts b/packages/opentelemetry/src/custom/hub.ts index 74e4c3c7b90e..6a877e3e16ab 100644 --- a/packages/opentelemetry/src/custom/hub.ts +++ b/packages/opentelemetry/src/custom/hub.ts @@ -1,48 +1,8 @@ -import type { Carrier, Scope } from '@sentry/core'; -import { getMainCarrier } from '@sentry/core'; -import { Hub } from '@sentry/core'; -import type { Client } from '@sentry/types'; - -import { OpenTelemetryScope } from './scope'; - /** - * A custom hub that ensures we always creat an OTEL scope. - * Exported only for testing - */ -export class OpenTelemetryHub extends Hub { - public constructor(client?: Client, scope: Scope = new OpenTelemetryScope(), isolationScope?: Scope) { - super(client, scope, isolationScope); - } -} - -/** - * Ensure the global hub is an OpenTelemetryHub. + * Ensure the global hub is setup. + * + * @deprecated This will be removed in the next major version. */ export function setupGlobalHub(): void { - const carrier = getMainCarrier(); - const sentry = getSentryCarrier(carrier); - - // We register a custom hub creator - sentry.createHub = (...options: ConstructorParameters) => { - return new OpenTelemetryHub(...options); - }; - - const hub = sentry.hub; - - if (hub && hub instanceof OpenTelemetryHub) { - return; - } - // If the current global hub is not correct, ensure we overwrite it - sentry.hub = new OpenTelemetryHub(); -} - -/** Will either get the existing sentry carrier, or create a new one. */ -function getSentryCarrier(carrier: Carrier): Carrier['__SENTRY__'] & object { - if (!carrier.__SENTRY__) { - carrier.__SENTRY__ = { - extensions: {}, - hub: undefined, - }; - } - return carrier.__SENTRY__; + // noop } diff --git a/packages/opentelemetry/src/custom/scope.ts b/packages/opentelemetry/src/custom/scope.ts deleted file mode 100644 index f686ecbc5c34..000000000000 --- a/packages/opentelemetry/src/custom/scope.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Scope } from '@sentry/core'; -import type { Span as SentrySpan } from '@sentry/types'; -import { logger } from '@sentry/utils'; - -import { DEBUG_BUILD } from '../debug-build'; - -/** A fork of the classic scope with some otel specific stuff. */ -export class OpenTelemetryScope extends Scope { - /** - * @inheritDoc - */ - public static clone(scope?: Scope): Scope { - return scope ? scope.clone() : new OpenTelemetryScope(); - } - - /** - * Clone this scope instance. - */ - public clone(): OpenTelemetryScope { - const newScope = new OpenTelemetryScope(); - newScope._breadcrumbs = [...this['_breadcrumbs']]; - newScope._tags = { ...this['_tags'] }; - newScope._extra = { ...this['_extra'] }; - newScope._contexts = { ...this['_contexts'] }; - newScope._user = this['_user']; - newScope._level = this['_level']; - newScope._span = this['_span']; - newScope._session = this['_session']; - newScope._transactionName = this['_transactionName']; - newScope._fingerprint = this['_fingerprint']; - newScope._eventProcessors = [...this['_eventProcessors']]; - newScope._requestSession = this['_requestSession']; - newScope._attachments = [...this['_attachments']]; - newScope._sdkProcessingMetadata = { ...this['_sdkProcessingMetadata'] }; - newScope._propagationContext = { ...this['_propagationContext'] }; - newScope._client = this._client; - - return newScope; - } - - /** - * In node-experimental, scope.getSpan() always returns undefined. - * Instead, use the global `getActiveSpan()`. - */ - public getSpan(): undefined { - DEBUG_BUILD && logger.warn('Calling getSpan() is a noop in @sentry/opentelemetry. Use `getActiveSpan()` instead.'); - - return undefined; - } - - /** - * In node-experimental, scope.setSpan() is a noop. - * Instead, use the global `startSpan()` to define the active span. - */ - public setSpan(_span: SentrySpan): this { - DEBUG_BUILD && logger.warn('Calling setSpan() is a noop in @sentry/opentelemetry. Use `startSpan()` instead.'); - - return this; - } -} diff --git a/packages/opentelemetry/src/index.ts b/packages/opentelemetry/src/index.ts index f0b43ab8a386..4c3211ebd23c 100644 --- a/packages/opentelemetry/src/index.ts +++ b/packages/opentelemetry/src/index.ts @@ -30,8 +30,8 @@ export { isSentryRequestSpan } from './utils/isSentryRequest'; export { getActiveSpan, getRootSpan } from './utils/getActiveSpan'; export { startSpan, startSpanManual, startInactiveSpan } from './trace'; +// eslint-disable-next-line deprecation/deprecation export { setupGlobalHub } from './custom/hub'; -export { OpenTelemetryScope } from './custom/scope'; export { addTracingExtensions } from './custom/hubextensions'; export { setupEventContextTrace } from './setupEventContextTrace'; diff --git a/packages/opentelemetry/src/spanProcessor.ts b/packages/opentelemetry/src/spanProcessor.ts index 6a68d1fbce1c..fa40748c5c9c 100644 --- a/packages/opentelemetry/src/spanProcessor.ts +++ b/packages/opentelemetry/src/spanProcessor.ts @@ -5,14 +5,13 @@ import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; import { getCurrentHub } from '@sentry/core'; import { logger } from '@sentry/utils'; -import { OpenTelemetryScope } from './custom/scope'; import { DEBUG_BUILD } from './debug-build'; import { SentrySpanExporter } from './spanExporter'; import { maybeCaptureExceptionForTimedEvent } from './utils/captureExceptionForTimedEvent'; import { getHubFromContext } from './utils/contextData'; import { getSpanHub, setSpanHub, setSpanParent, setSpanScopes } from './utils/spanData'; -function onSpanStart(span: Span, parentContext: Context, _ScopeClass: typeof OpenTelemetryScope): void { +function onSpanStart(span: Span, parentContext: Context): void { // This is a reliable way to get the parent span - because this is exactly how the parent is identified in the OTEL SDK const parentSpan = trace.getSpan(parentContext); const hub = getHubFromContext(parentContext); @@ -55,19 +54,15 @@ function onSpanEnd(span: Span): void { * the Sentry SDK. */ export class SentrySpanProcessor extends BatchSpanProcessor implements SpanProcessorInterface { - private _scopeClass: typeof OpenTelemetryScope; - - public constructor(options: { scopeClass?: typeof OpenTelemetryScope } = {}) { + public constructor() { super(new SentrySpanExporter()); - - this._scopeClass = options.scopeClass || OpenTelemetryScope; } /** * @inheritDoc */ public onStart(span: Span, parentContext: Context): void { - onSpanStart(span, parentContext, this._scopeClass); + onSpanStart(span, parentContext); DEBUG_BUILD && logger.log(`[Tracing] Starting span "${span.name}" (${span.spanContext().spanId})`); diff --git a/packages/opentelemetry/test/custom/hub.test.ts b/packages/opentelemetry/test/custom/hub.test.ts deleted file mode 100644 index f3b62e2d1507..000000000000 --- a/packages/opentelemetry/test/custom/hub.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { getCurrentHub } from '@sentry/core'; -import { OpenTelemetryHub, setupGlobalHub } from '../../src/custom/hub'; -import { OpenTelemetryScope } from '../../src/custom/scope'; - -describe('OpenTelemetryHub', () => { - beforeEach(() => { - setupGlobalHub(); - }); - - it('getCurrentHub() returns the correct hub', () => { - // eslint-disable-next-line deprecation/deprecation - const hub = getCurrentHub(); - expect(hub).toBeDefined(); - expect(hub).toBeInstanceOf(OpenTelemetryHub); - - // eslint-disable-next-line deprecation/deprecation - const hub2 = getCurrentHub(); - expect(hub2).toBe(hub); - - // eslint-disable-next-line deprecation/deprecation - const scope = hub.getScope(); - expect(scope).toBeDefined(); - expect(scope).toBeInstanceOf(OpenTelemetryScope); - }); - - it('hub gets correct scope on initialization', () => { - const hub = new OpenTelemetryHub(); - - // eslint-disable-next-line deprecation/deprecation - const scope = hub.getScope(); - expect(scope).toBeDefined(); - expect(scope).toBeInstanceOf(OpenTelemetryScope); - }); - - it('pushScope() creates correct scope', () => { - const hub = new OpenTelemetryHub(); - - // eslint-disable-next-line deprecation/deprecation - const scope = hub.pushScope(); - expect(scope).toBeInstanceOf(OpenTelemetryScope); - - // eslint-disable-next-line deprecation/deprecation - const scope2 = hub.getScope(); - expect(scope2).toBe(scope); - }); - - it('withScope() creates correct scope', () => { - const hub = new OpenTelemetryHub(); - - // eslint-disable-next-line deprecation/deprecation - hub.withScope(scope => { - expect(scope).toBeInstanceOf(OpenTelemetryScope); - }); - }); -}); diff --git a/packages/opentelemetry/test/custom/scope.test.ts b/packages/opentelemetry/test/custom/scope.test.ts deleted file mode 100644 index 978e68e2df85..000000000000 --- a/packages/opentelemetry/test/custom/scope.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { makeSession } from '@sentry/core'; - -import { OpenTelemetryScope } from '../../src/custom/scope'; - -describe('NodeExperimentalScope', () => { - afterEach(() => { - jest.resetAllMocks(); - }); - - it('clone() correctly clones the scope', () => { - const scope = new OpenTelemetryScope(); - - scope['_breadcrumbs'] = [{ message: 'test' }]; - scope['_tags'] = { tag: 'bar' }; - scope['_extra'] = { extra: 'bar' }; - scope['_contexts'] = { os: { name: 'Linux' } }; - scope['_user'] = { id: '123' }; - scope['_level'] = 'warning'; - // we don't care about _span - scope['_session'] = makeSession({ sid: '123' }); - // we don't care about transactionName - scope['_fingerprint'] = ['foo']; - scope['_eventProcessors'] = [() => ({})]; - scope['_requestSession'] = { status: 'ok' }; - scope['_attachments'] = [{ data: '123', filename: 'test.txt' }]; - scope['_sdkProcessingMetadata'] = { sdk: 'bar' }; - - // eslint-disable-next-line deprecation/deprecation - const scope2 = OpenTelemetryScope.clone(scope); - - expect(scope2).toBeInstanceOf(OpenTelemetryScope); - expect(scope2).not.toBe(scope); - - // Ensure everything is correctly cloned - expect(scope2['_breadcrumbs']).toEqual(scope['_breadcrumbs']); - expect(scope2['_tags']).toEqual(scope['_tags']); - expect(scope2['_extra']).toEqual(scope['_extra']); - expect(scope2['_contexts']).toEqual(scope['_contexts']); - expect(scope2['_user']).toEqual(scope['_user']); - expect(scope2['_level']).toEqual(scope['_level']); - expect(scope2['_session']).toEqual(scope['_session']); - expect(scope2['_fingerprint']).toEqual(scope['_fingerprint']); - expect(scope2['_eventProcessors']).toEqual(scope['_eventProcessors']); - expect(scope2['_requestSession']).toEqual(scope['_requestSession']); - expect(scope2['_attachments']).toEqual(scope['_attachments']); - expect(scope2['_sdkProcessingMetadata']).toEqual(scope['_sdkProcessingMetadata']); - expect(scope2['_propagationContext']).toEqual(scope['_propagationContext']); - - // Ensure things are not copied by reference - expect(scope2['_breadcrumbs']).not.toBe(scope['_breadcrumbs']); - expect(scope2['_tags']).not.toBe(scope['_tags']); - expect(scope2['_extra']).not.toBe(scope['_extra']); - expect(scope2['_contexts']).not.toBe(scope['_contexts']); - expect(scope2['_eventProcessors']).not.toBe(scope['_eventProcessors']); - expect(scope2['_attachments']).not.toBe(scope['_attachments']); - expect(scope2['_sdkProcessingMetadata']).not.toBe(scope['_sdkProcessingMetadata']); - expect(scope2['_propagationContext']).not.toBe(scope['_propagationContext']); - - // These are actually copied by reference - expect(scope2['_user']).toBe(scope['_user']); - expect(scope2['_session']).toBe(scope['_session']); - expect(scope2['_requestSession']).toBe(scope['_requestSession']); - expect(scope2['_fingerprint']).toBe(scope['_fingerprint']); - }); - - it('clone() works without existing scope', () => { - // eslint-disable-next-line deprecation/deprecation - const scope = OpenTelemetryScope.clone(undefined); - - expect(scope).toBeInstanceOf(OpenTelemetryScope); - }); - - it('getSpan returns undefined', () => { - const scope = new OpenTelemetryScope(); - - // Pretend we have a _span set - scope['_span'] = {} as any; - - // eslint-disable-next-line deprecation/deprecation - expect(scope.getSpan()).toBeUndefined(); - }); - - it('setSpan is a noop', () => { - const scope = new OpenTelemetryScope(); - - // eslint-disable-next-line deprecation/deprecation - scope.setSpan({} as any); - - expect(scope['_span']).toBeUndefined(); - }); -}); diff --git a/packages/opentelemetry/test/helpers/mockSdkInit.ts b/packages/opentelemetry/test/helpers/mockSdkInit.ts index cc5a4e11c5e6..cf362c731fe4 100644 --- a/packages/opentelemetry/test/helpers/mockSdkInit.ts +++ b/packages/opentelemetry/test/helpers/mockSdkInit.ts @@ -4,7 +4,6 @@ import type { ClientOptions, Options } from '@sentry/types'; import { GLOBAL_OBJ } from '@sentry/utils'; import { setOpenTelemetryContextAsyncContextStrategy } from '../../src/asyncContextStrategy'; -import { setupGlobalHub } from '../../src/custom/hub'; import { init as initTestClient } from './TestClient'; import { initOtel } from './initOtel'; @@ -14,8 +13,6 @@ const PUBLIC_DSN = 'https://username@domain/123'; * Initialize Sentry for Node. */ function init(options: Partial | undefined = {}): void { - setupGlobalHub(); - const fullOptions: Partial = { instrumenter: 'otel', ...options, diff --git a/packages/opentelemetry/test/integration/breadcrumbs.test.ts b/packages/opentelemetry/test/integration/breadcrumbs.test.ts index 6a745855251b..9da0f4d6e240 100644 --- a/packages/opentelemetry/test/integration/breadcrumbs.test.ts +++ b/packages/opentelemetry/test/integration/breadcrumbs.test.ts @@ -1,6 +1,5 @@ -import { addBreadcrumb, captureException, getClient, getCurrentHub, withIsolationScope, withScope } from '@sentry/core'; +import { addBreadcrumb, captureException, getClient, withIsolationScope, withScope } from '@sentry/core'; -import { OpenTelemetryHub } from '../../src/custom/hub'; import { startSpan } from '../../src/trace'; import type { TestClientInterface } from '../helpers/TestClient'; import { cleanupOtel, mockSdkInit } from '../helpers/mockSdkInit'; @@ -19,18 +18,13 @@ describe('Integration | breadcrumbs', () => { mockSdkInit({ beforeSend, beforeBreadcrumb }); - // eslint-disable-next-line deprecation/deprecation - const hub = getCurrentHub(); const client = getClient() as TestClientInterface; - expect(hub).toBeInstanceOf(OpenTelemetryHub); - addBreadcrumb({ timestamp: 123456, message: 'test1' }); addBreadcrumb({ timestamp: 123457, message: 'test2', data: { nested: 'yes' } }); addBreadcrumb({ timestamp: 123455, message: 'test3' }); const error = new Error('test'); - // eslint-disable-next-line deprecation/deprecation captureException(error); await client.flush(); @@ -60,12 +54,8 @@ describe('Integration | breadcrumbs', () => { mockSdkInit({ beforeSend, beforeBreadcrumb }); - // eslint-disable-next-line deprecation/deprecation - const hub = getCurrentHub(); const client = getClient() as TestClientInterface; - expect(hub).toBeInstanceOf(OpenTelemetryHub); - const error = new Error('test'); addBreadcrumb({ timestamp: 123456, message: 'test0' }); @@ -76,7 +66,6 @@ describe('Integration | breadcrumbs', () => { withIsolationScope(() => { addBreadcrumb({ timestamp: 123456, message: 'test2' }); - // eslint-disable-next-line deprecation/deprecation captureException(error); }); diff --git a/packages/opentelemetry/test/integration/otelTimedEvents.test.ts b/packages/opentelemetry/test/integration/otelTimedEvents.test.ts index ab360d74b9e1..f0e0fc109c80 100644 --- a/packages/opentelemetry/test/integration/otelTimedEvents.test.ts +++ b/packages/opentelemetry/test/integration/otelTimedEvents.test.ts @@ -48,6 +48,7 @@ describe('Integration | OTEL TimedEvents', () => { event_id: expect.any(String), originalException: expect.any(Error), syntheticException: expect.any(Error), + captureContext: expect.any(Object), }, ); }); diff --git a/packages/opentelemetry/test/integration/scope.test.ts b/packages/opentelemetry/test/integration/scope.test.ts index 6b61fd42c34c..cc4def42ddbc 100644 --- a/packages/opentelemetry/test/integration/scope.test.ts +++ b/packages/opentelemetry/test/integration/scope.test.ts @@ -1,7 +1,6 @@ import { captureException, getClient, - getCurrentHub, getCurrentScope, getIsolationScope, setTag, @@ -9,8 +8,6 @@ import { withScope, } from '@sentry/core'; -import { OpenTelemetryHub } from '../../src/custom/hub'; -import { OpenTelemetryScope } from '../../src/custom/scope'; import { startSpan } from '../../src/trace'; import { getSpanScopes } from '../../src/utils/spanData'; import type { TestClientInterface } from '../helpers/TestClient'; @@ -31,15 +28,10 @@ describe('Integration | Scope', () => { mockSdkInit({ enableTracing, beforeSend, beforeSendTransaction }); - // eslint-disable-next-line deprecation/deprecation - const hub = getCurrentHub(); const client = getClient() as TestClientInterface; const rootScope = getCurrentScope(); - expect(hub).toBeInstanceOf(OpenTelemetryHub); - expect(rootScope).toBeInstanceOf(OpenTelemetryScope); - const error = new Error('test error'); let spanId: string | undefined; let traceId: string | undefined; @@ -140,14 +132,9 @@ describe('Integration | Scope', () => { mockSdkInit({ enableTracing, beforeSend, beforeSendTransaction }); - // eslint-disable-next-line deprecation/deprecation - const hub = getCurrentHub(); const client = getClient() as TestClientInterface; const rootScope = getCurrentScope(); - expect(hub).toBeInstanceOf(OpenTelemetryHub); - expect(rootScope).toBeInstanceOf(OpenTelemetryScope); - const error1 = new Error('test error 1'); const error2 = new Error('test error 2'); let spanId1: string | undefined; @@ -264,14 +251,9 @@ describe('Integration | Scope', () => { mockSdkInit({ enableTracing, beforeSend, beforeSendTransaction }); - // eslint-disable-next-line deprecation/deprecation - const hub = getCurrentHub(); const client = getClient() as TestClientInterface; const rootScope = getCurrentScope(); - expect(hub).toBeInstanceOf(OpenTelemetryHub); - expect(rootScope).toBeInstanceOf(OpenTelemetryScope); - const error1 = new Error('test error 1'); const error2 = new Error('test error 2'); let spanId1: string | undefined; diff --git a/packages/opentelemetry/test/utils/setupEventContextTrace.test.ts b/packages/opentelemetry/test/utils/setupEventContextTrace.test.ts index 3490e03fedd1..5d074a1c4ea2 100644 --- a/packages/opentelemetry/test/utils/setupEventContextTrace.test.ts +++ b/packages/opentelemetry/test/utils/setupEventContextTrace.test.ts @@ -1,7 +1,6 @@ import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'; -import { makeMain } from '@sentry/core'; +import { captureException, setCurrentClient } from '@sentry/core'; -import { OpenTelemetryHub } from '../../src/custom/hub'; import { setupEventContextTrace } from '../../src/setupEventContextTrace'; import type { TestClientInterface } from '../helpers/TestClient'; import { TestClient, getDefaultTestClientOptions } from '../helpers/TestClient'; @@ -13,7 +12,6 @@ const PUBLIC_DSN = 'https://username@domain/123'; describe('setupEventContextTrace', () => { const beforeSend = jest.fn(() => null); let client: TestClientInterface; - let hub: OpenTelemetryHub; let provider: BasicTracerProvider | undefined; beforeEach(() => { @@ -27,9 +25,8 @@ describe('setupEventContextTrace', () => { }), ); - hub = new OpenTelemetryHub(client); - // eslint-disable-next-line deprecation/deprecation - makeMain(hub); + setCurrentClient(client); + client.init(); setupEventContextTrace(client); provider = setupOtel(client); @@ -46,8 +43,7 @@ describe('setupEventContextTrace', () => { it('works with no active span', async () => { const error = new Error('test'); - // eslint-disable-next-line deprecation/deprecation - hub.captureException(error); + captureException(error); await client.flush(); expect(beforeSend).toHaveBeenCalledTimes(1); @@ -81,8 +77,7 @@ describe('setupEventContextTrace', () => { client.tracer.startActiveSpan('inner', innerSpan => { innerId = innerSpan?.spanContext().spanId; - // eslint-disable-next-line deprecation/deprecation - hub.captureException(error); + captureException(error); }); }); diff --git a/packages/types/src/scope.ts b/packages/types/src/scope.ts index 2a6d01f7caa0..2f9fb9149479 100644 --- a/packages/types/src/scope.ts +++ b/packages/types/src/scope.ts @@ -259,4 +259,9 @@ export interface Scope { * @returns the id of the captured event. */ captureEvent(event: Event, hint?: EventHint): string; + + /** + * Clone all data from this scope into a new scope. + */ + clone(): Scope; }