Skip to content

Commit 94cfae2

Browse files
committed
Add otel contextManager & use it for hub management
1 parent 4f19e32 commit 94cfae2

File tree

6 files changed

+62
-25
lines changed

6 files changed

+62
-25
lines changed

packages/node-experimental/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@opentelemetry/instrumentation-pg": "~0.36.0",
3838
"@opentelemetry/sdk-trace-node": "~1.15.0",
3939
"@opentelemetry/semantic-conventions": "~1.15.0",
40+
"@opentelemetry/context-async-hooks": "~1.15.0",
4041
"@prisma/instrumentation": "~5.0.0",
4142
"@sentry/core": "7.66.0",
4243
"@sentry/node": "7.66.0",

packages/node-experimental/src/sdk/init.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Http } from '../integrations/http';
66
import type { NodeExperimentalOptions } from '../types';
77
import { NodeExperimentalClient } from './client';
88
import { initOtel } from './initOtel';
9+
import { setOtelContextAsyncContextStrategy } from './otelAsyncContextStrategy';
910

1011
const ignoredDefaultIntegrations = ['Http', 'Undici'];
1112

@@ -35,4 +36,5 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
3536

3637
// Always init Otel, even if tracing is disabled, because we need it for trace propagation & the HTTP integration
3738
initOtel();
39+
setOtelContextAsyncContextStrategy();
3840
}

packages/node-experimental/src/sdk/initOtel.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { getCurrentHub } from '@sentry/core';
44
import { SentryPropagator, SentrySpanProcessor } from '@sentry/opentelemetry-node';
55

66
import type { NodeExperimentalClient } from './client';
7-
import { setOtelContextAsyncContextStrategy } from './otelContextAsyncContextStrategy';
7+
import { SentryContextManager } from './otelContextManager';
88

