-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathtracingUtils.ts
110 lines (99 loc) · 4.02 KB
/
tracingUtils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import type { PropagationContext } from '@sentry/core';
import { GLOBAL_OBJ, Scope, getActiveSpan, getRootSpan, logger, spanToJSON, startNewTrace } from '@sentry/core';
import { DEBUG_BUILD } from '../debug-build';
import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from '../span-attributes-with-logic-attached';
const commonPropagationContextMap = new WeakMap<object, PropagationContext>();
/**
* Takes a shared (garbage collectable) object between resources, e.g. a headers object shared between Next.js server components and returns a common propagation context.
*
* @param commonObject The shared object.
* @param propagationContext The propagation context that should be shared between all the resources if no propagation context was registered yet.
* @returns the shared propagation context.
*/
export function commonObjectToPropagationContext(
commonObject: unknown,
propagationContext: PropagationContext,
): PropagationContext {
if (typeof commonObject === 'object' && commonObject) {
const memoPropagationContext = commonPropagationContextMap.get(commonObject);
if (memoPropagationContext) {
return memoPropagationContext;
} else {
commonPropagationContextMap.set(commonObject, propagationContext);
return propagationContext;
}
} else {
return propagationContext;
}
}
const commonIsolationScopeMap = new WeakMap<object, Scope>();
/**
* Takes a shared (garbage collectable) object between resources, e.g. a headers object shared between Next.js server components and returns a common propagation context.
*
* @param commonObject The shared object.
* @param isolationScope The isolationScope that should be shared between all the resources if no isolation scope was created yet.
* @returns the shared isolation scope.
*/
export function commonObjectToIsolationScope(commonObject: unknown): Scope {
if (typeof commonObject === 'object' && commonObject) {
const memoIsolationScope = commonIsolationScopeMap.get(commonObject);
if (memoIsolationScope) {
return memoIsolationScope;
} else {
const newIsolationScope = new Scope();
commonIsolationScopeMap.set(commonObject, newIsolationScope);
return newIsolationScope;
}
} else {
return new Scope();
}
}
interface AsyncLocalStorage<T> {
getStore(): T | undefined;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
run<R, TArgs extends any[]>(store: T, callback: (...args: TArgs) => R, ...args: TArgs): R;
}
let nextjsEscapedAsyncStorage: AsyncLocalStorage<true>;
/**
* Will mark the execution context of the callback as "escaped" from Next.js internal tracing by unsetting the active
* span and propagation context. When an execution passes through this function multiple times, it is a noop after the
* first time.
*/
export function escapeNextjsTracing<T>(cb: () => T): T {
const MaybeGlobalAsyncLocalStorage = (GLOBAL_OBJ as { AsyncLocalStorage?: new () => AsyncLocalStorage<true> })
.AsyncLocalStorage;
if (!MaybeGlobalAsyncLocalStorage) {
DEBUG_BUILD &&
logger.warn(
"Tried to register AsyncLocalStorage async context strategy in a runtime that doesn't support AsyncLocalStorage.",
);
return cb();
}
if (!nextjsEscapedAsyncStorage) {
nextjsEscapedAsyncStorage = new MaybeGlobalAsyncLocalStorage();
}
if (nextjsEscapedAsyncStorage.getStore()) {
return cb();
} else {
return startNewTrace(() => {
return nextjsEscapedAsyncStorage.run(true, () => {
return cb();
});
});
}
}
/**
* Ideally this function never lands in the develop branch.
*
* Drops the entire span tree this function was called in, if it was a span tree created by Next.js.
*/
export function dropNextjsRootContext(): void {
const nextJsOwnedSpan = getActiveSpan();
if (nextJsOwnedSpan) {
const rootSpan = getRootSpan(nextJsOwnedSpan);
const rootSpanAttributes = spanToJSON(rootSpan).data;
if (rootSpanAttributes?.['next.span_type']) {
getRootSpan(nextJsOwnedSpan)?.setAttribute(TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION, true);
}
}
}