Skip to content

feat(core): Streamline custom hub creation for node-experimental #10555

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 72 additions & 42 deletions packages/core/src/hub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,7 @@ import type {
TransactionContext,
User,
} from '@sentry/types';
import {
GLOBAL_OBJ,
consoleSandbox,
dateTimestampInSeconds,
getGlobalSingleton,
isThenable,
logger,
uuid4,
} from '@sentry/utils';
import { GLOBAL_OBJ, consoleSandbox, dateTimestampInSeconds, isThenable, logger, uuid4 } from '@sentry/utils';

import { DEFAULT_ENVIRONMENT } from './constants';
import { DEBUG_BUILD } from './debug-build';
Expand Down Expand Up @@ -87,21 +79,41 @@ export interface Layer {
* @hidden
*/
export interface Carrier {
__SENTRY__?: {
hub?: Hub;
acs?: AsyncContextStrategy;
/**
* Extra Hub properties injected by various SDKs
*/
integrations?: Integration[];
extensions?: {
/** Extension methods for the hub, which are bound to the current Hub instance */
// eslint-disable-next-line @typescript-eslint/ban-types
[key: string]: Function;
};
__SENTRY__?: SentryCarrier;
}

type CreateHub = (...options: ConstructorParameters<typeof Hub>) => Hub;

interface SentryCarrier {
hub?: Hub;
createHub?: CreateHub;
acs?: AsyncContextStrategy;
/**
* Extra Hub properties injected by various SDKs
*/
integrations?: Integration[];
extensions?: {
/** Extension methods for the hub, which are bound to the current Hub instance */
// eslint-disable-next-line @typescript-eslint/ban-types
[key: string]: Function;
};
}

/**
* Create a hub. If a custom `createHub` is registered on the main carrier, use that instead.
* This only exists to make POTEL migration easier.
*/
function createHub(...options: ConstructorParameters<typeof Hub>): Hub {
const carrier = getMainCarrier();
const sentry = getSentryCarrier(carrier);

if (sentry.createHub) {
return sentry.createHub(...options);
}

return new Hub(...options);
}

/**
* @inheritDoc
*/
Expand Down Expand Up @@ -669,8 +681,8 @@ Sentry.init({...});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private _callExtensionMethod<T>(method: string, ...args: any[]): T {
const carrier = getMainCarrier();
const sentry = carrier.__SENTRY__;
if (sentry && sentry.extensions && typeof sentry.extensions[method] === 'function') {
const sentry = getSentryCarrier(carrier);
if (sentry.extensions && typeof sentry.extensions[method] === 'function') {
return sentry.extensions[method].apply(this, args);
}
DEBUG_BUILD && logger.warn(`Extension method ${method} couldn't be found, doing nothing.`);
Expand All @@ -685,10 +697,8 @@ Sentry.init({...});
* at the call-site. We always access the carrier through this function, so we can guarantee that `__SENTRY__` is there.
**/
export function getMainCarrier(): Carrier {
GLOBAL_OBJ.__SENTRY__ = GLOBAL_OBJ.__SENTRY__ || {
extensions: {},
hub: undefined,
};
// This ensures a Sentry carrier exists
getSentryCarrier(GLOBAL_OBJ);
return GLOBAL_OBJ;
}

Expand Down Expand Up @@ -717,18 +727,19 @@ export function makeMain(hub: Hub): Hub {
*/
export function getCurrentHub(): Hub {
// Get main carrier (global for every environment)
const registry = getMainCarrier();
const carrier = getMainCarrier();
const sentry = getSentryCarrier(carrier);

if (registry.__SENTRY__ && registry.__SENTRY__.acs) {
const hub = registry.__SENTRY__.acs.getCurrentHub();
if (sentry.acs) {
const hub = sentry.acs.getCurrentHub();

if (hub) {
return hub;
}
}

// Return hub that lives on a global object
return getGlobalHub(registry);
return getGlobalHub();
}

/**
Expand All @@ -741,15 +752,17 @@ export function getIsolationScope(): Scope {
return getCurrentHub().getIsolationScope();
}

function getGlobalHub(registry: Carrier = getMainCarrier()): Hub {
function getGlobalHub(): Hub {
const registry = getMainCarrier();

// If there's no hub, or its an old API, assign a new one

if (
!hasHubOnCarrier(registry) ||
// eslint-disable-next-line deprecation/deprecation
getHubFromCarrier(registry).isOlderThan(API_VERSION)
) {
setHubOnCarrier(registry, new Hub());
setHubOnCarrier(registry, createHub());
}

// Return hub that lives on a global object
Expand All @@ -774,7 +787,7 @@ export function ensureHubOnCarrier(carrier: Carrier, parent: Hub = getGlobalHub(
const scope = parent.getScope();
// eslint-disable-next-line deprecation/deprecation
const isolationScope = parent.getIsolationScope();
setHubOnCarrier(carrier, new Hub(client, scope.clone(), isolationScope.clone()));
setHubOnCarrier(carrier, createHub(client, scope.clone(), isolationScope.clone()));
}
}

Expand All @@ -786,8 +799,8 @@ export function ensureHubOnCarrier(carrier: Carrier, parent: Hub = getGlobalHub(
export function setAsyncContextStrategy(strategy: AsyncContextStrategy | undefined): void {
// Get main carrier (global for every environment)
const registry = getMainCarrier();
registry.__SENTRY__ = registry.__SENTRY__ || {};
registry.__SENTRY__.acs = strategy;
const sentry = getSentryCarrier(registry);
sentry.acs = strategy;
}

/**
Expand All @@ -799,9 +812,10 @@ export function setAsyncContextStrategy(strategy: AsyncContextStrategy | undefin
*/
export function runWithAsyncContext<T>(callback: () => T, options: RunWithAsyncContextOptions = {}): T {
const registry = getMainCarrier();
const sentry = getSentryCarrier(registry);

if (registry.__SENTRY__ && registry.__SENTRY__.acs) {
return registry.__SENTRY__.acs.runWithAsyncContext(callback, options);
if (sentry.acs) {
return sentry.acs.runWithAsyncContext(callback, options);
}

// if there was no strategy, fallback to just calling the callback
Expand All @@ -813,7 +827,7 @@ export function runWithAsyncContext<T>(callback: () => T, options: RunWithAsyncC
* @param carrier object
*/
function hasHubOnCarrier(carrier: Carrier): boolean {
return !!(carrier && carrier.__SENTRY__ && carrier.__SENTRY__.hub);
return !!getSentryCarrier(carrier).hub;
}

/**
Expand All @@ -823,7 +837,12 @@ function hasHubOnCarrier(carrier: Carrier): boolean {
* @hidden
*/
export function getHubFromCarrier(carrier: Carrier): Hub {
return getGlobalSingleton<Hub>('hub', () => new Hub(), carrier);
const sentry = getSentryCarrier(carrier);
if (!sentry.hub) {
sentry.hub = createHub();
}

return sentry.hub;
}

/**
Expand All @@ -834,7 +853,18 @@ export function getHubFromCarrier(carrier: Carrier): Hub {
*/
export function setHubOnCarrier(carrier: Carrier, hub: Hub): boolean {
if (!carrier) return false;
const __SENTRY__ = (carrier.__SENTRY__ = carrier.__SENTRY__ || {});
__SENTRY__.hub = hub;
const sentry = getSentryCarrier(carrier);
sentry.hub = hub;
return true;
}

/** Will either get the existing sentry carrier, or create a new one. */
function getSentryCarrier(carrier: Carrier): SentryCarrier {
if (!carrier.__SENTRY__) {
carrier.__SENTRY__ = {
extensions: {},
hub: undefined,
};
}
return carrier.__SENTRY__;
}
3 changes: 2 additions & 1 deletion packages/opentelemetry/src/contextManager.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Context, ContextManager } from '@opentelemetry/api';
import type { Carrier, Hub } from '@sentry/core';
import { getCurrentHub, getHubFromCarrier } from '@sentry/core';
import { ensureHubOnCarrier } from '@sentry/core';

import { getCurrentHub, getHubFromCarrier } from './custom/hub';
import { setHubOnContext } from './utils/contextData';

function createNewHub(parent: Hub | undefined): Hub {
Expand Down Expand Up @@ -46,6 +46,7 @@ export function wrapContextManagerClass<ContextManagerInstance extends ContextMa
thisArg?: ThisParameterType<F>,
...args: A
): ReturnType<F> {
// eslint-disable-next-line deprecation/deprecation
const existingHub = getCurrentHub();
const newHub = createNewHub(existingHub);

Expand Down
Loading