99
/**
1010
* Initialize OpenTelemetry for Node.
@@ -23,13 +23,16 @@ export function initOtel(): () => void {
2323
});
2424
provider.addSpanProcessor(new SentrySpanProcessor());
2525

26+
// We use a custom context manager to keep context in sync with sentry scope
27+
const contextManager = new SentryContextManager();
28+
contextManager.enable();
29+
2630
// Initialize the provider
2731
provider.register({
2832
propagator: new SentryPropagator(),
33+
contextManager,
2934
});
3035

31-
setOtelContextAsyncContextStrategy();
32-
3336
// Cleanup function
3437
return () => {
3538
void provider.forceFlush();

packages/node-experimental/src/sdk/otelContextAsyncContextStrategy.ts renamed to packages/node-experimental/src/sdk/otelAsyncContextStrategy.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import * as api from '@opentelemetry/api';
2-
import type { Carrier, Hub, RunWithAsyncContextOptions } from '@sentry/core';
3-
import { ensureHubOnCarrier, getHubFromCarrier, setAsyncContextStrategy } from '@sentry/core';
2+
import type { Hub, RunWithAsyncContextOptions } from '@sentry/core';
3+
import { setAsyncContextStrategy } from '@sentry/core';
44

5-
const hubKey = api.createContextKey('sentry_hub');
5+
import { OTEL_CONTEXT_HUB_KEY } from './otelContextManager';
66

77
/**
88
* Sets the async context strategy to use follow the OTEL context under the hood.
@@ -12,15 +12,10 @@ export function setOtelContextAsyncContextStrategy(): void {
1212
const ctx = api.context.active();
1313

1414
// Returning undefined means the global hub will be used
15-
return ctx.getValue(hubKey) as Hub | undefined;
16-
}
17-
18-
function createNewHub(parent: Hub | undefined): Hub {
19-
const carrier: Carrier = {};
20-
ensureHubOnCarrier(carrier, parent);
21-
return getHubFromCarrier(carrier);
15+
return ctx.getValue(OTEL_CONTEXT_HUB_KEY) as Hub | undefined;
2216
}
2317

18+
/* This is more or less a NOOP - we rely on the OTEL context manager for this */
2419
function runWithAsyncContext<T>(callback: () => T, options: RunWithAsyncContextOptions): T {
2520
const existingHub = getCurrentHub();
2621

@@ -30,11 +25,10 @@ export function setOtelContextAsyncContextStrategy(): void {
3025
return callback();
3126
}
3227

33-
const newHub = createNewHub(existingHub);
34-
3528
const ctx = api.context.active();
3629

37-
return api.context.with(ctx.setValue(hubKey, newHub), () => {
30+
// We depend on the otelContextManager to handle the context/hub
31+
return api.context.with(ctx, () => {
3832
return callback();
3933
});
4034
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type { Context } from '@opentelemetry/api';
2+
import * as api from '@opentelemetry/api';
3+
import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
4+
import type { Carrier, Hub } from '@sentry/core';
5+
import { ensureHubOnCarrier, getCurrentHub, getHubFromCarrier } from '@sentry/core';
6+
7+
export const OTEL_CONTEXT_HUB_KEY = api.createContextKey('sentry_hub');
8+
9+
function createNewHub(parent: Hub | undefined): Hub {
10+
const carrier: Carrier = {};
11+
ensureHubOnCarrier(carrier, parent);
12+
return getHubFromCarrier(carrier);
13+
}
14+
15+
/** TODO docs */
16+
export class SentryContextManager extends AsyncLocalStorageContextManager {
17+
/**
18+
* Overwrite with() of the original AsyncLocalStorageContextManager
19+
* to ensure we also create a new hub per context.
20+
*/
21+
public with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(
22+
context: Context,
23+
fn: F,
24+
thisArg?: ThisParameterType<F>,
25+
...args: A
26+
): ReturnType<F> {
27+
const existingHub = getCurrentHub();
28+
const newHub = createNewHub(existingHub);
29+
30+
return super.with(context.setValue(OTEL_CONTEXT_HUB_KEY, newHub), fn, thisArg, ...args);
31+
}
32+
}

yarn.lock

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3733,6 +3733,11 @@
37333733
dependencies:
37343734
tslib "^2.3.1"
37353735

3736+
"@opentelemetry/context-async-hooks@~1.15.0":
3737+
version "1.15.2"
3738+
resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-1.15.2.tgz#116bd5fef231137198d5bf551e8c0521fbdfe928"
3739+
integrity sha512-VAMHG67srGFQDG/N2ns5AyUT9vUcoKpZ/NpJ5fDQIPfJd7t3ju+aHwvDsMcrYBWuCh03U3Ky6o16+872CZchBg==
3740+
37363741
"@opentelemetry/context-base@^0.12.0":
37373742
version "0.12.0"
37383743
resolved "https://registry.yarnpkg.com/@opentelemetry/context-base/-/context-base-0.12.0.tgz#4906ae27359d3311e3dea1b63770a16f60848550"
@@ -4414,10 +4419,10 @@
44144419
fflate "^0.4.4"
44154420
mitt "^1.1.3"
44164421

4417-
"@sentry/bundler-plugin-core@0.6.0":
4418-
version "0.6.0"
4419-
resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-0.6.0.tgz#70ad3740b2f90cdca1aff5fdbcd7306566a2f51e"
4420-
integrity sha512-gDPBkFxiOkc525U9pxnGMI5B2DAG0+UCsNuiNgl9+AieDcPSYTwdzfGHytxDZrQgPMvIHEnTAp1VlNB+6UxUGQ==
4422+
"@sentry/bundler-plugin-core@0.6.1":
4423+
version "0.6.1"
4424+
resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-0.6.1.tgz#6c6a2ff3cdc98cd0ff1c30c59408cee9f067adf2"
4425+
integrity sha512-EecCJKp9ERM7J93DNDJTvkY78UiD/IfOjBdXWnaUVE0n619O7LfMVjwlXzxRJKl2x05dBE3lDraILLDGxCf6fg==
44214426
dependencies:
44224427
"@sentry/cli" "^2.17.0"
44234428
"@sentry/node" "^7.19.0"
@@ -4463,12 +4468,12 @@
44634468
proxy-from-env "^1.1.0"
44644469
which "^2.0.2"
44654470

4466-
"@sentry/vite-plugin@^0.6.0":
4467-
version "0.6.0"
4468-
resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-0.6.0.tgz#3902a5224d52b06d753a1deeb6b722bf6523840c"
4469-
integrity sha512-3J1ESvbI5okGJaSWm+gTAOOIa96u4ZwfI/C3n+0HSStz3e4vGiGUh59iNyb1/2m5HFgR5OLaHNfAvlyP8GM/ew==
4471+
"@sentry/vite-plugin@^0.6.1":
4472+
version "0.6.1"
4473+
resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-0.6.1.tgz#31eb744e8d87b1528eed8d41433647727a62e7c0"
4474+
integrity sha512-qkvKaSOcNhNWcdxRXLSs+8cF3ey0XIRmEzTl8U7sTTcZwuOMHsJB+HsYij6aTGaqsKfP8w1ozVt9szBAiL4//w==
44704475
dependencies:
4471-
"@sentry/bundler-plugin-core" "0.6.0"
4476+
"@sentry/bundler-plugin-core" "0.6.1"
44724477

44734478
"@sentry/webpack-plugin@1.19.0":
44744479
version "1.19.0"

0 commit comments

Comments
 (0)