@atrim/instrument-node 0.5.2-dev.ac2fbfe.20251221205322 → 0.7.0-14fdea7-20260108225522
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 +92 -330
- package/package.json +25 -19
- package/target/dist/index.cjs +227 -60
- package/target/dist/index.cjs.map +1 -1
- package/target/dist/index.d.cts +28 -13
- package/target/dist/index.d.ts +28 -13
- package/target/dist/index.js +226 -60
- package/target/dist/index.js.map +1 -1
- package/target/dist/integrations/effect/auto/index.cjs +1181 -0
- package/target/dist/integrations/effect/auto/index.cjs.map +1 -0
- package/target/dist/integrations/effect/auto/index.d.cts +437 -0
- package/target/dist/integrations/effect/auto/index.d.ts +437 -0
- package/target/dist/integrations/effect/auto/index.js +1136 -0
- package/target/dist/integrations/effect/auto/index.js.map +1 -0
- package/target/dist/integrations/effect/index.cjs +231 -129
- package/target/dist/integrations/effect/index.cjs.map +1 -1
- package/target/dist/integrations/effect/index.d.cts +19 -24
- package/target/dist/integrations/effect/index.d.ts +19 -24
- package/target/dist/integrations/effect/index.js +232 -132
- package/target/dist/integrations/effect/index.js.map +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Layer, Effect, FiberSet as FiberSet$1 } from 'effect';
|
|
2
|
+
import * as Tracer from '@effect/opentelemetry/Tracer';
|
|
2
3
|
import { InstrumentationConfig } from '@atrim/instrument-core';
|
|
3
4
|
import * as effect_Runtime from 'effect/Runtime';
|
|
4
5
|
import * as effect_FiberId from 'effect/FiberId';
|
|
@@ -6,9 +7,10 @@ import * as effect_Scope from 'effect/Scope';
|
|
|
6
7
|
import { RuntimeFiber } from 'effect/Fiber';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
|
-
* Node.js configuration loader
|
|
10
|
+
* Node.js configuration loader
|
|
10
11
|
*
|
|
11
|
-
* Provides
|
|
12
|
+
* Provides configuration loading using native Node.js APIs (fs, fetch)
|
|
13
|
+
* This module doesn't require Effect Platform, making it work without Effect installed.
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -46,17 +48,12 @@ interface ConfigLoaderOptions {
|
|
|
46
48
|
*/
|
|
47
49
|
interface EffectInstrumentationOptions extends ConfigLoaderOptions {
|
|
48
50
|
/**
|
|
49
|
-
*
|
|
50
|
-
* @default process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318'
|
|
51
|
-
*/
|
|
52
|
-
otlpEndpoint?: string;
|
|
53
|
-
/**
|
|
54
|
-
* Service name
|
|
51
|
+
* Service name for Effect spans
|
|
55
52
|
* @default process.env.OTEL_SERVICE_NAME || 'effect-service'
|
|
56
53
|
*/
|
|
57
54
|
serviceName?: string;
|
|
58
55
|
/**
|
|
59
|
-
* Service version
|
|
56
|
+
* Service version for Effect spans
|
|
60
57
|
* @default process.env.npm_package_version || '1.0.0'
|
|
61
58
|
*/
|
|
62
59
|
serviceVersion?: string;
|
|
@@ -66,20 +63,17 @@ interface EffectInstrumentationOptions extends ConfigLoaderOptions {
|
|
|
66
63
|
*/
|
|
67
64
|
autoExtractMetadata?: boolean;
|
|
68
65
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* - Not recommended unless you have specific requirements
|
|
79
|
-
*
|
|
80
|
-
* @default true
|
|
66
|
+
* OTLP endpoint URL (only used when exporter mode is 'standalone')
|
|
67
|
+
* @default process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318'
|
|
68
|
+
*/
|
|
69
|
+
otlpEndpoint?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Exporter mode:
|
|
72
|
+
* - 'unified': Use global TracerProvider from Node SDK (recommended, enables filtering)
|
|
73
|
+
* - 'standalone': Use Effect's own OTLP exporter (bypasses Node SDK filtering)
|
|
74
|
+
* @default 'unified'
|
|
81
75
|
*/
|
|
82
|
-
|
|
76
|
+
exporterMode?: 'unified' | 'standalone';
|
|
83
77
|
}
|
|
84
78
|
/**
|
|
85
79
|
* Create Effect instrumentation layer with custom options
|
|
@@ -118,11 +112,12 @@ declare function createEffectInstrumentation(options?: EffectInstrumentationOpti
|
|
|
118
112
|
*
|
|
119
113
|
* Uses the global OpenTelemetry tracer provider that was set up by
|
|
120
114
|
* initializeInstrumentation(). This ensures all traces (Express, Effect, etc.)
|
|
121
|
-
* go
|
|
115
|
+
* go through the same TracerProvider and PatternSpanProcessor.
|
|
122
116
|
*
|
|
123
117
|
* Context Propagation:
|
|
124
118
|
* - Automatically continues traces from NodeSDK auto-instrumentation
|
|
125
119
|
* - Effect spans become children of HTTP request spans
|
|
120
|
+
* - Respects http.ignore_incoming_paths and other filtering patterns
|
|
126
121
|
* - No configuration needed
|
|
127
122
|
*
|
|
128
123
|
* @example
|
|
@@ -138,7 +133,7 @@ declare function createEffectInstrumentation(options?: EffectInstrumentationOpti
|
|
|
138
133
|
* )
|
|
139
134
|
* ```
|
|
140
135
|
*/
|
|
141
|
-
declare const EffectInstrumentationLive: Layer.Layer<
|
|
136
|
+
declare const EffectInstrumentationLive: Layer.Layer<Tracer.OtelTracer, never, never>;
|
|
142
137
|
|
|
143
138
|
/**
|
|
144
139
|
* Effect-specific span annotation helpers
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Layer, Effect, FiberSet as FiberSet$1 } from 'effect';
|
|
2
|
+
import * as Tracer from '@effect/opentelemetry/Tracer';
|
|
2
3
|
import { InstrumentationConfig } from '@atrim/instrument-core';
|
|
3
4
|
import * as effect_Runtime from 'effect/Runtime';
|
|
4
5
|
import * as effect_FiberId from 'effect/FiberId';
|
|
@@ -6,9 +7,10 @@ import * as effect_Scope from 'effect/Scope';
|
|
|
6
7
|
import { RuntimeFiber } from 'effect/Fiber';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
|
-
* Node.js configuration loader
|
|
10
|
+
* Node.js configuration loader
|
|
10
11
|
*
|
|
11
|
-
* Provides
|
|
12
|
+
* Provides configuration loading using native Node.js APIs (fs, fetch)
|
|
13
|
+
* This module doesn't require Effect Platform, making it work without Effect installed.
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -46,17 +48,12 @@ interface ConfigLoaderOptions {
|
|
|
46
48
|
*/
|
|
47
49
|
interface EffectInstrumentationOptions extends ConfigLoaderOptions {
|
|
48
50
|
/**
|
|
49
|
-
*
|
|
50
|
-
* @default process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318'
|
|
51
|
-
*/
|
|
52
|
-
otlpEndpoint?: string;
|
|
53
|
-
/**
|
|
54
|
-
* Service name
|
|
51
|
+
* Service name for Effect spans
|
|
55
52
|
* @default process.env.OTEL_SERVICE_NAME || 'effect-service'
|
|
56
53
|
*/
|
|
57
54
|
serviceName?: string;
|
|
58
55
|
/**
|
|
59
|
-
* Service version
|
|
56
|
+
* Service version for Effect spans
|
|
60
57
|
* @default process.env.npm_package_version || '1.0.0'
|
|
61
58
|
*/
|
|
62
59
|
serviceVersion?: string;
|
|
@@ -66,20 +63,17 @@ interface EffectInstrumentationOptions extends ConfigLoaderOptions {
|
|
|
66
63
|
*/
|
|
67
64
|
autoExtractMetadata?: boolean;
|
|
68
65
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* - Not recommended unless you have specific requirements
|
|
79
|
-
*
|
|
80
|
-
* @default true
|
|
66
|
+
* OTLP endpoint URL (only used when exporter mode is 'standalone')
|
|
67
|
+
* @default process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318'
|
|
68
|
+
*/
|
|
69
|
+
otlpEndpoint?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Exporter mode:
|
|
72
|
+
* - 'unified': Use global TracerProvider from Node SDK (recommended, enables filtering)
|
|
73
|
+
* - 'standalone': Use Effect's own OTLP exporter (bypasses Node SDK filtering)
|
|
74
|
+
* @default 'unified'
|
|
81
75
|
*/
|
|
82
|
-
|
|
76
|
+
exporterMode?: 'unified' | 'standalone';
|
|
83
77
|
}
|
|
84
78
|
/**
|
|
85
79
|
* Create Effect instrumentation layer with custom options
|
|
@@ -118,11 +112,12 @@ declare function createEffectInstrumentation(options?: EffectInstrumentationOpti
|
|
|
118
112
|
*
|
|
119
113
|
* Uses the global OpenTelemetry tracer provider that was set up by
|
|
120
114
|
* initializeInstrumentation(). This ensures all traces (Express, Effect, etc.)
|
|
121
|
-
* go
|
|
115
|
+
* go through the same TracerProvider and PatternSpanProcessor.
|
|
122
116
|
*
|
|
123
117
|
* Context Propagation:
|
|
124
118
|
* - Automatically continues traces from NodeSDK auto-instrumentation
|
|
125
119
|
* - Effect spans become children of HTTP request spans
|
|
120
|
+
* - Respects http.ignore_incoming_paths and other filtering patterns
|
|
126
121
|
* - No configuration needed
|
|
127
122
|
*
|
|
128
123
|
* @example
|
|
@@ -138,7 +133,7 @@ declare function createEffectInstrumentation(options?: EffectInstrumentationOpti
|
|
|
138
133
|
* )
|
|
139
134
|
* ```
|
|
140
135
|
*/
|
|
141
|
-
declare const EffectInstrumentationLive: Layer.Layer<
|
|
136
|
+
declare const EffectInstrumentationLive: Layer.Layer<Tracer.OtelTracer, never, never>;
|
|
142
137
|
|
|
143
138
|
/**
|
|
144
139
|
* Effect-specific span annotation helpers
|
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
import { Data, Context, Effect, Layer, FiberSet as FiberSet$1, Fiber, Option, FiberId, Tracer } from 'effect';
|
|
1
|
+
import { Data, Context, Effect, Layer, FiberSet as FiberSet$1, Fiber, Option, FiberId, Tracer as Tracer$1 } from 'effect';
|
|
2
|
+
import * as Tracer from '@effect/opentelemetry/Tracer';
|
|
3
|
+
import * as Resource from '@effect/opentelemetry/Resource';
|
|
2
4
|
import * as Otlp from '@effect/opentelemetry/Otlp';
|
|
3
5
|
import { FetchHttpClient } from '@effect/platform';
|
|
4
6
|
import { TraceFlags, trace, context } from '@opentelemetry/api';
|
|
7
|
+
import { TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS, ATTR_TELEMETRY_SDK_NAME, ATTR_TELEMETRY_SDK_LANGUAGE } from '@opentelemetry/semantic-conventions';
|
|
5
8
|
import { FileSystem } from '@effect/platform/FileSystem';
|
|
6
9
|
import * as HttpClient from '@effect/platform/HttpClient';
|
|
7
10
|
import * as HttpClientRequest from '@effect/platform/HttpClientRequest';
|
|
8
11
|
import { parse } from 'yaml';
|
|
9
12
|
import { z } from 'zod';
|
|
10
|
-
import { NodeContext } from '@effect/platform-node';
|
|
11
13
|
|
|
12
14
|
// src/integrations/effect/effect-tracer.ts
|
|
13
|
-
|
|
14
|
-
// ../../node_modules/.pnpm/@opentelemetry+semantic-conventions@1.38.0/node_modules/@opentelemetry/semantic-conventions/build/esm/stable_attributes.js
|
|
15
|
-
var ATTR_TELEMETRY_SDK_LANGUAGE = "telemetry.sdk.language";
|
|
16
|
-
var TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS = "nodejs";
|
|
17
|
-
var ATTR_TELEMETRY_SDK_NAME = "telemetry.sdk.name";
|
|
18
15
|
var __defProp = Object.defineProperty;
|
|
19
16
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
20
17
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -45,6 +42,69 @@ var AutoIsolationConfigSchema = z.object({
|
|
|
45
42
|
add_metadata: z.boolean().default(true)
|
|
46
43
|
}).default({})
|
|
47
44
|
});
|
|
45
|
+
var SpanNamingRuleSchema = z.object({
|
|
46
|
+
// Match criteria (all specified criteria must match)
|
|
47
|
+
match: z.object({
|
|
48
|
+
// Regex pattern to match file path
|
|
49
|
+
file: z.string().optional(),
|
|
50
|
+
// Regex pattern to match function name
|
|
51
|
+
function: z.string().optional(),
|
|
52
|
+
// Regex pattern to match module name
|
|
53
|
+
module: z.string().optional()
|
|
54
|
+
}),
|
|
55
|
+
// Span name template with variables:
|
|
56
|
+
// {fiber_id} - Fiber ID
|
|
57
|
+
// {function} - Function name
|
|
58
|
+
// {module} - Module name
|
|
59
|
+
// {file} - File path
|
|
60
|
+
// {line} - Line number
|
|
61
|
+
// {operator} - Effect operator (gen, all, forEach, etc.)
|
|
62
|
+
// {match:field:N} - Captured regex group from match
|
|
63
|
+
name: z.string()
|
|
64
|
+
});
|
|
65
|
+
var AutoInstrumentationConfigSchema = z.object({
|
|
66
|
+
// Enable/disable auto-instrumentation
|
|
67
|
+
enabled: z.boolean().default(false),
|
|
68
|
+
// Tracing granularity
|
|
69
|
+
// - 'fiber': Trace at fiber creation (recommended, lower overhead)
|
|
70
|
+
// - 'operator': Trace each Effect operator (higher granularity, more overhead)
|
|
71
|
+
granularity: z.enum(["fiber", "operator"]).default("fiber"),
|
|
72
|
+
// Smart span naming configuration
|
|
73
|
+
span_naming: z.object({
|
|
74
|
+
// Default span name template when no rules match
|
|
75
|
+
default: z.string().default("effect.fiber.{fiber_id}"),
|
|
76
|
+
// Infer span names from source code (requires stack trace parsing)
|
|
77
|
+
// Adds ~50-100μs overhead per fiber
|
|
78
|
+
infer_from_source: z.boolean().default(true),
|
|
79
|
+
// Naming rules (first match wins)
|
|
80
|
+
rules: z.array(SpanNamingRuleSchema).default([])
|
|
81
|
+
}).default({}),
|
|
82
|
+
// Pattern-based filtering
|
|
83
|
+
filter: z.object({
|
|
84
|
+
// Only trace spans matching these patterns (empty = trace all)
|
|
85
|
+
include: z.array(z.string()).default([]),
|
|
86
|
+
// Never trace spans matching these patterns
|
|
87
|
+
exclude: z.array(z.string()).default([])
|
|
88
|
+
}).default({}),
|
|
89
|
+
// Performance controls
|
|
90
|
+
performance: z.object({
|
|
91
|
+
// Sample rate (0.0 - 1.0)
|
|
92
|
+
sampling_rate: z.number().min(0).max(1).default(1),
|
|
93
|
+
// Skip fibers shorter than this duration (e.g., "10ms", "100 millis")
|
|
94
|
+
min_duration: z.string().default("0ms"),
|
|
95
|
+
// Maximum concurrent traced fibers (0 = unlimited)
|
|
96
|
+
max_concurrent: z.number().default(0)
|
|
97
|
+
}).default({}),
|
|
98
|
+
// Automatic metadata extraction
|
|
99
|
+
metadata: z.object({
|
|
100
|
+
// Extract Effect fiber information
|
|
101
|
+
fiber_info: z.boolean().default(true),
|
|
102
|
+
// Extract source location (file:line)
|
|
103
|
+
source_location: z.boolean().default(true),
|
|
104
|
+
// Extract parent fiber information
|
|
105
|
+
parent_fiber: z.boolean().default(true)
|
|
106
|
+
}).default({})
|
|
107
|
+
});
|
|
48
108
|
var HttpFilteringConfigSchema = z.object({
|
|
49
109
|
// Patterns to ignore for outgoing HTTP requests (string patterns only in YAML)
|
|
50
110
|
ignore_outgoing_urls: z.array(z.string()).optional(),
|
|
@@ -66,6 +126,30 @@ var HttpFilteringConfigSchema = z.object({
|
|
|
66
126
|
include_urls: z.array(z.string()).optional()
|
|
67
127
|
}).optional()
|
|
68
128
|
});
|
|
129
|
+
var ExporterConfigSchema = z.object({
|
|
130
|
+
// Exporter type: 'otlp' | 'console' | 'none'
|
|
131
|
+
// - 'otlp': Export to OTLP endpoint (production)
|
|
132
|
+
// - 'console': Log spans to console (development)
|
|
133
|
+
// - 'none': No export (disable tracing)
|
|
134
|
+
type: z.enum(["otlp", "console", "none"]).default("otlp"),
|
|
135
|
+
// OTLP endpoint URL (for type: otlp)
|
|
136
|
+
// Defaults to OTEL_EXPORTER_OTLP_ENDPOINT env var or http://localhost:4318
|
|
137
|
+
endpoint: z.string().optional(),
|
|
138
|
+
// Custom headers to send with OTLP requests (for type: otlp)
|
|
139
|
+
// Useful for authentication (x-api-key, Authorization, etc.)
|
|
140
|
+
headers: z.record(z.string()).optional(),
|
|
141
|
+
// Span processor type
|
|
142
|
+
// - 'batch': Batch spans for export (production, lower overhead)
|
|
143
|
+
// - 'simple': Export immediately (development, no batching delay)
|
|
144
|
+
processor: z.enum(["batch", "simple"]).default("batch"),
|
|
145
|
+
// Batch processor settings (for processor: batch)
|
|
146
|
+
batch: z.object({
|
|
147
|
+
// Max time to wait before exporting (milliseconds)
|
|
148
|
+
scheduled_delay_millis: z.number().default(1e3),
|
|
149
|
+
// Max batch size
|
|
150
|
+
max_export_batch_size: z.number().default(100)
|
|
151
|
+
}).optional()
|
|
152
|
+
});
|
|
69
153
|
var InstrumentationConfigSchema = z.object({
|
|
70
154
|
version: z.string(),
|
|
71
155
|
instrumentation: z.object({
|
|
@@ -76,11 +160,54 @@ var InstrumentationConfigSchema = z.object({
|
|
|
76
160
|
ignore_patterns: z.array(PatternConfigSchema)
|
|
77
161
|
}),
|
|
78
162
|
effect: z.object({
|
|
163
|
+
// Enable/disable Effect tracing entirely
|
|
164
|
+
// When false, EffectInstrumentationLive returns Layer.empty
|
|
165
|
+
enabled: z.boolean().default(true),
|
|
166
|
+
// Exporter mode (legacy - use exporter.type instead):
|
|
167
|
+
// - "unified": Use global TracerProvider from Node SDK (recommended, enables filtering)
|
|
168
|
+
// - "standalone": Use Effect's own OTLP exporter (bypasses Node SDK filtering)
|
|
169
|
+
exporter: z.enum(["unified", "standalone"]).default("unified"),
|
|
170
|
+
// Exporter configuration (for auto-instrumentation)
|
|
171
|
+
exporter_config: ExporterConfigSchema.optional(),
|
|
79
172
|
auto_extract_metadata: z.boolean(),
|
|
80
|
-
auto_isolation: AutoIsolationConfigSchema.optional()
|
|
173
|
+
auto_isolation: AutoIsolationConfigSchema.optional(),
|
|
174
|
+
// Auto-instrumentation: automatic tracing of all Effect fibers
|
|
175
|
+
auto_instrumentation: AutoInstrumentationConfigSchema.optional()
|
|
81
176
|
}).optional(),
|
|
82
177
|
http: HttpFilteringConfigSchema.optional()
|
|
83
178
|
});
|
|
179
|
+
var defaultConfig = {
|
|
180
|
+
version: "1.0",
|
|
181
|
+
instrumentation: {
|
|
182
|
+
enabled: true,
|
|
183
|
+
logging: "on",
|
|
184
|
+
description: "Default instrumentation configuration",
|
|
185
|
+
instrument_patterns: [
|
|
186
|
+
{ pattern: "^app\\.", enabled: true, description: "Application operations" },
|
|
187
|
+
{ pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
|
|
188
|
+
{ pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
|
|
189
|
+
],
|
|
190
|
+
ignore_patterns: [
|
|
191
|
+
{ pattern: "^test\\.", description: "Test utilities" },
|
|
192
|
+
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
193
|
+
{ pattern: "^health\\.", description: "Health checks" }
|
|
194
|
+
]
|
|
195
|
+
},
|
|
196
|
+
effect: {
|
|
197
|
+
enabled: true,
|
|
198
|
+
exporter: "unified",
|
|
199
|
+
auto_extract_metadata: true
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
function parseAndValidateConfig(content) {
|
|
203
|
+
let parsed;
|
|
204
|
+
if (typeof content === "string") {
|
|
205
|
+
parsed = parse(content);
|
|
206
|
+
} else {
|
|
207
|
+
parsed = content;
|
|
208
|
+
}
|
|
209
|
+
return InstrumentationConfigSchema.parse(parsed);
|
|
210
|
+
}
|
|
84
211
|
(class extends Data.TaggedError("ConfigError") {
|
|
85
212
|
get message() {
|
|
86
213
|
return this.reason;
|
|
@@ -258,7 +385,7 @@ var makeConfigLoader = Effect.gen(function* () {
|
|
|
258
385
|
})
|
|
259
386
|
});
|
|
260
387
|
});
|
|
261
|
-
|
|
388
|
+
Layer.effect(ConfigLoader, makeConfigLoader);
|
|
262
389
|
var PatternMatcher = class {
|
|
263
390
|
constructor(config) {
|
|
264
391
|
__publicField(this, "ignorePatterns", []);
|
|
@@ -406,84 +533,58 @@ var Logger = class {
|
|
|
406
533
|
}
|
|
407
534
|
};
|
|
408
535
|
var logger = new Logger();
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
);
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
}).pipe(Effect.provide(NodeConfigLoaderLive))
|
|
419
|
-
);
|
|
536
|
+
async function loadFromFile(filePath) {
|
|
537
|
+
const { readFile } = await import('fs/promises');
|
|
538
|
+
const content = await readFile(filePath, "utf-8");
|
|
539
|
+
return parseAndValidateConfig(content);
|
|
540
|
+
}
|
|
541
|
+
async function loadFromUrl(url) {
|
|
542
|
+
const response = await fetch(url);
|
|
543
|
+
if (!response.ok) {
|
|
544
|
+
throw new Error(`Failed to fetch config from ${url}: ${response.statusText}`);
|
|
420
545
|
}
|
|
421
|
-
|
|
546
|
+
const content = await response.text();
|
|
547
|
+
return parseAndValidateConfig(content);
|
|
422
548
|
}
|
|
423
|
-
async function loadConfig(uri,
|
|
424
|
-
if (
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
return
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
return Effect.runPromise(loader.loadFromUri(uri));
|
|
549
|
+
async function loadConfig(uri, _options) {
|
|
550
|
+
if (uri.startsWith("http://") || uri.startsWith("https://")) {
|
|
551
|
+
return loadFromUrl(uri);
|
|
552
|
+
}
|
|
553
|
+
if (uri.startsWith("file://")) {
|
|
554
|
+
const filePath = uri.slice(7);
|
|
555
|
+
return loadFromFile(filePath);
|
|
556
|
+
}
|
|
557
|
+
return loadFromFile(uri);
|
|
433
558
|
}
|
|
434
559
|
async function loadConfigFromInline(content) {
|
|
435
|
-
|
|
436
|
-
return Effect.runPromise(loader.loadFromInline(content));
|
|
437
|
-
}
|
|
438
|
-
function getDefaultConfig() {
|
|
439
|
-
return {
|
|
440
|
-
version: "1.0",
|
|
441
|
-
instrumentation: {
|
|
442
|
-
enabled: true,
|
|
443
|
-
logging: "on",
|
|
444
|
-
description: "Default instrumentation configuration",
|
|
445
|
-
instrument_patterns: [
|
|
446
|
-
{ pattern: "^app\\.", enabled: true, description: "Application operations" },
|
|
447
|
-
{ pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
|
|
448
|
-
{ pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
|
|
449
|
-
],
|
|
450
|
-
ignore_patterns: [
|
|
451
|
-
{ pattern: "^test\\.", description: "Test utilities" },
|
|
452
|
-
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
453
|
-
{ pattern: "^health\\.", description: "Health checks" }
|
|
454
|
-
]
|
|
455
|
-
},
|
|
456
|
-
effect: {
|
|
457
|
-
auto_extract_metadata: true
|
|
458
|
-
}
|
|
459
|
-
};
|
|
560
|
+
return parseAndValidateConfig(content);
|
|
460
561
|
}
|
|
461
562
|
async function loadConfigWithOptions(options = {}) {
|
|
462
|
-
const loadOptions = options.cacheTimeout !== void 0 ? { cacheTimeout: options.cacheTimeout } : void 0;
|
|
463
563
|
if (options.config) {
|
|
464
564
|
return loadConfigFromInline(options.config);
|
|
465
565
|
}
|
|
466
566
|
const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
|
|
467
567
|
if (envConfigPath) {
|
|
468
|
-
return loadConfig(envConfigPath
|
|
568
|
+
return loadConfig(envConfigPath);
|
|
469
569
|
}
|
|
470
570
|
if (options.configUrl) {
|
|
471
|
-
return loadConfig(options.configUrl
|
|
571
|
+
return loadConfig(options.configUrl);
|
|
472
572
|
}
|
|
473
573
|
if (options.configPath) {
|
|
474
|
-
return loadConfig(options.configPath
|
|
574
|
+
return loadConfig(options.configPath);
|
|
475
575
|
}
|
|
476
576
|
const { existsSync } = await import('fs');
|
|
477
577
|
const { join } = await import('path');
|
|
478
578
|
const defaultPath = join(process.cwd(), "instrumentation.yaml");
|
|
479
579
|
if (existsSync(defaultPath)) {
|
|
480
|
-
return loadConfig(defaultPath
|
|
580
|
+
return loadConfig(defaultPath);
|
|
481
581
|
}
|
|
482
|
-
return
|
|
582
|
+
return defaultConfig;
|
|
483
583
|
}
|
|
484
584
|
|
|
485
585
|
// src/integrations/effect/effect-tracer.ts
|
|
486
|
-
var SDK_NAME = "@effect/opentelemetry
|
|
586
|
+
var SDK_NAME = "@effect/opentelemetry";
|
|
587
|
+
var ATTR_TELEMETRY_EXPORTER_MODE = "telemetry.exporter.mode";
|
|
487
588
|
function createEffectInstrumentation(options = {}) {
|
|
488
589
|
return Layer.unwrapEffect(
|
|
489
590
|
Effect.gen(function* () {
|
|
@@ -494,90 +595,89 @@ function createEffectInstrumentation(options = {}) {
|
|
|
494
595
|
message: error instanceof Error ? error.message : String(error)
|
|
495
596
|
})
|
|
496
597
|
});
|
|
598
|
+
const effectEnabled = process.env.OTEL_EFFECT_ENABLED !== "false" && (config.effect?.enabled ?? true);
|
|
599
|
+
if (!effectEnabled) {
|
|
600
|
+
logger.log("@atrim/instrumentation/effect: Effect tracing disabled via config");
|
|
601
|
+
return Layer.empty;
|
|
602
|
+
}
|
|
497
603
|
yield* Effect.sync(() => {
|
|
498
604
|
const loggingLevel = config.instrumentation.logging || "on";
|
|
499
605
|
logger.setLevel(loggingLevel);
|
|
500
606
|
});
|
|
501
607
|
yield* Effect.sync(() => initializePatternMatcher(config));
|
|
502
|
-
const otlpEndpoint = options.otlpEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
|
|
503
608
|
const serviceName = options.serviceName || process.env.OTEL_SERVICE_NAME || "effect-service";
|
|
504
609
|
const serviceVersion = options.serviceVersion || process.env.npm_package_version || "1.0.0";
|
|
505
|
-
const
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
610
|
+
const exporterMode = options.exporterMode ?? config.effect?.exporter ?? "unified";
|
|
611
|
+
const resourceAttributes = {
|
|
612
|
+
"platform.component": "effect",
|
|
613
|
+
[ATTR_TELEMETRY_SDK_LANGUAGE]: TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
|
|
614
|
+
[ATTR_TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
615
|
+
[ATTR_TELEMETRY_EXPORTER_MODE]: exporterMode
|
|
616
|
+
};
|
|
617
|
+
if (exporterMode === "standalone") {
|
|
618
|
+
const otlpEndpoint = options.otlpEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
|
|
619
|
+
logger.log("Effect OpenTelemetry instrumentation (standalone)");
|
|
620
|
+
logger.log(` Service: ${serviceName}`);
|
|
621
|
+
logger.log(` Endpoint: ${otlpEndpoint}`);
|
|
622
|
+
logger.log(" WARNING: Standalone mode bypasses Node SDK filtering");
|
|
623
|
+
return Otlp.layer({
|
|
624
|
+
baseUrl: otlpEndpoint,
|
|
625
|
+
resource: {
|
|
626
|
+
serviceName,
|
|
627
|
+
serviceVersion,
|
|
628
|
+
attributes: resourceAttributes
|
|
629
|
+
},
|
|
630
|
+
// Bridge Effect context to OpenTelemetry global context
|
|
631
|
+
tracerContext: (f, span) => {
|
|
632
|
+
if (span._tag !== "Span") {
|
|
633
|
+
return f();
|
|
634
|
+
}
|
|
635
|
+
const spanContext = {
|
|
636
|
+
traceId: span.traceId,
|
|
637
|
+
spanId: span.spanId,
|
|
638
|
+
traceFlags: span.sampled ? TraceFlags.SAMPLED : TraceFlags.NONE
|
|
639
|
+
};
|
|
640
|
+
const otelSpan = trace.wrapSpanContext(spanContext);
|
|
641
|
+
return context.with(trace.setSpan(context.active(), otelSpan), f);
|
|
530
642
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
643
|
+
}).pipe(Layer.provide(FetchHttpClient.layer));
|
|
644
|
+
} else {
|
|
645
|
+
logger.log("Effect OpenTelemetry instrumentation (unified)");
|
|
646
|
+
logger.log(` Service: ${serviceName}`);
|
|
647
|
+
logger.log(" Using global TracerProvider for span export");
|
|
648
|
+
return Tracer.layerGlobal.pipe(
|
|
649
|
+
Layer.provide(
|
|
650
|
+
Resource.layer({
|
|
651
|
+
serviceName,
|
|
652
|
+
serviceVersion,
|
|
653
|
+
attributes: resourceAttributes
|
|
654
|
+
})
|
|
655
|
+
)
|
|
656
|
+
);
|
|
542
657
|
}
|
|
543
|
-
return otlpLayer;
|
|
544
658
|
})
|
|
545
659
|
).pipe(Layer.orDie);
|
|
546
660
|
}
|
|
547
661
|
var EffectInstrumentationLive = Effect.sync(() => {
|
|
548
|
-
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
|
|
549
662
|
const serviceName = process.env.OTEL_SERVICE_NAME || "effect-service";
|
|
550
663
|
const serviceVersion = process.env.npm_package_version || "1.0.0";
|
|
551
664
|
logger.minimal(`@atrim/instrumentation/effect: Effect tracing enabled (${serviceName})`);
|
|
552
|
-
logger.log("
|
|
553
|
-
logger.log(`
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
tracerContext: (f, span) => {
|
|
569
|
-
if (span._tag !== "Span") {
|
|
570
|
-
return f();
|
|
571
|
-
}
|
|
572
|
-
const spanContext = {
|
|
573
|
-
traceId: span.traceId,
|
|
574
|
-
spanId: span.spanId,
|
|
575
|
-
traceFlags: span.sampled ? TraceFlags.SAMPLED : TraceFlags.NONE
|
|
576
|
-
};
|
|
577
|
-
const otelSpan = trace.wrapSpanContext(spanContext);
|
|
578
|
-
return context.with(trace.setSpan(context.active(), otelSpan), f);
|
|
579
|
-
}
|
|
580
|
-
}).pipe(Layer.provide(FetchHttpClient.layer));
|
|
665
|
+
logger.log("Effect OpenTelemetry tracer (unified)");
|
|
666
|
+
logger.log(` Service: ${serviceName}`);
|
|
667
|
+
return Tracer.layerGlobal.pipe(
|
|
668
|
+
Layer.provide(
|
|
669
|
+
Resource.layer({
|
|
670
|
+
serviceName,
|
|
671
|
+
serviceVersion,
|
|
672
|
+
attributes: {
|
|
673
|
+
"platform.component": "effect",
|
|
674
|
+
[ATTR_TELEMETRY_SDK_LANGUAGE]: TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
|
|
675
|
+
[ATTR_TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
676
|
+
[ATTR_TELEMETRY_EXPORTER_MODE]: "unified"
|
|
677
|
+
}
|
|
678
|
+
})
|
|
679
|
+
)
|
|
680
|
+
);
|
|
581
681
|
}).pipe(Layer.unwrapEffect);
|
|
582
682
|
function annotateUser(userId, email, username) {
|
|
583
683
|
const attributes = {
|
|
@@ -766,7 +866,7 @@ var runIsolated = (set, effect, name, options) => {
|
|
|
766
866
|
return FiberSet$1.run(set, effect, { propagateInterruption });
|
|
767
867
|
}
|
|
768
868
|
return Effect.gen(function* () {
|
|
769
|
-
const maybeParent = yield* Effect.serviceOption(Tracer.ParentSpan);
|
|
869
|
+
const maybeParent = yield* Effect.serviceOption(Tracer$1.ParentSpan);
|
|
770
870
|
if (maybeParent._tag === "None" || !captureLogicalParent) {
|
|
771
871
|
const isolated2 = effect.pipe(
|
|
772
872
|
Effect.withSpan(name, {
|