@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
package/target/dist/index.d.cts
CHANGED
|
@@ -46,35 +46,33 @@ declare function createOtlpExporter(options?: OtlpExporterOptions): OTLPTraceExp
|
|
|
46
46
|
declare function getOtlpEndpoint(options?: OtlpExporterOptions): string;
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Node.js configuration loader
|
|
49
|
+
* Node.js configuration loader
|
|
50
50
|
*
|
|
51
|
-
* Provides
|
|
51
|
+
* Provides configuration loading using native Node.js APIs (fs, fetch)
|
|
52
|
+
* This module doesn't require Effect Platform, making it work without Effect installed.
|
|
52
53
|
*/
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
|
-
*
|
|
56
|
-
* @internal
|
|
57
|
-
*/
|
|
58
|
-
declare function _resetConfigLoaderCache(): void;
|
|
59
|
-
/**
|
|
60
|
-
* Load configuration from URI (Promise-based convenience API)
|
|
61
|
-
*
|
|
62
|
-
* Automatically provides Node.js platform layers (FileSystem + HttpClient)
|
|
56
|
+
* Load configuration from URI (file path or URL)
|
|
63
57
|
*
|
|
64
58
|
* @param uri - Configuration URI (file://, http://, https://, or relative path)
|
|
65
|
-
* @param options - Optional loading options (e.g., to disable caching)
|
|
66
59
|
* @returns Promise that resolves to validated configuration
|
|
67
60
|
*/
|
|
68
|
-
declare function loadConfig(uri: string,
|
|
61
|
+
declare function loadConfig(uri: string, _options?: {
|
|
69
62
|
cacheTimeout?: number;
|
|
70
63
|
}): Promise<InstrumentationConfig>;
|
|
71
64
|
/**
|
|
72
|
-
* Load configuration from inline content
|
|
65
|
+
* Load configuration from inline content
|
|
73
66
|
*
|
|
74
67
|
* @param content - YAML string, JSON string, or plain object
|
|
75
68
|
* @returns Promise that resolves to validated configuration
|
|
76
69
|
*/
|
|
77
70
|
declare function loadConfigFromInline(content: string | unknown): Promise<InstrumentationConfig>;
|
|
71
|
+
/**
|
|
72
|
+
* Reset the config loader cache (no-op for native implementation)
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
declare function _resetConfigLoaderCache(): void;
|
|
78
76
|
/**
|
|
79
77
|
* Legacy options interface for backward compatibility
|
|
80
78
|
*/
|
|
@@ -548,6 +546,10 @@ declare function getServiceVersionAsync(): Promise<string | undefined>;
|
|
|
548
546
|
* This processor filters spans based on configured patterns before they are exported.
|
|
549
547
|
* It wraps another processor (typically BatchSpanProcessor) and only forwards spans
|
|
550
548
|
* that match the instrumentation patterns.
|
|
549
|
+
*
|
|
550
|
+
* Filtering is applied at two levels:
|
|
551
|
+
* 1. Span name patterns (instrument_patterns / ignore_patterns)
|
|
552
|
+
* 2. HTTP path patterns (http.ignore_incoming_paths) - for HTTP spans
|
|
551
553
|
*/
|
|
552
554
|
|
|
553
555
|
/**
|
|
@@ -570,6 +572,7 @@ declare function getServiceVersionAsync(): Promise<string | undefined>;
|
|
|
570
572
|
declare class PatternSpanProcessor implements SpanProcessor {
|
|
571
573
|
private matcher;
|
|
572
574
|
private wrappedProcessor;
|
|
575
|
+
private httpIgnorePatterns;
|
|
573
576
|
constructor(config: InstrumentationConfig, wrappedProcessor: SpanProcessor);
|
|
574
577
|
/**
|
|
575
578
|
* Called when a span is started
|
|
@@ -582,8 +585,20 @@ declare class PatternSpanProcessor implements SpanProcessor {
|
|
|
582
585
|
* Called when a span is ended
|
|
583
586
|
*
|
|
584
587
|
* This is where we make the final decision on whether to export the span.
|
|
588
|
+
* We check both span name patterns and HTTP path patterns.
|
|
585
589
|
*/
|
|
586
590
|
onEnd(span: ReadableSpan): void;
|
|
591
|
+
/**
|
|
592
|
+
* Check if span should be ignored based on HTTP path attributes
|
|
593
|
+
*
|
|
594
|
+
* This checks the span's url.path, http.route, or http.target attributes
|
|
595
|
+
* against the configured http.ignore_incoming_paths patterns.
|
|
596
|
+
*
|
|
597
|
+
* This enables filtering of Effect HTTP spans (and any other HTTP spans)
|
|
598
|
+
* based on path patterns, which is essential for filtering out OTLP
|
|
599
|
+
* endpoint requests like /v1/traces, /v1/logs, /v1/metrics.
|
|
600
|
+
*/
|
|
601
|
+
private shouldIgnoreHttpSpan;
|
|
587
602
|
/**
|
|
588
603
|
* Shutdown the processor
|
|
589
604
|
*/
|
package/target/dist/index.d.ts
CHANGED
|
@@ -46,35 +46,33 @@ declare function createOtlpExporter(options?: OtlpExporterOptions): OTLPTraceExp
|
|
|
46
46
|
declare function getOtlpEndpoint(options?: OtlpExporterOptions): string;
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Node.js configuration loader
|
|
49
|
+
* Node.js configuration loader
|
|
50
50
|
*
|
|
51
|
-
* Provides
|
|
51
|
+
* Provides configuration loading using native Node.js APIs (fs, fetch)
|
|
52
|
+
* This module doesn't require Effect Platform, making it work without Effect installed.
|
|
52
53
|
*/
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
|
-
*
|
|
56
|
-
* @internal
|
|
57
|
-
*/
|
|
58
|
-
declare function _resetConfigLoaderCache(): void;
|
|
59
|
-
/**
|
|
60
|
-
* Load configuration from URI (Promise-based convenience API)
|
|
61
|
-
*
|
|
62
|
-
* Automatically provides Node.js platform layers (FileSystem + HttpClient)
|
|
56
|
+
* Load configuration from URI (file path or URL)
|
|
63
57
|
*
|
|
64
58
|
* @param uri - Configuration URI (file://, http://, https://, or relative path)
|
|
65
|
-
* @param options - Optional loading options (e.g., to disable caching)
|
|
66
59
|
* @returns Promise that resolves to validated configuration
|
|
67
60
|
*/
|
|
68
|
-
declare function loadConfig(uri: string,
|
|
61
|
+
declare function loadConfig(uri: string, _options?: {
|
|
69
62
|
cacheTimeout?: number;
|
|
70
63
|
}): Promise<InstrumentationConfig>;
|
|
71
64
|
/**
|
|
72
|
-
* Load configuration from inline content
|
|
65
|
+
* Load configuration from inline content
|
|
73
66
|
*
|
|
74
67
|
* @param content - YAML string, JSON string, or plain object
|
|
75
68
|
* @returns Promise that resolves to validated configuration
|
|
76
69
|
*/
|
|
77
70
|
declare function loadConfigFromInline(content: string | unknown): Promise<InstrumentationConfig>;
|
|
71
|
+
/**
|
|
72
|
+
* Reset the config loader cache (no-op for native implementation)
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
declare function _resetConfigLoaderCache(): void;
|
|
78
76
|
/**
|
|
79
77
|
* Legacy options interface for backward compatibility
|
|
80
78
|
*/
|
|
@@ -548,6 +546,10 @@ declare function getServiceVersionAsync(): Promise<string | undefined>;
|
|
|
548
546
|
* This processor filters spans based on configured patterns before they are exported.
|
|
549
547
|
* It wraps another processor (typically BatchSpanProcessor) and only forwards spans
|
|
550
548
|
* that match the instrumentation patterns.
|
|
549
|
+
*
|
|
550
|
+
* Filtering is applied at two levels:
|
|
551
|
+
* 1. Span name patterns (instrument_patterns / ignore_patterns)
|
|
552
|
+
* 2. HTTP path patterns (http.ignore_incoming_paths) - for HTTP spans
|
|
551
553
|
*/
|
|
552
554
|
|
|
553
555
|
/**
|
|
@@ -570,6 +572,7 @@ declare function getServiceVersionAsync(): Promise<string | undefined>;
|
|
|
570
572
|
declare class PatternSpanProcessor implements SpanProcessor {
|
|
571
573
|
private matcher;
|
|
572
574
|
private wrappedProcessor;
|
|
575
|
+
private httpIgnorePatterns;
|
|
573
576
|
constructor(config: InstrumentationConfig, wrappedProcessor: SpanProcessor);
|
|
574
577
|
/**
|
|
575
578
|
* Called when a span is started
|
|
@@ -582,8 +585,20 @@ declare class PatternSpanProcessor implements SpanProcessor {
|
|
|
582
585
|
* Called when a span is ended
|
|
583
586
|
*
|
|
584
587
|
* This is where we make the final decision on whether to export the span.
|
|
588
|
+
* We check both span name patterns and HTTP path patterns.
|
|
585
589
|
*/
|
|
586
590
|
onEnd(span: ReadableSpan): void;
|
|
591
|
+
/**
|
|
592
|
+
* Check if span should be ignored based on HTTP path attributes
|
|
593
|
+
*
|
|
594
|
+
* This checks the span's url.path, http.route, or http.target attributes
|
|
595
|
+
* against the configured http.ignore_incoming_paths patterns.
|
|
596
|
+
*
|
|
597
|
+
* This enables filtering of Effect HTTP spans (and any other HTTP spans)
|
|
598
|
+
* based on path patterns, which is essential for filtering out OTLP
|
|
599
|
+
* endpoint requests like /v1/traces, /v1/logs, /v1/metrics.
|
|
600
|
+
*/
|
|
601
|
+
private shouldIgnoreHttpSpan;
|
|
587
602
|
/**
|
|
588
603
|
* Shutdown the processor
|
|
589
604
|
*/
|
package/target/dist/index.js
CHANGED
|
@@ -11,8 +11,7 @@ import { z } from 'zod';
|
|
|
11
11
|
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
|
12
12
|
import { readFile } from 'fs/promises';
|
|
13
13
|
import { join } from 'path';
|
|
14
|
-
import {
|
|
15
|
-
import { FetchHttpClient } from '@effect/platform';
|
|
14
|
+
import { createRequire } from 'module';
|
|
16
15
|
|
|
17
16
|
var __defProp = Object.defineProperty;
|
|
18
17
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -53,6 +52,69 @@ var AutoIsolationConfigSchema = z.object({
|
|
|
53
52
|
add_metadata: z.boolean().default(true)
|
|
54
53
|
}).default({})
|
|
55
54
|
});
|
|
55
|
+
var SpanNamingRuleSchema = z.object({
|
|
56
|
+
// Match criteria (all specified criteria must match)
|
|
57
|
+
match: z.object({
|
|
58
|
+
// Regex pattern to match file path
|
|
59
|
+
file: z.string().optional(),
|
|
60
|
+
// Regex pattern to match function name
|
|
61
|
+
function: z.string().optional(),
|
|
62
|
+
// Regex pattern to match module name
|
|
63
|
+
module: z.string().optional()
|
|
64
|
+
}),
|
|
65
|
+
// Span name template with variables:
|
|
66
|
+
// {fiber_id} - Fiber ID
|
|
67
|
+
// {function} - Function name
|
|
68
|
+
// {module} - Module name
|
|
69
|
+
// {file} - File path
|
|
70
|
+
// {line} - Line number
|
|
71
|
+
// {operator} - Effect operator (gen, all, forEach, etc.)
|
|
72
|
+
// {match:field:N} - Captured regex group from match
|
|
73
|
+
name: z.string()
|
|
74
|
+
});
|
|
75
|
+
var AutoInstrumentationConfigSchema = z.object({
|
|
76
|
+
// Enable/disable auto-instrumentation
|
|
77
|
+
enabled: z.boolean().default(false),
|
|
78
|
+
// Tracing granularity
|
|
79
|
+
// - 'fiber': Trace at fiber creation (recommended, lower overhead)
|
|
80
|
+
// - 'operator': Trace each Effect operator (higher granularity, more overhead)
|
|
81
|
+
granularity: z.enum(["fiber", "operator"]).default("fiber"),
|
|
82
|
+
// Smart span naming configuration
|
|
83
|
+
span_naming: z.object({
|
|
84
|
+
// Default span name template when no rules match
|
|
85
|
+
default: z.string().default("effect.fiber.{fiber_id}"),
|
|
86
|
+
// Infer span names from source code (requires stack trace parsing)
|
|
87
|
+
// Adds ~50-100μs overhead per fiber
|
|
88
|
+
infer_from_source: z.boolean().default(true),
|
|
89
|
+
// Naming rules (first match wins)
|
|
90
|
+
rules: z.array(SpanNamingRuleSchema).default([])
|
|
91
|
+
}).default({}),
|
|
92
|
+
// Pattern-based filtering
|
|
93
|
+
filter: z.object({
|
|
94
|
+
// Only trace spans matching these patterns (empty = trace all)
|
|
95
|
+
include: z.array(z.string()).default([]),
|
|
96
|
+
// Never trace spans matching these patterns
|
|
97
|
+
exclude: z.array(z.string()).default([])
|
|
98
|
+
}).default({}),
|
|
99
|
+
// Performance controls
|
|
100
|
+
performance: z.object({
|
|
101
|
+
// Sample rate (0.0 - 1.0)
|
|
102
|
+
sampling_rate: z.number().min(0).max(1).default(1),
|
|
103
|
+
// Skip fibers shorter than this duration (e.g., "10ms", "100 millis")
|
|
104
|
+
min_duration: z.string().default("0ms"),
|
|
105
|
+
// Maximum concurrent traced fibers (0 = unlimited)
|
|
106
|
+
max_concurrent: z.number().default(0)
|
|
107
|
+
}).default({}),
|
|
108
|
+
// Automatic metadata extraction
|
|
109
|
+
metadata: z.object({
|
|
110
|
+
// Extract Effect fiber information
|
|
111
|
+
fiber_info: z.boolean().default(true),
|
|
112
|
+
// Extract source location (file:line)
|
|
113
|
+
source_location: z.boolean().default(true),
|
|
114
|
+
// Extract parent fiber information
|
|
115
|
+
parent_fiber: z.boolean().default(true)
|
|
116
|
+
}).default({})
|
|
117
|
+
});
|
|
56
118
|
var HttpFilteringConfigSchema = z.object({
|
|
57
119
|
// Patterns to ignore for outgoing HTTP requests (string patterns only in YAML)
|
|
58
120
|
ignore_outgoing_urls: z.array(z.string()).optional(),
|
|
@@ -74,6 +136,30 @@ var HttpFilteringConfigSchema = z.object({
|
|
|
74
136
|
include_urls: z.array(z.string()).optional()
|
|
75
137
|
}).optional()
|
|
76
138
|
});
|
|
139
|
+
var ExporterConfigSchema = z.object({
|
|
140
|
+
// Exporter type: 'otlp' | 'console' | 'none'
|
|
141
|
+
// - 'otlp': Export to OTLP endpoint (production)
|
|
142
|
+
// - 'console': Log spans to console (development)
|
|
143
|
+
// - 'none': No export (disable tracing)
|
|
144
|
+
type: z.enum(["otlp", "console", "none"]).default("otlp"),
|
|
145
|
+
// OTLP endpoint URL (for type: otlp)
|
|
146
|
+
// Defaults to OTEL_EXPORTER_OTLP_ENDPOINT env var or http://localhost:4318
|
|
147
|
+
endpoint: z.string().optional(),
|
|
148
|
+
// Custom headers to send with OTLP requests (for type: otlp)
|
|
149
|
+
// Useful for authentication (x-api-key, Authorization, etc.)
|
|
150
|
+
headers: z.record(z.string()).optional(),
|
|
151
|
+
// Span processor type
|
|
152
|
+
// - 'batch': Batch spans for export (production, lower overhead)
|
|
153
|
+
// - 'simple': Export immediately (development, no batching delay)
|
|
154
|
+
processor: z.enum(["batch", "simple"]).default("batch"),
|
|
155
|
+
// Batch processor settings (for processor: batch)
|
|
156
|
+
batch: z.object({
|
|
157
|
+
// Max time to wait before exporting (milliseconds)
|
|
158
|
+
scheduled_delay_millis: z.number().default(1e3),
|
|
159
|
+
// Max batch size
|
|
160
|
+
max_export_batch_size: z.number().default(100)
|
|
161
|
+
}).optional()
|
|
162
|
+
});
|
|
77
163
|
var InstrumentationConfigSchema = z.object({
|
|
78
164
|
version: z.string(),
|
|
79
165
|
instrumentation: z.object({
|
|
@@ -84,11 +170,54 @@ var InstrumentationConfigSchema = z.object({
|
|
|
84
170
|
ignore_patterns: z.array(PatternConfigSchema)
|
|
85
171
|
}),
|
|
86
172
|
effect: z.object({
|
|
173
|
+
// Enable/disable Effect tracing entirely
|
|
174
|
+
// When false, EffectInstrumentationLive returns Layer.empty
|
|
175
|
+
enabled: z.boolean().default(true),
|
|
176
|
+
// Exporter mode (legacy - use exporter.type instead):
|
|
177
|
+
// - "unified": Use global TracerProvider from Node SDK (recommended, enables filtering)
|
|
178
|
+
// - "standalone": Use Effect's own OTLP exporter (bypasses Node SDK filtering)
|
|
179
|
+
exporter: z.enum(["unified", "standalone"]).default("unified"),
|
|
180
|
+
// Exporter configuration (for auto-instrumentation)
|
|
181
|
+
exporter_config: ExporterConfigSchema.optional(),
|
|
87
182
|
auto_extract_metadata: z.boolean(),
|
|
88
|
-
auto_isolation: AutoIsolationConfigSchema.optional()
|
|
183
|
+
auto_isolation: AutoIsolationConfigSchema.optional(),
|
|
184
|
+
// Auto-instrumentation: automatic tracing of all Effect fibers
|
|
185
|
+
auto_instrumentation: AutoInstrumentationConfigSchema.optional()
|
|
89
186
|
}).optional(),
|
|
90
187
|
http: HttpFilteringConfigSchema.optional()
|
|
91
188
|
});
|
|
189
|
+
var defaultConfig = {
|
|
190
|
+
version: "1.0",
|
|
191
|
+
instrumentation: {
|
|
192
|
+
enabled: true,
|
|
193
|
+
logging: "on",
|
|
194
|
+
description: "Default instrumentation configuration",
|
|
195
|
+
instrument_patterns: [
|
|
196
|
+
{ pattern: "^app\\.", enabled: true, description: "Application operations" },
|
|
197
|
+
{ pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
|
|
198
|
+
{ pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
|
|
199
|
+
],
|
|
200
|
+
ignore_patterns: [
|
|
201
|
+
{ pattern: "^test\\.", description: "Test utilities" },
|
|
202
|
+
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
203
|
+
{ pattern: "^health\\.", description: "Health checks" }
|
|
204
|
+
]
|
|
205
|
+
},
|
|
206
|
+
effect: {
|
|
207
|
+
enabled: true,
|
|
208
|
+
exporter: "unified",
|
|
209
|
+
auto_extract_metadata: true
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
function parseAndValidateConfig(content) {
|
|
213
|
+
let parsed;
|
|
214
|
+
if (typeof content === "string") {
|
|
215
|
+
parsed = parse(content);
|
|
216
|
+
} else {
|
|
217
|
+
parsed = content;
|
|
218
|
+
}
|
|
219
|
+
return InstrumentationConfigSchema.parse(parsed);
|
|
220
|
+
}
|
|
92
221
|
(class extends Data.TaggedError("ConfigError") {
|
|
93
222
|
get message() {
|
|
94
223
|
return this.reason;
|
|
@@ -266,7 +395,7 @@ var makeConfigLoader = Effect.gen(function* () {
|
|
|
266
395
|
})
|
|
267
396
|
});
|
|
268
397
|
});
|
|
269
|
-
|
|
398
|
+
Layer.effect(ConfigLoader, makeConfigLoader);
|
|
270
399
|
var PatternMatcher = class {
|
|
271
400
|
constructor(config) {
|
|
272
401
|
__publicField2(this, "ignorePatterns", []);
|
|
@@ -430,8 +559,14 @@ var PatternSpanProcessor = class {
|
|
|
430
559
|
constructor(config, wrappedProcessor) {
|
|
431
560
|
__publicField(this, "matcher");
|
|
432
561
|
__publicField(this, "wrappedProcessor");
|
|
562
|
+
__publicField(this, "httpIgnorePatterns", []);
|
|
433
563
|
this.matcher = new PatternMatcher(config);
|
|
434
564
|
this.wrappedProcessor = wrappedProcessor;
|
|
565
|
+
if (config.http?.ignore_incoming_paths) {
|
|
566
|
+
this.httpIgnorePatterns = config.http.ignore_incoming_paths.map(
|
|
567
|
+
(pattern) => new RegExp(pattern)
|
|
568
|
+
);
|
|
569
|
+
}
|
|
435
570
|
}
|
|
436
571
|
/**
|
|
437
572
|
* Called when a span is started
|
|
@@ -449,12 +584,40 @@ var PatternSpanProcessor = class {
|
|
|
449
584
|
* Called when a span is ended
|
|
450
585
|
*
|
|
451
586
|
* This is where we make the final decision on whether to export the span.
|
|
587
|
+
* We check both span name patterns and HTTP path patterns.
|
|
452
588
|
*/
|
|
453
589
|
onEnd(span) {
|
|
454
590
|
const spanName = span.name;
|
|
455
|
-
if (this.matcher.shouldInstrument(spanName)) {
|
|
456
|
-
|
|
591
|
+
if (!this.matcher.shouldInstrument(spanName)) {
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
if (this.shouldIgnoreHttpSpan(span)) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
this.wrappedProcessor.onEnd(span);
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Check if span should be ignored based on HTTP path attributes
|
|
601
|
+
*
|
|
602
|
+
* This checks the span's url.path, http.route, or http.target attributes
|
|
603
|
+
* against the configured http.ignore_incoming_paths patterns.
|
|
604
|
+
*
|
|
605
|
+
* This enables filtering of Effect HTTP spans (and any other HTTP spans)
|
|
606
|
+
* based on path patterns, which is essential for filtering out OTLP
|
|
607
|
+
* endpoint requests like /v1/traces, /v1/logs, /v1/metrics.
|
|
608
|
+
*/
|
|
609
|
+
shouldIgnoreHttpSpan(span) {
|
|
610
|
+
if (this.httpIgnorePatterns.length === 0) {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
const urlPath = span.attributes["url.path"];
|
|
614
|
+
const httpRoute = span.attributes["http.route"];
|
|
615
|
+
const httpTarget = span.attributes["http.target"];
|
|
616
|
+
const pathToCheck = urlPath || httpRoute || httpTarget;
|
|
617
|
+
if (!pathToCheck) {
|
|
618
|
+
return false;
|
|
457
619
|
}
|
|
620
|
+
return this.httpIgnorePatterns.some((pattern) => pattern.test(pathToCheck));
|
|
458
621
|
}
|
|
459
622
|
/**
|
|
460
623
|
* Shutdown the processor
|
|
@@ -692,83 +855,55 @@ async function getServiceNameAsync() {
|
|
|
692
855
|
async function getServiceVersionAsync() {
|
|
693
856
|
return Effect.runPromise(getServiceVersion);
|
|
694
857
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
);
|
|
698
|
-
|
|
699
|
-
function getCachedLoader() {
|
|
700
|
-
if (!cachedLoaderPromise) {
|
|
701
|
-
cachedLoaderPromise = Effect.runPromise(
|
|
702
|
-
Effect.gen(function* () {
|
|
703
|
-
return yield* ConfigLoader;
|
|
704
|
-
}).pipe(Effect.provide(NodeConfigLoaderLive))
|
|
705
|
-
);
|
|
706
|
-
}
|
|
707
|
-
return cachedLoaderPromise;
|
|
858
|
+
async function loadFromFile(filePath) {
|
|
859
|
+
const { readFile: readFile2 } = await import('fs/promises');
|
|
860
|
+
const content = await readFile2(filePath, "utf-8");
|
|
861
|
+
return parseAndValidateConfig(content);
|
|
708
862
|
}
|
|
709
|
-
function
|
|
710
|
-
|
|
863
|
+
async function loadFromUrl(url) {
|
|
864
|
+
const response = await fetch(url);
|
|
865
|
+
if (!response.ok) {
|
|
866
|
+
throw new Error(`Failed to fetch config from ${url}: ${response.statusText}`);
|
|
867
|
+
}
|
|
868
|
+
const content = await response.text();
|
|
869
|
+
return parseAndValidateConfig(content);
|
|
711
870
|
}
|
|
712
|
-
async function loadConfig(uri,
|
|
713
|
-
if (
|
|
714
|
-
|
|
715
|
-
const loader2 = yield* ConfigLoader;
|
|
716
|
-
return yield* loader2.loadFromUri(uri);
|
|
717
|
-
});
|
|
718
|
-
return Effect.runPromise(program.pipe(Effect.provide(NodeConfigLoaderLive)));
|
|
871
|
+
async function loadConfig(uri, _options) {
|
|
872
|
+
if (uri.startsWith("http://") || uri.startsWith("https://")) {
|
|
873
|
+
return loadFromUrl(uri);
|
|
719
874
|
}
|
|
720
|
-
|
|
721
|
-
|
|
875
|
+
if (uri.startsWith("file://")) {
|
|
876
|
+
const filePath = uri.slice(7);
|
|
877
|
+
return loadFromFile(filePath);
|
|
878
|
+
}
|
|
879
|
+
return loadFromFile(uri);
|
|
722
880
|
}
|
|
723
881
|
async function loadConfigFromInline(content) {
|
|
724
|
-
|
|
725
|
-
return Effect.runPromise(loader.loadFromInline(content));
|
|
882
|
+
return parseAndValidateConfig(content);
|
|
726
883
|
}
|
|
727
|
-
function
|
|
728
|
-
return {
|
|
729
|
-
version: "1.0",
|
|
730
|
-
instrumentation: {
|
|
731
|
-
enabled: true,
|
|
732
|
-
logging: "on",
|
|
733
|
-
description: "Default instrumentation configuration",
|
|
734
|
-
instrument_patterns: [
|
|
735
|
-
{ pattern: "^app\\.", enabled: true, description: "Application operations" },
|
|
736
|
-
{ pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
|
|
737
|
-
{ pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
|
|
738
|
-
],
|
|
739
|
-
ignore_patterns: [
|
|
740
|
-
{ pattern: "^test\\.", description: "Test utilities" },
|
|
741
|
-
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
742
|
-
{ pattern: "^health\\.", description: "Health checks" }
|
|
743
|
-
]
|
|
744
|
-
},
|
|
745
|
-
effect: {
|
|
746
|
-
auto_extract_metadata: true
|
|
747
|
-
}
|
|
748
|
-
};
|
|
884
|
+
function _resetConfigLoaderCache() {
|
|
749
885
|
}
|
|
750
886
|
async function loadConfigWithOptions(options = {}) {
|
|
751
|
-
const loadOptions = options.cacheTimeout !== void 0 ? { cacheTimeout: options.cacheTimeout } : void 0;
|
|
752
887
|
if (options.config) {
|
|
753
888
|
return loadConfigFromInline(options.config);
|
|
754
889
|
}
|
|
755
890
|
const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
|
|
756
891
|
if (envConfigPath) {
|
|
757
|
-
return loadConfig(envConfigPath
|
|
892
|
+
return loadConfig(envConfigPath);
|
|
758
893
|
}
|
|
759
894
|
if (options.configUrl) {
|
|
760
|
-
return loadConfig(options.configUrl
|
|
895
|
+
return loadConfig(options.configUrl);
|
|
761
896
|
}
|
|
762
897
|
if (options.configPath) {
|
|
763
|
-
return loadConfig(options.configPath
|
|
898
|
+
return loadConfig(options.configPath);
|
|
764
899
|
}
|
|
765
900
|
const { existsSync } = await import('fs');
|
|
766
901
|
const { join: join2 } = await import('path');
|
|
767
902
|
const defaultPath = join2(process.cwd(), "instrumentation.yaml");
|
|
768
903
|
if (existsSync(defaultPath)) {
|
|
769
|
-
return loadConfig(defaultPath
|
|
904
|
+
return loadConfig(defaultPath);
|
|
770
905
|
}
|
|
771
|
-
return
|
|
906
|
+
return defaultConfig;
|
|
772
907
|
}
|
|
773
908
|
|
|
774
909
|
// src/core/sdk-initializer.ts
|
|
@@ -1060,9 +1195,39 @@ function logInitialization(config, serviceName, serviceVersion, options, autoIns
|
|
|
1060
1195
|
logger.log(` - OTLP endpoint: ${endpoint}`);
|
|
1061
1196
|
logger.log("");
|
|
1062
1197
|
}
|
|
1198
|
+
var require2 = createRequire(import.meta.url);
|
|
1199
|
+
function validateOpenTelemetryApi() {
|
|
1200
|
+
try {
|
|
1201
|
+
require2.resolve("@opentelemetry/api");
|
|
1202
|
+
} catch {
|
|
1203
|
+
throw new Error(
|
|
1204
|
+
"@atrim/instrument-node requires @opentelemetry/api as a peer dependency.\n\nInstall it with:\n npm install @opentelemetry/api\n\nOr with your preferred package manager:\n pnpm add @opentelemetry/api\n yarn add @opentelemetry/api\n bun add @opentelemetry/api"
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
function validateEffectDependencies() {
|
|
1209
|
+
const packages = ["effect", "@effect/opentelemetry", "@effect/platform"];
|
|
1210
|
+
for (const pkg of packages) {
|
|
1211
|
+
try {
|
|
1212
|
+
require2.resolve(pkg);
|
|
1213
|
+
} catch {
|
|
1214
|
+
return false;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
return true;
|
|
1218
|
+
}
|
|
1219
|
+
var validateDependencies = Effect.try({
|
|
1220
|
+
try: () => validateOpenTelemetryApi(),
|
|
1221
|
+
catch: (error) => new InitializationError2({
|
|
1222
|
+
reason: error instanceof Error ? error.message : "Dependency validation failed",
|
|
1223
|
+
cause: error
|
|
1224
|
+
})
|
|
1225
|
+
});
|
|
1226
|
+
Effect.sync(() => validateEffectDependencies());
|
|
1063
1227
|
|
|
1064
1228
|
// src/api.ts
|
|
1065
1229
|
async function initializeInstrumentation(options = {}) {
|
|
1230
|
+
validateOpenTelemetryApi();
|
|
1066
1231
|
const sdk = await initializeSdk(options);
|
|
1067
1232
|
if (sdk) {
|
|
1068
1233
|
const config = await loadConfigWithOptions(options);
|
|
@@ -1079,6 +1244,7 @@ async function initializePatternMatchingOnly(options = {}) {
|
|
|
1079
1244
|
);
|
|
1080
1245
|
}
|
|
1081
1246
|
var initializeInstrumentationEffect = (options = {}) => Effect.gen(function* () {
|
|
1247
|
+
yield* validateDependencies;
|
|
1082
1248
|
const sdk = yield* Effect.tryPromise({
|
|
1083
1249
|
try: () => initializeSdk(options),
|
|
1084
1250
|
catch: (error) => new InitializationError2({
|