@atrim/instrument-node 0.1.3-12a8f92-20251118011211
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/README.md +351 -0
- package/package.json +130 -0
- package/target/dist/index.cjs +1212 -0
- package/target/dist/index.cjs.map +1 -0
- package/target/dist/index.d.cts +602 -0
- package/target/dist/index.d.ts +602 -0
- package/target/dist/index.js +1174 -0
- package/target/dist/index.js.map +1 -0
- package/target/dist/integrations/effect/index.cjs +715 -0
- package/target/dist/integrations/effect/index.cjs.map +1 -0
- package/target/dist/integrations/effect/index.d.cts +343 -0
- package/target/dist/integrations/effect/index.d.ts +343 -0
- package/target/dist/integrations/effect/index.js +679 -0
- package/target/dist/integrations/effect/index.js.map +1 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { Layer, FiberSet as FiberSet$1, Effect } from 'effect';
|
|
2
|
+
import { ConfigLoaderOptions } from '@atrim/instrument-core';
|
|
3
|
+
import * as effect_Runtime from 'effect/Runtime';
|
|
4
|
+
import * as effect_FiberId from 'effect/FiberId';
|
|
5
|
+
import * as effect_Scope from 'effect/Scope';
|
|
6
|
+
import { RuntimeFiber } from 'effect/Fiber';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Effect-TS Tracer integration with context propagation
|
|
10
|
+
*
|
|
11
|
+
* This module provides Effect-TS tracing that seamlessly integrates with
|
|
12
|
+
* OpenTelemetry NodeSDK auto-instrumentation. Effect spans will automatically
|
|
13
|
+
* continue existing traces created by NodeSDK (e.g., HTTP requests).
|
|
14
|
+
*
|
|
15
|
+
* Context Propagation:
|
|
16
|
+
* - NodeSDK auto-instrumentation creates root spans (e.g., HTTP requests)
|
|
17
|
+
* - Effect operations automatically become child spans of the active trace
|
|
18
|
+
* - Uses OpenTelemetry Context API (equivalent to Java thread-local)
|
|
19
|
+
* - No configuration needed - works out of the box
|
|
20
|
+
*
|
|
21
|
+
* Architecture:
|
|
22
|
+
* 1. @effect/opentelemetry uses the global OpenTelemetry tracer provider
|
|
23
|
+
* 2. When an Effect operation starts, it checks context.active() for existing spans
|
|
24
|
+
* 3. If found, creates child spans. If not, creates new root span.
|
|
25
|
+
* 4. This happens automatically via OpenTelemetry Context propagation
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Configuration options for Effect instrumentation
|
|
30
|
+
*/
|
|
31
|
+
interface EffectInstrumentationOptions extends ConfigLoaderOptions {
|
|
32
|
+
/**
|
|
33
|
+
* OTLP endpoint URL
|
|
34
|
+
* @default process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318'
|
|
35
|
+
*/
|
|
36
|
+
otlpEndpoint?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Service name
|
|
39
|
+
* @default process.env.OTEL_SERVICE_NAME || 'effect-service'
|
|
40
|
+
*/
|
|
41
|
+
serviceName?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Service version
|
|
44
|
+
* @default process.env.npm_package_version || '1.0.0'
|
|
45
|
+
*/
|
|
46
|
+
serviceVersion?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Whether to automatically extract Effect fiber metadata
|
|
49
|
+
* @default true
|
|
50
|
+
*/
|
|
51
|
+
autoExtractMetadata?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Whether to continue existing traces from NodeSDK auto-instrumentation
|
|
54
|
+
*
|
|
55
|
+
* When true (default):
|
|
56
|
+
* - Effect spans become children of existing NodeSDK spans
|
|
57
|
+
* - Example: HTTP request span → Effect business logic span
|
|
58
|
+
* - Uses OpenTelemetry Context API for propagation
|
|
59
|
+
*
|
|
60
|
+
* When false:
|
|
61
|
+
* - Effect operations always create new root spans
|
|
62
|
+
* - Not recommended unless you have specific requirements
|
|
63
|
+
*
|
|
64
|
+
* @default true
|
|
65
|
+
*/
|
|
66
|
+
continueExistingTraces?: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create Effect instrumentation layer with custom options
|
|
70
|
+
*
|
|
71
|
+
* This function creates an Effect Layer that provides OpenTelemetry tracing
|
|
72
|
+
* with automatic context propagation from NodeSDK auto-instrumentation.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* // With NodeSDK auto-instrumentation
|
|
77
|
+
* import { NodeSDK } from '@opentelemetry/sdk-node'
|
|
78
|
+
* import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
|
|
79
|
+
*
|
|
80
|
+
* // 1. Start NodeSDK (creates HTTP spans automatically)
|
|
81
|
+
* const sdk = new NodeSDK({
|
|
82
|
+
* instrumentations: [getNodeAutoInstrumentations()]
|
|
83
|
+
* })
|
|
84
|
+
* sdk.start()
|
|
85
|
+
*
|
|
86
|
+
* // 2. Create Effect instrumentation (will continue NodeSDK traces)
|
|
87
|
+
* const EffectLayer = createEffectInstrumentation()
|
|
88
|
+
*
|
|
89
|
+
* // 3. Use in Effect operations
|
|
90
|
+
* const program = Effect.gen(function* () {
|
|
91
|
+
* // This span will be a child of the HTTP request span (if any)
|
|
92
|
+
* yield* Effect.log("Business logic")
|
|
93
|
+
* }).pipe(
|
|
94
|
+
* Effect.withSpan("app.business.logic"),
|
|
95
|
+
* Effect.provide(EffectLayer)
|
|
96
|
+
* )
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
declare function createEffectInstrumentation(options?: EffectInstrumentationOptions): Layer.Layer<never, never, never>;
|
|
100
|
+
/**
|
|
101
|
+
* Zero-config Effect instrumentation layer
|
|
102
|
+
*
|
|
103
|
+
* Uses the global OpenTelemetry tracer provider that was set up by
|
|
104
|
+
* initializeInstrumentation(). This ensures all traces (Express, Effect, etc.)
|
|
105
|
+
* go to the same OTLP endpoint.
|
|
106
|
+
*
|
|
107
|
+
* Context Propagation:
|
|
108
|
+
* - Automatically continues traces from NodeSDK auto-instrumentation
|
|
109
|
+
* - Effect spans become children of HTTP request spans
|
|
110
|
+
* - No configuration needed
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* import { EffectInstrumentationLive } from '@atrim/instrumentation/effect'
|
|
115
|
+
*
|
|
116
|
+
* const program = Effect.gen(function* () {
|
|
117
|
+
* // This span continues any existing trace from NodeSDK
|
|
118
|
+
* yield* Effect.log("Processing")
|
|
119
|
+
* }).pipe(
|
|
120
|
+
* Effect.withSpan("app.process"),
|
|
121
|
+
* Effect.provide(EffectInstrumentationLive)
|
|
122
|
+
* )
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
declare const EffectInstrumentationLive: Layer.Layer<never, never, never>;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Effect-specific span annotation helpers
|
|
129
|
+
*/
|
|
130
|
+
declare function annotateUser(_userId: string, _email?: string): void;
|
|
131
|
+
declare function annotateDataSize(_bytes: number, _count: number): void;
|
|
132
|
+
declare function annotateBatch(_size: number, _batchSize: number): void;
|
|
133
|
+
declare function annotateLLM(_model: string, _operation: string, _inputTokens: number, _outputTokens: number): void;
|
|
134
|
+
declare function annotateQuery(_query: string, _database: string): void;
|
|
135
|
+
declare function annotateHttpRequest(_method: string, _url: string, _statusCode: number): void;
|
|
136
|
+
declare function annotateError(_error: Error, _context?: Record<string, string | number | boolean>): void;
|
|
137
|
+
declare function annotatePriority(_priority: string): void;
|
|
138
|
+
declare function annotateCache(_operation: string, _hit: boolean): void;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Effect metadata extraction
|
|
142
|
+
*
|
|
143
|
+
* Automatically extracts metadata from Effect fibers and adds them as span attributes.
|
|
144
|
+
* This provides valuable context about the Effect execution environment.
|
|
145
|
+
*/
|
|
146
|
+
/**
|
|
147
|
+
* Metadata extracted from Effect fibers
|
|
148
|
+
*/
|
|
149
|
+
interface EffectMetadata {
|
|
150
|
+
'effect.fiber.id'?: string;
|
|
151
|
+
'effect.fiber.status'?: string;
|
|
152
|
+
'effect.operation.root'?: boolean;
|
|
153
|
+
'effect.operation.interrupted'?: boolean;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Options for span isolation when running effects in FiberSet
|
|
158
|
+
*/
|
|
159
|
+
interface IsolationOptions {
|
|
160
|
+
/**
|
|
161
|
+
* Whether to create a root span (breaks parent chain)
|
|
162
|
+
* @default true (from config or this default)
|
|
163
|
+
*/
|
|
164
|
+
readonly createRoot?: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Capture logical parent relationship via span links and attributes
|
|
167
|
+
* @default true
|
|
168
|
+
*/
|
|
169
|
+
readonly captureLogicalParent?: boolean;
|
|
170
|
+
/**
|
|
171
|
+
* Use OpenTelemetry span links to track logical parent
|
|
172
|
+
* Works in: Honeycomb, Datadog, Lightstep, SigNoz, Splunk
|
|
173
|
+
* @default true
|
|
174
|
+
*/
|
|
175
|
+
readonly useSpanLinks?: boolean;
|
|
176
|
+
/**
|
|
177
|
+
* Add custom attributes for logical parent tracking
|
|
178
|
+
* Works in: ALL observability tools (universal fallback)
|
|
179
|
+
* @default true
|
|
180
|
+
*/
|
|
181
|
+
readonly useAttributes?: boolean;
|
|
182
|
+
/**
|
|
183
|
+
* Propagate interruption from parent
|
|
184
|
+
* @default undefined (FiberSet.run default behavior)
|
|
185
|
+
*/
|
|
186
|
+
readonly propagateInterruption?: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* Custom span attributes to add
|
|
189
|
+
*/
|
|
190
|
+
readonly attributes?: Record<string, unknown>;
|
|
191
|
+
/**
|
|
192
|
+
* Span category for Atrim grouping
|
|
193
|
+
* @default "background_task"
|
|
194
|
+
*/
|
|
195
|
+
readonly category?: string;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Run an effect in a FiberSet with automatic span isolation and virtual parent tracking.
|
|
199
|
+
*
|
|
200
|
+
* This function prevents span context leakage (fibers inheriting parent spans incorrectly)
|
|
201
|
+
* while maintaining logical parent relationships for observability.
|
|
202
|
+
*
|
|
203
|
+
* **Technical:** Uses `{ root: true }` to create independent root span
|
|
204
|
+
* **Observability:** Uses span links + attributes to track logical parent
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* import { runIsolated } from "@atrim/instrumentation/effect/fiberset"
|
|
209
|
+
*
|
|
210
|
+
* const program = Effect.scoped(
|
|
211
|
+
* Effect.gen(function* () {
|
|
212
|
+
* const set = yield* FiberSet.make()
|
|
213
|
+
*
|
|
214
|
+
* yield* Effect.gen(function* () {
|
|
215
|
+
* // Spawn background tasks with automatic isolation
|
|
216
|
+
* yield* runIsolated(set, backgroundTask1(), "background-task-1")
|
|
217
|
+
* yield* runIsolated(set, backgroundTask2(), "background-task-2")
|
|
218
|
+
* }).pipe(
|
|
219
|
+
* Effect.withSpan("parent-operation")
|
|
220
|
+
* )
|
|
221
|
+
*
|
|
222
|
+
* yield* Effect.sleep("100 millis")
|
|
223
|
+
* })
|
|
224
|
+
* )
|
|
225
|
+
*
|
|
226
|
+
* // In Honeycomb/Datadog/SigNoz:
|
|
227
|
+
* // - background tasks are ROOT spans (no context leakage)
|
|
228
|
+
* // - span links show they were spawned by parent-operation
|
|
229
|
+
* // - can reconstruct virtual hierarchy
|
|
230
|
+
* ```
|
|
231
|
+
*
|
|
232
|
+
* @param set - The FiberSet to run the effect in
|
|
233
|
+
* @param effect - The effect to run (will be isolated)
|
|
234
|
+
* @param name - Span name for the isolated effect
|
|
235
|
+
* @param options - Configuration options
|
|
236
|
+
* @returns Effect that returns the forked fiber
|
|
237
|
+
*
|
|
238
|
+
* @see https://github.com/atrim-ai/instrumentation/issues/5
|
|
239
|
+
*/
|
|
240
|
+
declare const runIsolated: <A, E, R>(set: FiberSet$1.FiberSet<A, E>, effect: Effect.Effect<A, E, R>, name: string, options?: IsolationOptions) => Effect.Effect<RuntimeFiber<A, E>, never, R>;
|
|
241
|
+
/**
|
|
242
|
+
* Convenience function to run an effect in a FiberSet with automatic span isolation.
|
|
243
|
+
*
|
|
244
|
+
* This is a simpler version of `runIsolated` with sensible defaults.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* yield* runWithSpan(set, "background-task", backgroundTask(), {
|
|
249
|
+
* attributes: { "task.priority": "high" }
|
|
250
|
+
* })
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
declare const runWithSpan: <A, E, R>(set: FiberSet$1.FiberSet<A, E>, name: string, effect: Effect.Effect<A, E, R>, options?: {
|
|
254
|
+
readonly propagateInterruption?: boolean;
|
|
255
|
+
readonly attributes?: Record<string, unknown>;
|
|
256
|
+
readonly category?: string;
|
|
257
|
+
}) => Effect.Effect<RuntimeFiber<A, E>, never, R>;
|
|
258
|
+
/**
|
|
259
|
+
* Annotate the current span with metadata about spawned FiberSet tasks.
|
|
260
|
+
*
|
|
261
|
+
* Call this in the parent operation before spawning tasks to add metadata
|
|
262
|
+
* that helps reconstruct the virtual hierarchy.
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```typescript
|
|
266
|
+
* yield* Effect.gen(function* () {
|
|
267
|
+
* yield* annotateSpawnedTasks([
|
|
268
|
+
* { name: "background-task-1" },
|
|
269
|
+
* { name: "background-task-2" },
|
|
270
|
+
* { name: "background-task-3" }
|
|
271
|
+
* ])
|
|
272
|
+
*
|
|
273
|
+
* yield* runIsolated(set, task1(), "background-task-1")
|
|
274
|
+
* yield* runIsolated(set, task2(), "background-task-2")
|
|
275
|
+
* yield* runIsolated(set, task3(), "background-task-3")
|
|
276
|
+
* }).pipe(
|
|
277
|
+
* Effect.withSpan("parent-operation")
|
|
278
|
+
* )
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
declare const annotateSpawnedTasks: (tasks: Array<{
|
|
282
|
+
name: string;
|
|
283
|
+
spanId?: string;
|
|
284
|
+
category?: string;
|
|
285
|
+
}>) => Effect.Effect<void>;
|
|
286
|
+
/**
|
|
287
|
+
* Re-export FiberSet namespace with isolation helpers
|
|
288
|
+
*
|
|
289
|
+
* This provides a convenient way to import all FiberSet functions:
|
|
290
|
+
* ```typescript
|
|
291
|
+
* import { FiberSet } from "@atrim/instrumentation/effect/fiberset"
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
declare const FiberSet: {
|
|
295
|
+
make: <A = unknown, E = unknown>() => Effect.Effect<FiberSet$1.FiberSet<A, E>, never, effect_Scope.Scope>;
|
|
296
|
+
add: {
|
|
297
|
+
<A, E, XE extends E, XA extends A>(fiber: RuntimeFiber<XA, XE>, options?: {
|
|
298
|
+
readonly propagateInterruption?: boolean | undefined;
|
|
299
|
+
} | undefined): (self: FiberSet$1.FiberSet<A, E>) => Effect.Effect<void>;
|
|
300
|
+
<A, E, XE extends E, XA extends A>(self: FiberSet$1.FiberSet<A, E>, fiber: RuntimeFiber<XA, XE>, options?: {
|
|
301
|
+
readonly propagateInterruption?: boolean | undefined;
|
|
302
|
+
} | undefined): Effect.Effect<void>;
|
|
303
|
+
};
|
|
304
|
+
unsafeAdd: {
|
|
305
|
+
<A, E, XE extends E, XA extends A>(fiber: RuntimeFiber<XA, XE>, options?: {
|
|
306
|
+
readonly interruptAs?: effect_FiberId.FiberId | undefined;
|
|
307
|
+
readonly propagateInterruption?: boolean | undefined;
|
|
308
|
+
} | undefined): (self: FiberSet$1.FiberSet<A, E>) => void;
|
|
309
|
+
<A, E, XE extends E, XA extends A>(self: FiberSet$1.FiberSet<A, E>, fiber: RuntimeFiber<XA, XE>, options?: {
|
|
310
|
+
readonly interruptAs?: effect_FiberId.FiberId | undefined;
|
|
311
|
+
readonly propagateInterruption?: boolean | undefined;
|
|
312
|
+
} | undefined): void;
|
|
313
|
+
};
|
|
314
|
+
run: {
|
|
315
|
+
<A, E>(self: FiberSet$1.FiberSet<A, E>, options?: {
|
|
316
|
+
readonly propagateInterruption?: boolean | undefined;
|
|
317
|
+
} | undefined): <R, XE extends E, XA extends A>(effect: Effect.Effect<XA, XE, R>) => Effect.Effect<RuntimeFiber<XA, XE>, never, R>;
|
|
318
|
+
<A, E, R, XE extends E, XA extends A>(self: FiberSet$1.FiberSet<A, E>, effect: Effect.Effect<XA, XE, R>, options?: {
|
|
319
|
+
readonly propagateInterruption?: boolean | undefined;
|
|
320
|
+
} | undefined): Effect.Effect<RuntimeFiber<XA, XE>, never, R>;
|
|
321
|
+
};
|
|
322
|
+
clear: <A, E>(self: FiberSet$1.FiberSet<A, E>) => Effect.Effect<void>;
|
|
323
|
+
join: <A, E>(self: FiberSet$1.FiberSet<A, E>) => Effect.Effect<void, E>;
|
|
324
|
+
awaitEmpty: <A, E>(self: FiberSet$1.FiberSet<A, E>) => Effect.Effect<void>;
|
|
325
|
+
size: <A, E>(self: FiberSet$1.FiberSet<A, E>) => Effect.Effect<number>;
|
|
326
|
+
runtime: <A, E>(self: FiberSet$1.FiberSet<A, E>) => <R = never>() => Effect.Effect<(<XE extends E, XA extends A>(effect: Effect.Effect<XA, XE, R>, options?: (effect_Runtime.RunForkOptions & {
|
|
327
|
+
readonly propagateInterruption?: boolean | undefined;
|
|
328
|
+
}) | undefined) => RuntimeFiber<XA, XE>), never, R>;
|
|
329
|
+
runtimePromise: <A, E>(self: FiberSet$1.FiberSet<A, E>) => <R = never>() => Effect.Effect<(<XE extends E, XA extends A>(effect: Effect.Effect<XA, XE, R>, options?: (effect_Runtime.RunForkOptions & {
|
|
330
|
+
readonly propagateInterruption?: boolean | undefined;
|
|
331
|
+
}) | undefined) => Promise<XA>), never, R>;
|
|
332
|
+
makeRuntime: <R = never, A = unknown, E = unknown>() => Effect.Effect<(<XE extends E, XA extends A>(effect: Effect.Effect<XA, XE, R>, options?: effect_Runtime.RunForkOptions | undefined) => RuntimeFiber<XA, XE>), never, effect_Scope.Scope | R>;
|
|
333
|
+
makeRuntimePromise: <R = never, A = unknown, E = unknown>() => Effect.Effect<(<XE extends E, XA extends A>(effect: Effect.Effect<XA, XE, R>, options?: effect_Runtime.RunForkOptions | undefined) => Promise<XA>), never, effect_Scope.Scope | R>;
|
|
334
|
+
isFiberSet: (u: unknown) => u is FiberSet$1.FiberSet<unknown, unknown>;
|
|
335
|
+
runIsolated: <A, E, R>(set: FiberSet$1.FiberSet<A, E>, effect: Effect.Effect<A, E, R>, name: string, options?: IsolationOptions) => Effect.Effect<RuntimeFiber<A, E>, never, R>;
|
|
336
|
+
runWithSpan: <A, E, R>(set: FiberSet$1.FiberSet<A, E>, name: string, effect: Effect.Effect<A, E, R>, options?: {
|
|
337
|
+
readonly propagateInterruption?: boolean;
|
|
338
|
+
readonly attributes?: Record<string, unknown>;
|
|
339
|
+
readonly category?: string;
|
|
340
|
+
}) => Effect.Effect<RuntimeFiber<A, E>, never, R>;
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
export { EffectInstrumentationLive, type EffectMetadata, FiberSet, type IsolationOptions, annotateBatch, annotateCache, annotateDataSize, annotateError, annotateHttpRequest, annotateLLM, annotatePriority, annotateQuery, annotateSpawnedTasks, annotateUser, createEffectInstrumentation, runIsolated, runWithSpan };
|