autotel 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1946 -0
- package/dist/chunk-2LNRY4QK.js +273 -0
- package/dist/chunk-2LNRY4QK.js.map +1 -0
- package/dist/chunk-3HENGDW2.js +587 -0
- package/dist/chunk-3HENGDW2.js.map +1 -0
- package/dist/chunk-4OAT42CA.cjs +73 -0
- package/dist/chunk-4OAT42CA.cjs.map +1 -0
- package/dist/chunk-5GWX5LFW.js +70 -0
- package/dist/chunk-5GWX5LFW.js.map +1 -0
- package/dist/chunk-5R2M36QB.js +195 -0
- package/dist/chunk-5R2M36QB.js.map +1 -0
- package/dist/chunk-5ZN622AO.js +73 -0
- package/dist/chunk-5ZN622AO.js.map +1 -0
- package/dist/chunk-77MSMAUQ.cjs +498 -0
- package/dist/chunk-77MSMAUQ.cjs.map +1 -0
- package/dist/chunk-ABPEQ6RK.cjs +596 -0
- package/dist/chunk-ABPEQ6RK.cjs.map +1 -0
- package/dist/chunk-BWYGJKRB.js +95 -0
- package/dist/chunk-BWYGJKRB.js.map +1 -0
- package/dist/chunk-BZHG5IZ4.js +73 -0
- package/dist/chunk-BZHG5IZ4.js.map +1 -0
- package/dist/chunk-G7VZBCD6.cjs +35 -0
- package/dist/chunk-G7VZBCD6.cjs.map +1 -0
- package/dist/chunk-GVLK7YUU.cjs +30 -0
- package/dist/chunk-GVLK7YUU.cjs.map +1 -0
- package/dist/chunk-HCCXC7XG.js +205 -0
- package/dist/chunk-HCCXC7XG.js.map +1 -0
- package/dist/chunk-HE6T6FIX.cjs +203 -0
- package/dist/chunk-HE6T6FIX.cjs.map +1 -0
- package/dist/chunk-KIXWPOCO.cjs +100 -0
- package/dist/chunk-KIXWPOCO.cjs.map +1 -0
- package/dist/chunk-KVGNW3FC.js +87 -0
- package/dist/chunk-KVGNW3FC.js.map +1 -0
- package/dist/chunk-LITNXTTT.js +3 -0
- package/dist/chunk-LITNXTTT.js.map +1 -0
- package/dist/chunk-M4ANN7RL.js +114 -0
- package/dist/chunk-M4ANN7RL.js.map +1 -0
- package/dist/chunk-NC52UBR2.cjs +32 -0
- package/dist/chunk-NC52UBR2.cjs.map +1 -0
- package/dist/chunk-NHCNRQD3.cjs +212 -0
- package/dist/chunk-NHCNRQD3.cjs.map +1 -0
- package/dist/chunk-NZ72VDNY.cjs +4 -0
- package/dist/chunk-NZ72VDNY.cjs.map +1 -0
- package/dist/chunk-P6JUDYNO.js +57 -0
- package/dist/chunk-P6JUDYNO.js.map +1 -0
- package/dist/chunk-RJYY7BWX.js +1349 -0
- package/dist/chunk-RJYY7BWX.js.map +1 -0
- package/dist/chunk-TRI4V5BF.cjs +126 -0
- package/dist/chunk-TRI4V5BF.cjs.map +1 -0
- package/dist/chunk-UL33I6IS.js +139 -0
- package/dist/chunk-UL33I6IS.js.map +1 -0
- package/dist/chunk-URRW6M2C.cjs +61 -0
- package/dist/chunk-URRW6M2C.cjs.map +1 -0
- package/dist/chunk-UY3UYPBZ.cjs +77 -0
- package/dist/chunk-UY3UYPBZ.cjs.map +1 -0
- package/dist/chunk-W3253FGB.cjs +277 -0
- package/dist/chunk-W3253FGB.cjs.map +1 -0
- package/dist/chunk-W7LHZVQF.js +26 -0
- package/dist/chunk-W7LHZVQF.js.map +1 -0
- package/dist/chunk-WBWNM6LB.cjs +1360 -0
- package/dist/chunk-WBWNM6LB.cjs.map +1 -0
- package/dist/chunk-WFJ7L2RV.js +494 -0
- package/dist/chunk-WFJ7L2RV.js.map +1 -0
- package/dist/chunk-X4RMFFMR.js +28 -0
- package/dist/chunk-X4RMFFMR.js.map +1 -0
- package/dist/chunk-Y4Y2S7BM.cjs +92 -0
- package/dist/chunk-Y4Y2S7BM.cjs.map +1 -0
- package/dist/chunk-YLPNXZFI.cjs +143 -0
- package/dist/chunk-YLPNXZFI.cjs.map +1 -0
- package/dist/chunk-YTXEZ4SD.cjs +77 -0
- package/dist/chunk-YTXEZ4SD.cjs.map +1 -0
- package/dist/chunk-Z6ZWNWWR.js +30 -0
- package/dist/chunk-Z6ZWNWWR.js.map +1 -0
- package/dist/config.cjs +26 -0
- package/dist/config.cjs.map +1 -0
- package/dist/config.d.cts +75 -0
- package/dist/config.d.ts +75 -0
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -0
- package/dist/db.cjs +233 -0
- package/dist/db.cjs.map +1 -0
- package/dist/db.d.cts +123 -0
- package/dist/db.d.ts +123 -0
- package/dist/db.js +228 -0
- package/dist/db.js.map +1 -0
- package/dist/decorators.cjs +67 -0
- package/dist/decorators.cjs.map +1 -0
- package/dist/decorators.d.cts +91 -0
- package/dist/decorators.d.ts +91 -0
- package/dist/decorators.js +65 -0
- package/dist/decorators.js.map +1 -0
- package/dist/event-subscriber.cjs +6 -0
- package/dist/event-subscriber.cjs.map +1 -0
- package/dist/event-subscriber.d.cts +116 -0
- package/dist/event-subscriber.d.ts +116 -0
- package/dist/event-subscriber.js +3 -0
- package/dist/event-subscriber.js.map +1 -0
- package/dist/event-testing.cjs +21 -0
- package/dist/event-testing.cjs.map +1 -0
- package/dist/event-testing.d.cts +110 -0
- package/dist/event-testing.d.ts +110 -0
- package/dist/event-testing.js +4 -0
- package/dist/event-testing.js.map +1 -0
- package/dist/event.cjs +30 -0
- package/dist/event.cjs.map +1 -0
- package/dist/event.d.cts +282 -0
- package/dist/event.d.ts +282 -0
- package/dist/event.js +13 -0
- package/dist/event.js.map +1 -0
- package/dist/exporters.cjs +17 -0
- package/dist/exporters.cjs.map +1 -0
- package/dist/exporters.d.cts +1 -0
- package/dist/exporters.d.ts +1 -0
- package/dist/exporters.js +4 -0
- package/dist/exporters.js.map +1 -0
- package/dist/functional.cjs +46 -0
- package/dist/functional.cjs.map +1 -0
- package/dist/functional.d.cts +478 -0
- package/dist/functional.d.ts +478 -0
- package/dist/functional.js +13 -0
- package/dist/functional.js.map +1 -0
- package/dist/http.cjs +189 -0
- package/dist/http.cjs.map +1 -0
- package/dist/http.d.cts +169 -0
- package/dist/http.d.ts +169 -0
- package/dist/http.js +184 -0
- package/dist/http.js.map +1 -0
- package/dist/index.cjs +333 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +758 -0
- package/dist/index.d.ts +758 -0
- package/dist/index.js +143 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation.cjs +182 -0
- package/dist/instrumentation.cjs.map +1 -0
- package/dist/instrumentation.d.cts +49 -0
- package/dist/instrumentation.d.ts +49 -0
- package/dist/instrumentation.js +179 -0
- package/dist/instrumentation.js.map +1 -0
- package/dist/logger.cjs +19 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +146 -0
- package/dist/logger.d.ts +146 -0
- package/dist/logger.js +6 -0
- package/dist/logger.js.map +1 -0
- package/dist/metric-helpers.cjs +31 -0
- package/dist/metric-helpers.cjs.map +1 -0
- package/dist/metric-helpers.d.cts +13 -0
- package/dist/metric-helpers.d.ts +13 -0
- package/dist/metric-helpers.js +6 -0
- package/dist/metric-helpers.js.map +1 -0
- package/dist/metric-testing.cjs +21 -0
- package/dist/metric-testing.cjs.map +1 -0
- package/dist/metric-testing.d.cts +110 -0
- package/dist/metric-testing.d.ts +110 -0
- package/dist/metric-testing.js +4 -0
- package/dist/metric-testing.js.map +1 -0
- package/dist/metric.cjs +26 -0
- package/dist/metric.cjs.map +1 -0
- package/dist/metric.d.cts +240 -0
- package/dist/metric.d.ts +240 -0
- package/dist/metric.js +9 -0
- package/dist/metric.js.map +1 -0
- package/dist/processors.cjs +17 -0
- package/dist/processors.cjs.map +1 -0
- package/dist/processors.d.cts +1 -0
- package/dist/processors.d.ts +1 -0
- package/dist/processors.js +4 -0
- package/dist/processors.js.map +1 -0
- package/dist/sampling.cjs +40 -0
- package/dist/sampling.cjs.map +1 -0
- package/dist/sampling.d.cts +260 -0
- package/dist/sampling.d.ts +260 -0
- package/dist/sampling.js +7 -0
- package/dist/sampling.js.map +1 -0
- package/dist/semantic-helpers.cjs +35 -0
- package/dist/semantic-helpers.cjs.map +1 -0
- package/dist/semantic-helpers.d.cts +442 -0
- package/dist/semantic-helpers.d.ts +442 -0
- package/dist/semantic-helpers.js +14 -0
- package/dist/semantic-helpers.js.map +1 -0
- package/dist/tail-sampling-processor.cjs +13 -0
- package/dist/tail-sampling-processor.cjs.map +1 -0
- package/dist/tail-sampling-processor.d.cts +27 -0
- package/dist/tail-sampling-processor.d.ts +27 -0
- package/dist/tail-sampling-processor.js +4 -0
- package/dist/tail-sampling-processor.js.map +1 -0
- package/dist/testing.cjs +286 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +291 -0
- package/dist/testing.d.ts +291 -0
- package/dist/testing.js +263 -0
- package/dist/testing.js.map +1 -0
- package/dist/trace-context-DRZdUvVY.d.cts +181 -0
- package/dist/trace-context-DRZdUvVY.d.ts +181 -0
- package/dist/trace-helpers.cjs +54 -0
- package/dist/trace-helpers.cjs.map +1 -0
- package/dist/trace-helpers.d.cts +524 -0
- package/dist/trace-helpers.d.ts +524 -0
- package/dist/trace-helpers.js +5 -0
- package/dist/trace-helpers.js.map +1 -0
- package/dist/tracer-provider.cjs +21 -0
- package/dist/tracer-provider.cjs.map +1 -0
- package/dist/tracer-provider.d.cts +169 -0
- package/dist/tracer-provider.d.ts +169 -0
- package/dist/tracer-provider.js +4 -0
- package/dist/tracer-provider.js.map +1 -0
- package/package.json +280 -0
- package/src/baggage-span-processor.test.ts +202 -0
- package/src/baggage-span-processor.ts +98 -0
- package/src/circuit-breaker.test.ts +341 -0
- package/src/circuit-breaker.ts +184 -0
- package/src/config.test.ts +94 -0
- package/src/config.ts +169 -0
- package/src/db.test.ts +252 -0
- package/src/db.ts +447 -0
- package/src/decorators.test.ts +203 -0
- package/src/decorators.ts +188 -0
- package/src/env-config.test.ts +246 -0
- package/src/env-config.ts +158 -0
- package/src/event-queue.test.ts +222 -0
- package/src/event-queue.ts +203 -0
- package/src/event-subscriber.ts +136 -0
- package/src/event-testing.ts +197 -0
- package/src/event.test.ts +718 -0
- package/src/event.ts +556 -0
- package/src/exporters.ts +96 -0
- package/src/functional.test.ts +1059 -0
- package/src/functional.ts +2295 -0
- package/src/http.test.ts +487 -0
- package/src/http.ts +424 -0
- package/src/index.ts +158 -0
- package/src/init.customization.test.ts +210 -0
- package/src/init.integrations.test.ts +366 -0
- package/src/init.openllmetry.test.ts +282 -0
- package/src/init.protocol.test.ts +215 -0
- package/src/init.ts +1426 -0
- package/src/instrumentation.test.ts +108 -0
- package/src/instrumentation.ts +308 -0
- package/src/logger.test.ts +117 -0
- package/src/logger.ts +246 -0
- package/src/metric-helpers.ts +47 -0
- package/src/metric-testing.ts +197 -0
- package/src/metric.ts +434 -0
- package/src/metrics.test.ts +205 -0
- package/src/operation-context.ts +93 -0
- package/src/processors.ts +106 -0
- package/src/rate-limiter.test.ts +199 -0
- package/src/rate-limiter.ts +98 -0
- package/src/sampling.test.ts +513 -0
- package/src/sampling.ts +428 -0
- package/src/semantic-helpers.test.ts +311 -0
- package/src/semantic-helpers.ts +584 -0
- package/src/shutdown.test.ts +311 -0
- package/src/shutdown.ts +222 -0
- package/src/stub.integration.test.ts +361 -0
- package/src/tail-sampling-processor.test.ts +226 -0
- package/src/tail-sampling-processor.ts +51 -0
- package/src/testing.ts +670 -0
- package/src/trace-context.ts +470 -0
- package/src/trace-helpers.new.test.ts +278 -0
- package/src/trace-helpers.test.ts +242 -0
- package/src/trace-helpers.ts +690 -0
- package/src/tracer-provider.test.ts +183 -0
- package/src/tracer-provider.ts +266 -0
- package/src/track.test.ts +153 -0
- package/src/track.ts +120 -0
- package/src/validation.test.ts +306 -0
- package/src/validation.ts +239 -0
- package/src/variable-name-inference.test.ts +178 -0
- package/src/variable-name-inference.ts +242 -0
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trace context types and utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
Span,
|
|
7
|
+
SpanStatusCode,
|
|
8
|
+
BaggageEntry,
|
|
9
|
+
Context,
|
|
10
|
+
} from '@opentelemetry/api';
|
|
11
|
+
import { context, propagation } from '@opentelemetry/api';
|
|
12
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* AsyncLocalStorage for storing the active context with baggage
|
|
16
|
+
* This allows setters to update the context and have it persist
|
|
17
|
+
*/
|
|
18
|
+
const contextStorage = new AsyncLocalStorage<Context>();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get the context storage instance (for initialization in functional.ts)
|
|
22
|
+
*/
|
|
23
|
+
export function getContextStorage(): AsyncLocalStorage<Context> {
|
|
24
|
+
return contextStorage;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get the active context, checking our stored context first
|
|
29
|
+
* This ensures baggage setters work with OpenTelemetry's propagation
|
|
30
|
+
*/
|
|
31
|
+
export function getActiveContextWithBaggage(): Context {
|
|
32
|
+
// Check stored context first (from setters), then fall back to active context
|
|
33
|
+
// This ensures ctx.setBaggage() changes are visible to OpenTelemetry operations
|
|
34
|
+
const stored = contextStorage.getStore();
|
|
35
|
+
return stored ?? context.active();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Try to keep OpenTelemetry's context manager in sync with baggage updates
|
|
40
|
+
*/
|
|
41
|
+
type ContextManagerLike = {
|
|
42
|
+
with?: (ctx: Context, fn: () => void) => void;
|
|
43
|
+
_asyncLocalStorage?: { enterWith?: (ctx: Context) => void };
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function updateActiveContext(newContext: Context): void {
|
|
47
|
+
// Update our storage first so any helper reads see the new context
|
|
48
|
+
contextStorage.enterWith(newContext);
|
|
49
|
+
|
|
50
|
+
const contextWithManager = context as unknown as {
|
|
51
|
+
_getContextManager?: () => ContextManagerLike;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const manager = contextWithManager._getContextManager?.();
|
|
55
|
+
if (!manager) return;
|
|
56
|
+
|
|
57
|
+
const asyncLocal =
|
|
58
|
+
(manager as { _asyncLocalStorage?: { enterWith?: (ctx: Context) => void } })
|
|
59
|
+
._asyncLocalStorage ?? undefined;
|
|
60
|
+
if (asyncLocal?.enterWith) {
|
|
61
|
+
asyncLocal.enterWith(newContext);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (typeof manager.with === 'function') {
|
|
66
|
+
manager.with(newContext, () => {});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Base trace context containing trace identifiers
|
|
72
|
+
*/
|
|
73
|
+
export interface TraceContextBase {
|
|
74
|
+
traceId: string;
|
|
75
|
+
spanId: string;
|
|
76
|
+
correlationId: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Span methods available on trace context
|
|
81
|
+
*/
|
|
82
|
+
export interface SpanMethods {
|
|
83
|
+
setAttribute(key: string, value: string | number | boolean): void;
|
|
84
|
+
setAttributes(attrs: Record<string, string | number | boolean>): void;
|
|
85
|
+
setStatus(status: { code: SpanStatusCode; message?: string }): void;
|
|
86
|
+
recordException(exception: Error): void;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Baggage methods available on trace context
|
|
91
|
+
*
|
|
92
|
+
* @template TBaggage - Optional type for typed baggage (defaults to undefined for untyped)
|
|
93
|
+
*/
|
|
94
|
+
export interface BaggageMethods<
|
|
95
|
+
TBaggage extends Record<string, unknown> | undefined = undefined,
|
|
96
|
+
> {
|
|
97
|
+
/**
|
|
98
|
+
* Get a baggage entry by key
|
|
99
|
+
* @param key - Baggage key
|
|
100
|
+
* @returns Baggage entry value or undefined
|
|
101
|
+
*/
|
|
102
|
+
getBaggage(key: string): string | undefined;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Set a baggage entry
|
|
106
|
+
*
|
|
107
|
+
* Note: OpenTelemetry contexts are immutable. For proper scoping across async
|
|
108
|
+
* boundaries, use withBaggage() instead. This method updates baggage in the
|
|
109
|
+
* current context which may not propagate to all child operations.
|
|
110
|
+
*
|
|
111
|
+
* @param key - Baggage key
|
|
112
|
+
* @param value - Baggage value
|
|
113
|
+
* @returns The baggage value that was set (for chaining)
|
|
114
|
+
*
|
|
115
|
+
* @example Using withBaggage() (recommended)
|
|
116
|
+
* ```typescript
|
|
117
|
+
* await withBaggage({ baggage: { 'key': 'value' }, fn: async () => {
|
|
118
|
+
* // Baggage is available here and in child spans
|
|
119
|
+
* });
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
setBaggage(key: string, value: string): string;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Delete a baggage entry
|
|
126
|
+
*
|
|
127
|
+
* Note: OpenTelemetry contexts are immutable. For proper scoping across async
|
|
128
|
+
* boundaries, use withBaggage() with only the entries you want instead.
|
|
129
|
+
*
|
|
130
|
+
* @param key - Baggage key
|
|
131
|
+
*/
|
|
132
|
+
deleteBaggage(key: string): void;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get all baggage entries
|
|
136
|
+
* @returns Map of all baggage entries
|
|
137
|
+
*/
|
|
138
|
+
getAllBaggage(): Map<string, BaggageEntry>;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Get typed baggage (only available when TBaggage is defined)
|
|
142
|
+
* This is used internally by defineBaggageSchema()
|
|
143
|
+
*
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
getTypedBaggage?: TBaggage extends Record<string, unknown>
|
|
147
|
+
? <T extends TBaggage>(namespace?: string) => Partial<T> | undefined
|
|
148
|
+
: never;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Set typed baggage (only available when TBaggage is defined)
|
|
152
|
+
* This is used internally by defineBaggageSchema()
|
|
153
|
+
*
|
|
154
|
+
* @internal
|
|
155
|
+
*/
|
|
156
|
+
setTypedBaggage?: TBaggage extends Record<string, unknown>
|
|
157
|
+
? <T extends TBaggage>(
|
|
158
|
+
namespace: string | undefined,
|
|
159
|
+
value: Partial<T>,
|
|
160
|
+
) => void
|
|
161
|
+
: never;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Complete trace context that merges base context, span methods, and baggage methods
|
|
166
|
+
*
|
|
167
|
+
* This is the ctx parameter passed to factory functions in trace().
|
|
168
|
+
* It provides access to trace IDs, span manipulation methods, and baggage operations.
|
|
169
|
+
*
|
|
170
|
+
* @template TBaggage - Optional type for typed baggage support
|
|
171
|
+
*
|
|
172
|
+
* @example Untyped (default)
|
|
173
|
+
* ```typescript
|
|
174
|
+
* export const handler = trace((ctx) => async () => {
|
|
175
|
+
* ctx.getBaggage('key'); // returns string | undefined
|
|
176
|
+
* });
|
|
177
|
+
* ```
|
|
178
|
+
*
|
|
179
|
+
* @example Typed baggage
|
|
180
|
+
* ```typescript
|
|
181
|
+
* type TenantBaggage = { tenantId: string; region?: string };
|
|
182
|
+
*
|
|
183
|
+
* export const handler = trace<TenantBaggage>((ctx) => async () => {
|
|
184
|
+
* // Use typed schema helper for type-safe access
|
|
185
|
+
* const schema = defineBaggageSchema<TenantBaggage>('tenant');
|
|
186
|
+
* const tenant = schema.get(ctx); // Partial<TenantBaggage> | undefined
|
|
187
|
+
* });
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
export type TraceContext<
|
|
191
|
+
TBaggage extends Record<string, unknown> | undefined = undefined,
|
|
192
|
+
> = TraceContextBase & SpanMethods & BaggageMethods<TBaggage>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Create a TraceContext from an OpenTelemetry Span
|
|
196
|
+
*
|
|
197
|
+
* This utility extracts trace context information from a span
|
|
198
|
+
* and provides span manipulation methods and baggage operations in a consistent format.
|
|
199
|
+
*
|
|
200
|
+
* Note: Baggage methods always operate on the currently active context,
|
|
201
|
+
* which may differ from the context when createTraceContext was called.
|
|
202
|
+
*/
|
|
203
|
+
export function createTraceContext<
|
|
204
|
+
TBaggage extends Record<string, unknown> | undefined = undefined,
|
|
205
|
+
>(span: Span): TraceContext<TBaggage> {
|
|
206
|
+
const spanContext = span.spanContext();
|
|
207
|
+
|
|
208
|
+
// Store the current active context in AsyncLocalStorage so baggage setters can update it
|
|
209
|
+
// This ensures ctx.setBaggage() changes persist and are visible to OpenTelemetry operations
|
|
210
|
+
// IMPORTANT: Only initialize if not already set (preserve baggage updates from parent spans)
|
|
211
|
+
const existingStored = contextStorage.getStore();
|
|
212
|
+
if (!existingStored) {
|
|
213
|
+
const activeContext = context.active();
|
|
214
|
+
contextStorage.enterWith(activeContext);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Baggage helpers that always use the current active context
|
|
218
|
+
// This ensures baggage operations work correctly even if context changes
|
|
219
|
+
const baggageHelpers: BaggageMethods<TBaggage> = {
|
|
220
|
+
getBaggage(key: string): string | undefined {
|
|
221
|
+
// Check active context first (from withBaggage, context.with, etc.)
|
|
222
|
+
// Then check stored context (from setters)
|
|
223
|
+
// This ensures both withBaggage() and ctx.setBaggage() work correctly
|
|
224
|
+
const activeCtx = context.active();
|
|
225
|
+
let baggage = propagation.getBaggage(activeCtx);
|
|
226
|
+
if (!baggage) {
|
|
227
|
+
const storedContext = contextStorage.getStore();
|
|
228
|
+
if (storedContext) {
|
|
229
|
+
baggage = propagation.getBaggage(storedContext);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return baggage?.getEntry(key)?.value;
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
setBaggage(key: string, value: string): string {
|
|
236
|
+
// OpenTelemetry contexts are immutable, so we create a new context with updated baggage
|
|
237
|
+
// Check active context first (may have baggage from withBaggage), then stored context
|
|
238
|
+
const activeCtx = context.active();
|
|
239
|
+
const storedContext = contextStorage.getStore();
|
|
240
|
+
const currentContext = storedContext ?? activeCtx;
|
|
241
|
+
const baggage =
|
|
242
|
+
propagation.getBaggage(currentContext) ?? propagation.createBaggage();
|
|
243
|
+
const updated = baggage.setEntry(key, { value });
|
|
244
|
+
const newContext = propagation.setBaggage(currentContext, updated);
|
|
245
|
+
|
|
246
|
+
updateActiveContext(newContext);
|
|
247
|
+
|
|
248
|
+
return value;
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
deleteBaggage(key: string): void {
|
|
252
|
+
// Check active context first, then stored context
|
|
253
|
+
const activeCtx = context.active();
|
|
254
|
+
const storedContext = contextStorage.getStore();
|
|
255
|
+
const currentContext = storedContext ?? activeCtx;
|
|
256
|
+
const baggage = propagation.getBaggage(currentContext);
|
|
257
|
+
if (baggage) {
|
|
258
|
+
const updated = baggage.removeEntry(key);
|
|
259
|
+
const newContext = propagation.setBaggage(currentContext, updated);
|
|
260
|
+
|
|
261
|
+
updateActiveContext(newContext);
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
getAllBaggage(): Map<string, BaggageEntry> {
|
|
266
|
+
// Check active context first, then stored context
|
|
267
|
+
const activeCtx = context.active();
|
|
268
|
+
let baggage = propagation.getBaggage(activeCtx);
|
|
269
|
+
if (!baggage) {
|
|
270
|
+
const storedContext = contextStorage.getStore();
|
|
271
|
+
if (storedContext) {
|
|
272
|
+
baggage = propagation.getBaggage(storedContext);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (!baggage) {
|
|
276
|
+
return new Map();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Convert baggage entries to a Map
|
|
280
|
+
const entries = new Map<string, BaggageEntry>();
|
|
281
|
+
for (const [key, entry] of baggage.getAllEntries()) {
|
|
282
|
+
entries.set(key, entry);
|
|
283
|
+
}
|
|
284
|
+
return entries;
|
|
285
|
+
},
|
|
286
|
+
|
|
287
|
+
// Typed baggage helpers (used by defineBaggageSchema)
|
|
288
|
+
getTypedBaggage: (<T extends Record<string, unknown>>(
|
|
289
|
+
namespace?: string,
|
|
290
|
+
) => {
|
|
291
|
+
// Check active context first, then stored context
|
|
292
|
+
const activeCtx = context.active();
|
|
293
|
+
let baggage = propagation.getBaggage(activeCtx);
|
|
294
|
+
if (!baggage) {
|
|
295
|
+
const storedContext = contextStorage.getStore();
|
|
296
|
+
if (storedContext) {
|
|
297
|
+
baggage = propagation.getBaggage(storedContext);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (!baggage) return;
|
|
301
|
+
|
|
302
|
+
const prefix = namespace ? `${namespace}.` : '';
|
|
303
|
+
const result: Record<string, unknown> = {};
|
|
304
|
+
|
|
305
|
+
for (const [key, entry] of baggage.getAllEntries()) {
|
|
306
|
+
if (namespace && key.startsWith(prefix)) {
|
|
307
|
+
const fieldName = key.slice(prefix.length);
|
|
308
|
+
result[fieldName] = entry.value;
|
|
309
|
+
} else if (!namespace) {
|
|
310
|
+
result[key] = entry.value;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return Object.keys(result).length > 0
|
|
315
|
+
? (result as Partial<T>)
|
|
316
|
+
: undefined;
|
|
317
|
+
}) as TBaggage extends Record<string, unknown>
|
|
318
|
+
? <T extends TBaggage>(namespace?: string) => Partial<T> | undefined
|
|
319
|
+
: never,
|
|
320
|
+
|
|
321
|
+
setTypedBaggage: (<T extends Record<string, unknown>>(
|
|
322
|
+
namespace: string | undefined,
|
|
323
|
+
value: Partial<T>,
|
|
324
|
+
) => {
|
|
325
|
+
// Check active context first, then stored context
|
|
326
|
+
const activeCtx = context.active();
|
|
327
|
+
const storedContext = contextStorage.getStore();
|
|
328
|
+
const currentContext = storedContext ?? activeCtx;
|
|
329
|
+
let baggage =
|
|
330
|
+
propagation.getBaggage(currentContext) ?? propagation.createBaggage();
|
|
331
|
+
|
|
332
|
+
const prefix = namespace ? `${namespace}.` : '';
|
|
333
|
+
for (const [key, val] of Object.entries(value)) {
|
|
334
|
+
if (val !== undefined) {
|
|
335
|
+
const baggageKey = `${prefix}${key}`;
|
|
336
|
+
baggage = baggage.setEntry(baggageKey, { value: String(val) });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const newContext = propagation.setBaggage(currentContext, baggage);
|
|
341
|
+
updateActiveContext(newContext);
|
|
342
|
+
}) as TBaggage extends Record<string, unknown>
|
|
343
|
+
? <T extends TBaggage>(
|
|
344
|
+
namespace: string | undefined,
|
|
345
|
+
value: Partial<T>,
|
|
346
|
+
) => void
|
|
347
|
+
: never,
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
traceId: spanContext.traceId,
|
|
352
|
+
spanId: spanContext.spanId,
|
|
353
|
+
correlationId: spanContext.traceId.slice(0, 16),
|
|
354
|
+
setAttribute: span.setAttribute.bind(span),
|
|
355
|
+
setAttributes: span.setAttributes.bind(span),
|
|
356
|
+
setStatus: span.setStatus.bind(span),
|
|
357
|
+
recordException: span.recordException.bind(span),
|
|
358
|
+
...baggageHelpers,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Define a typed baggage schema for type-safe baggage operations
|
|
364
|
+
*
|
|
365
|
+
* This helper provides a type-safe API for working with baggage entries.
|
|
366
|
+
* The namespace parameter is optional and prefixes all keys to avoid collisions.
|
|
367
|
+
*
|
|
368
|
+
* @template T - The baggage schema type (all fields are treated as optional)
|
|
369
|
+
* @param namespace - Optional namespace to prefix baggage keys
|
|
370
|
+
*
|
|
371
|
+
* @example Basic usage
|
|
372
|
+
* ```typescript
|
|
373
|
+
* type TenantBaggage = { tenantId: string; region?: string };
|
|
374
|
+
* const tenantBaggage = defineBaggageSchema<TenantBaggage>('tenant');
|
|
375
|
+
*
|
|
376
|
+
* export const handler = trace<TenantBaggage>((ctx) => async () => {
|
|
377
|
+
* // Get typed baggage
|
|
378
|
+
* const tenant = tenantBaggage.get(ctx);
|
|
379
|
+
* if (tenant?.tenantId) {
|
|
380
|
+
* console.log('Tenant:', tenant.tenantId);
|
|
381
|
+
* }
|
|
382
|
+
*
|
|
383
|
+
* // Set typed baggage
|
|
384
|
+
* tenantBaggage.set(ctx, { tenantId: 't1', region: 'us-east-1' });
|
|
385
|
+
* });
|
|
386
|
+
* ```
|
|
387
|
+
*
|
|
388
|
+
* @example With withBaggage helper
|
|
389
|
+
* ```typescript
|
|
390
|
+
* const tenantBaggage = defineBaggageSchema<TenantBaggage>('tenant');
|
|
391
|
+
*
|
|
392
|
+
* export const handler = trace<TenantBaggage>((ctx) => async () => {
|
|
393
|
+
* return await tenantBaggage.with(ctx, { tenantId: 't1' }, async () => {
|
|
394
|
+
* // Baggage is available here and in child spans
|
|
395
|
+
* const tenant = tenantBaggage.get(ctx);
|
|
396
|
+
* });
|
|
397
|
+
* });
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
400
|
+
export function defineBaggageSchema<T extends Record<string, unknown>>(
|
|
401
|
+
namespace?: string,
|
|
402
|
+
) {
|
|
403
|
+
return {
|
|
404
|
+
/**
|
|
405
|
+
* Get typed baggage from context
|
|
406
|
+
* @param ctx - Trace context
|
|
407
|
+
* @returns Partial baggage object or undefined if no baggage is set
|
|
408
|
+
*/
|
|
409
|
+
get: (ctx: TraceContext<T>): Partial<T> | undefined => {
|
|
410
|
+
if (!ctx.getTypedBaggage) return undefined;
|
|
411
|
+
return ctx.getTypedBaggage<T>(namespace);
|
|
412
|
+
},
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Set typed baggage in context
|
|
416
|
+
*
|
|
417
|
+
* Note: For proper scoping across async boundaries, use the `with` method instead
|
|
418
|
+
*
|
|
419
|
+
* @param ctx - Trace context
|
|
420
|
+
* @param value - Partial baggage object to set
|
|
421
|
+
*/
|
|
422
|
+
set: (ctx: TraceContext<T>, value: Partial<T>): void => {
|
|
423
|
+
if (!ctx.setTypedBaggage) return;
|
|
424
|
+
ctx.setTypedBaggage<T>(namespace, value);
|
|
425
|
+
},
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Run a function with typed baggage properly scoped
|
|
429
|
+
*
|
|
430
|
+
* This is the recommended way to set baggage as it ensures proper
|
|
431
|
+
* scoping across async boundaries.
|
|
432
|
+
*
|
|
433
|
+
* @param ctx - Trace context (can be omitted, will use active context)
|
|
434
|
+
* @param value - Partial baggage object to set
|
|
435
|
+
* @param fn - Function to execute with the baggage
|
|
436
|
+
*/
|
|
437
|
+
with: <R>(
|
|
438
|
+
ctxOrValue: TraceContext<T> | Partial<T>,
|
|
439
|
+
valueOrFn: Partial<T> | (() => R | Promise<R>),
|
|
440
|
+
maybeFn?: () => R | Promise<R>,
|
|
441
|
+
): R | Promise<R> => {
|
|
442
|
+
// Support both with(ctx, value, fn) and with(value, fn)
|
|
443
|
+
const value = maybeFn
|
|
444
|
+
? (valueOrFn as Partial<T>)
|
|
445
|
+
: (ctxOrValue as Partial<T>);
|
|
446
|
+
const fn = maybeFn || (valueOrFn as () => R | Promise<R>);
|
|
447
|
+
|
|
448
|
+
// Serialize typed baggage to flat key-value pairs
|
|
449
|
+
const prefix = namespace ? `${namespace}.` : '';
|
|
450
|
+
const flatBaggage: Record<string, string> = {};
|
|
451
|
+
for (const [key, val] of Object.entries(value)) {
|
|
452
|
+
if (val !== undefined) {
|
|
453
|
+
flatBaggage[`${prefix}${key}`] = String(val);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Use the existing withBaggage helper
|
|
458
|
+
const currentContext = context.active();
|
|
459
|
+
let baggage =
|
|
460
|
+
propagation.getBaggage(currentContext) ?? propagation.createBaggage();
|
|
461
|
+
|
|
462
|
+
for (const [key, val] of Object.entries(flatBaggage)) {
|
|
463
|
+
baggage = baggage.setEntry(key, { value: val });
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const newContext = propagation.setBaggage(currentContext, baggage);
|
|
467
|
+
return context.with(newContext, fn);
|
|
468
|
+
},
|
|
469
|
+
};
|
|
470
|
+
}
|