@atrim/instrument-node 0.1.3-fea6398-20251118010933 → 0.4.0-7fcca2c-20251118194147

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.
@@ -5,12 +5,12 @@ var sdkNode = require('@opentelemetry/sdk-node');
5
5
  var sdkTraceBase = require('@opentelemetry/sdk-trace-base');
6
6
  var autoInstrumentationsNode = require('@opentelemetry/auto-instrumentations-node');
7
7
  var api = require('@opentelemetry/api');
8
- var fs = require('fs');
9
- var path = require('path');
10
- var yaml = require('yaml');
11
- var zod = require('zod');
8
+ var instrumentCore = require('@atrim/instrument-core');
12
9
  var exporterTraceOtlpHttp = require('@opentelemetry/exporter-trace-otlp-http');
13
10
  var promises = require('fs/promises');
11
+ var path = require('path');
12
+ var platformNode = require('@effect/platform-node');
13
+ var platform = require('@effect/platform');
14
14
 
15
15
  var __defProp = Object.defineProperty;
16
16
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -21,451 +21,11 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
21
21
  throw Error('Dynamic require of "' + x + '" is not supported');
22
22
  });
23
23
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
24
- var __defProp2 = Object.defineProperty;
25
- var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
26
- var __publicField2 = (obj, key, value) => __defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value);
27
- var PatternConfigSchema = zod.z.object({
28
- pattern: zod.z.string(),
29
- enabled: zod.z.boolean().optional(),
30
- description: zod.z.string().optional()
31
- });
32
- var AutoIsolationConfigSchema = zod.z.object({
33
- // Global enable/disable for auto-isolation
34
- enabled: zod.z.boolean().default(false),
35
- // Which operators to auto-isolate
36
- operators: zod.z.object({
37
- fiberset_run: zod.z.boolean().default(true),
38
- effect_fork: zod.z.boolean().default(true),
39
- effect_fork_daemon: zod.z.boolean().default(true),
40
- effect_fork_in: zod.z.boolean().default(false)
41
- }).default({}),
42
- // Virtual parent tracking configuration
43
- tracking: zod.z.object({
44
- use_span_links: zod.z.boolean().default(true),
45
- use_attributes: zod.z.boolean().default(true),
46
- capture_logical_parent: zod.z.boolean().default(true)
47
- }).default({}),
48
- // Span categorization
49
- attributes: zod.z.object({
50
- category: zod.z.string().default("background_task"),
51
- add_metadata: zod.z.boolean().default(true)
52
- }).default({})
53
- });
54
- var HttpFilteringConfigSchema = zod.z.object({
55
- // Patterns to ignore for outgoing HTTP requests (string patterns only in YAML)
56
- ignore_outgoing_urls: zod.z.array(zod.z.string()).optional(),
57
- // Patterns to ignore for incoming HTTP requests (string patterns only in YAML)
58
- ignore_incoming_paths: zod.z.array(zod.z.string()).optional(),
59
- // Require parent span for outgoing requests (prevents root spans for HTTP calls)
60
- require_parent_for_outgoing_spans: zod.z.boolean().optional()
61
- });
62
- var InstrumentationConfigSchema = zod.z.object({
63
- version: zod.z.string(),
64
- instrumentation: zod.z.object({
65
- enabled: zod.z.boolean(),
66
- description: zod.z.string().optional(),
67
- logging: zod.z.enum(["on", "off", "minimal"]).optional().default("on"),
68
- instrument_patterns: zod.z.array(PatternConfigSchema),
69
- ignore_patterns: zod.z.array(PatternConfigSchema)
70
- }),
71
- effect: zod.z.object({
72
- auto_extract_metadata: zod.z.boolean(),
73
- auto_isolation: AutoIsolationConfigSchema.optional()
74
- }).optional(),
75
- http: HttpFilteringConfigSchema.optional()
76
- });
77
- (class extends effect.Data.TaggedError("ConfigError") {
78
- });
79
- var ConfigUrlError = class extends effect.Data.TaggedError("ConfigUrlError") {
80
- };
81
- var ConfigValidationError = class extends effect.Data.TaggedError("ConfigValidationError") {
82
- };
83
- var ConfigFileError = class extends effect.Data.TaggedError("ConfigFileError") {
84
- };
85
- (class extends effect.Data.TaggedError("ServiceDetectionError") {
86
- });
87
- (class extends effect.Data.TaggedError("InitializationError") {
88
- });
89
- (class extends effect.Data.TaggedError("ExportError") {
90
- });
91
- (class extends effect.Data.TaggedError("ShutdownError") {
92
- });
93
- var SECURITY_DEFAULTS = {
94
- maxConfigSize: 1e6,
95
- // 1MB
96
- requestTimeout: 5e3,
97
- allowedProtocols: ["https:"],
98
- // Only HTTPS for remote configs
99
- cacheTimeout: 3e5
100
- // 5 minutes
101
- };
102
- function getDefaultConfig() {
103
- return {
104
- version: "1.0",
105
- instrumentation: {
106
- enabled: true,
107
- logging: "on",
108
- description: "Default instrumentation configuration",
109
- instrument_patterns: [
110
- { pattern: "^app\\.", enabled: true, description: "Application operations" },
111
- { pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
112
- { pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
113
- ],
114
- ignore_patterns: [
115
- { pattern: "^test\\.", description: "Test utilities" },
116
- { pattern: "^internal\\.", description: "Internal operations" },
117
- { pattern: "^health\\.", description: "Health checks" }
118
- ]
119
- },
120
- effect: {
121
- auto_extract_metadata: true
122
- }
123
- };
124
- }
125
- var validateConfigEffect = (rawConfig) => effect.Effect.try({
126
- try: () => InstrumentationConfigSchema.parse(rawConfig),
127
- catch: (error) => new ConfigValidationError({
128
- reason: "Invalid configuration schema",
129
- cause: error
130
- })
131
- });
132
- var loadConfigFromFileEffect = (filePath) => effect.Effect.gen(function* () {
133
- const fileContents = yield* effect.Effect.try({
134
- try: () => fs.readFileSync(filePath, "utf8"),
135
- catch: (error) => new ConfigFileError({
136
- reason: `Failed to read config file at ${filePath}`,
137
- cause: error
138
- })
139
- });
140
- if (fileContents.length > SECURITY_DEFAULTS.maxConfigSize) {
141
- return yield* effect.Effect.fail(
142
- new ConfigFileError({
143
- reason: `Config file exceeds maximum size of ${SECURITY_DEFAULTS.maxConfigSize} bytes`
144
- })
145
- );
146
- }
147
- let rawConfig;
148
- try {
149
- rawConfig = yaml.parse(fileContents);
150
- } catch (error) {
151
- return yield* effect.Effect.fail(
152
- new ConfigValidationError({
153
- reason: "Invalid YAML syntax",
154
- cause: error
155
- })
156
- );
157
- }
158
- return yield* validateConfigEffect(rawConfig);
159
- });
160
- var fetchAndParseConfig = (url) => effect.Effect.gen(function* () {
161
- let urlObj;
162
- try {
163
- urlObj = new URL(url);
164
- } catch (error) {
165
- return yield* effect.Effect.fail(
166
- new ConfigUrlError({
167
- reason: `Invalid URL: ${url}`,
168
- cause: error
169
- })
170
- );
171
- }
172
- if (!SECURITY_DEFAULTS.allowedProtocols.includes(urlObj.protocol)) {
173
- return yield* effect.Effect.fail(
174
- new ConfigUrlError({
175
- reason: `Insecure protocol ${urlObj.protocol}. Only ${SECURITY_DEFAULTS.allowedProtocols.join(", ")} are allowed`
176
- })
177
- );
178
- }
179
- const response = yield* effect.Effect.tryPromise({
180
- try: () => fetch(url, {
181
- redirect: "follow",
182
- headers: {
183
- Accept: "application/yaml, text/yaml, text/x-yaml"
184
- }
185
- }),
186
- catch: (error) => new ConfigUrlError({
187
- reason: `Failed to load config from URL ${url}`,
188
- cause: error
189
- })
190
- }).pipe(
191
- effect.Effect.timeout(effect.Duration.millis(SECURITY_DEFAULTS.requestTimeout)),
192
- effect.Effect.retry({
193
- times: 3,
194
- schedule: effect.Schedule.exponential(effect.Duration.millis(100))
195
- }),
196
- effect.Effect.catchAll((error) => {
197
- if (error._tag === "TimeoutException") {
198
- return effect.Effect.fail(
199
- new ConfigUrlError({
200
- reason: `Config fetch timeout after ${SECURITY_DEFAULTS.requestTimeout}ms`
201
- })
202
- );
203
- }
204
- return effect.Effect.fail(error);
205
- })
206
- );
207
- if (!response.ok) {
208
- return yield* effect.Effect.fail(
209
- new ConfigUrlError({
210
- reason: `HTTP ${response.status}: ${response.statusText}`
211
- })
212
- );
213
- }
214
- const contentLength = response.headers.get("content-length");
215
- if (contentLength && parseInt(contentLength) > SECURITY_DEFAULTS.maxConfigSize) {
216
- return yield* effect.Effect.fail(
217
- new ConfigUrlError({
218
- reason: `Config exceeds maximum size of ${SECURITY_DEFAULTS.maxConfigSize} bytes`
219
- })
220
- );
221
- }
222
- const text = yield* effect.Effect.tryPromise({
223
- try: () => response.text(),
224
- catch: (error) => new ConfigUrlError({
225
- reason: "Failed to read response body",
226
- cause: error
227
- })
228
- });
229
- if (text.length > SECURITY_DEFAULTS.maxConfigSize) {
230
- return yield* effect.Effect.fail(
231
- new ConfigUrlError({
232
- reason: `Config exceeds maximum size of ${SECURITY_DEFAULTS.maxConfigSize} bytes`
233
- })
234
- );
235
- }
236
- let rawConfig;
237
- try {
238
- rawConfig = yaml.parse(text);
239
- } catch (error) {
240
- return yield* effect.Effect.fail(
241
- new ConfigValidationError({
242
- reason: "Invalid YAML syntax",
243
- cause: error
244
- })
245
- );
246
- }
247
- return yield* validateConfigEffect(rawConfig);
248
- });
249
- var makeConfigCache = () => effect.Cache.make({
250
- capacity: 100,
251
- timeToLive: effect.Duration.minutes(5),
252
- lookup: (url) => fetchAndParseConfig(url)
253
- });
254
- var cacheInstance = null;
255
- var getCache = effect.Effect.gen(function* () {
256
- if (!cacheInstance) {
257
- cacheInstance = yield* makeConfigCache();
258
- }
259
- return cacheInstance;
260
- });
261
- var loadConfigFromUrlEffect = (url, cacheTimeout = SECURITY_DEFAULTS.cacheTimeout) => effect.Effect.gen(function* () {
262
- if (cacheTimeout === 0) {
263
- return yield* fetchAndParseConfig(url);
264
- }
265
- const cache = yield* getCache;
266
- return yield* cache.get(url);
267
- });
268
- var loadConfigEffect = (options = {}) => effect.Effect.gen(function* () {
269
- if (options.config) {
270
- return yield* validateConfigEffect(options.config);
271
- }
272
- const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
273
- if (envConfigPath) {
274
- if (envConfigPath.startsWith("http://") || envConfigPath.startsWith("https://")) {
275
- return yield* loadConfigFromUrlEffect(envConfigPath, options.cacheTimeout);
276
- }
277
- return yield* loadConfigFromFileEffect(envConfigPath);
278
- }
279
- if (options.configUrl) {
280
- return yield* loadConfigFromUrlEffect(options.configUrl, options.cacheTimeout);
281
- }
282
- if (options.configPath) {
283
- return yield* loadConfigFromFileEffect(options.configPath);
284
- }
285
- const defaultPath = path.join(process.cwd(), "instrumentation.yaml");
286
- const exists = yield* effect.Effect.sync(() => fs.existsSync(defaultPath));
287
- if (exists) {
288
- return yield* loadConfigFromFileEffect(defaultPath);
289
- }
290
- return getDefaultConfig();
291
- });
292
- async function loadConfig(options = {}) {
293
- return effect.Effect.runPromise(
294
- loadConfigEffect(options).pipe(
295
- // Convert typed errors to regular Error with reason message for backward compatibility
296
- effect.Effect.mapError((error) => {
297
- const message = error.reason;
298
- const newError = new Error(message);
299
- newError.cause = error.cause;
300
- return newError;
301
- })
302
- )
303
- );
304
- }
305
- var PatternMatcher = class {
306
- constructor(config) {
307
- __publicField2(this, "ignorePatterns", []);
308
- __publicField2(this, "instrumentPatterns", []);
309
- __publicField2(this, "enabled", true);
310
- this.enabled = config.instrumentation.enabled;
311
- this.ignorePatterns = config.instrumentation.ignore_patterns.map((p) => this.compilePattern(p));
312
- this.instrumentPatterns = config.instrumentation.instrument_patterns.filter((p) => p.enabled !== false).map((p) => this.compilePattern(p));
313
- }
314
- /**
315
- * Compile a pattern configuration into a RegExp
316
- */
317
- compilePattern(pattern) {
318
- try {
319
- const compiled = {
320
- regex: new RegExp(pattern.pattern),
321
- enabled: pattern.enabled !== false
322
- };
323
- if (pattern.description !== void 0) {
324
- compiled.description = pattern.description;
325
- }
326
- return compiled;
327
- } catch (error) {
328
- throw new Error(
329
- `Failed to compile pattern "${pattern.pattern}": ${error instanceof Error ? error.message : String(error)}`
330
- );
331
- }
332
- }
333
- /**
334
- * Check if a span should be instrumented
335
- *
336
- * Returns true if the span should be created, false otherwise.
337
- *
338
- * Logic:
339
- * 1. If instrumentation disabled globally, return false
340
- * 2. Check ignore patterns - if any match, return false
341
- * 3. Check instrument patterns - if any match, return true
342
- * 4. Default: return true (fail-open - create span if no patterns match)
343
- */
344
- shouldInstrument(spanName) {
345
- if (!this.enabled) {
346
- return false;
347
- }
348
- for (const pattern of this.ignorePatterns) {
349
- if (pattern.regex.test(spanName)) {
350
- return false;
351
- }
352
- }
353
- for (const pattern of this.instrumentPatterns) {
354
- if (pattern.enabled && pattern.regex.test(spanName)) {
355
- return true;
356
- }
357
- }
358
- return true;
359
- }
360
- /**
361
- * Get statistics about pattern matching (for debugging/monitoring)
362
- */
363
- getStats() {
364
- return {
365
- enabled: this.enabled,
366
- ignorePatternCount: this.ignorePatterns.length,
367
- instrumentPatternCount: this.instrumentPatterns.filter((p) => p.enabled).length
368
- };
369
- }
370
- };
371
- var globalMatcher = null;
372
- function initializePatternMatcher(config) {
373
- globalMatcher = new PatternMatcher(config);
374
- }
375
- function shouldInstrumentSpan(spanName) {
376
- if (!globalMatcher) {
377
- return true;
378
- }
379
- return globalMatcher.shouldInstrument(spanName);
380
- }
381
- function getPatternMatcher() {
382
- return globalMatcher;
383
- }
384
- var Logger = class {
385
- constructor() {
386
- __publicField2(this, "level", "on");
387
- __publicField2(this, "hasLoggedMinimal", false);
388
- }
389
- /**
390
- * Set the logging level
391
- */
392
- setLevel(level) {
393
- this.level = level;
394
- this.hasLoggedMinimal = false;
395
- }
396
- /**
397
- * Get the current logging level
398
- */
399
- getLevel() {
400
- return this.level;
401
- }
402
- /**
403
- * Log a minimal initialization message (only shown once in minimal mode)
404
- */
405
- minimal(message) {
406
- if (this.level === "off") {
407
- return;
408
- }
409
- if (this.level === "minimal" && !this.hasLoggedMinimal) {
410
- console.log(message);
411
- this.hasLoggedMinimal = true;
412
- return;
413
- }
414
- if (this.level === "on") {
415
- console.log(message);
416
- }
417
- }
418
- /**
419
- * Log an informational message
420
- */
421
- log(...args) {
422
- if (this.level === "on") {
423
- console.log(...args);
424
- }
425
- }
426
- /**
427
- * Log a warning message (shown in minimal mode)
428
- */
429
- warn(...args) {
430
- if (this.level !== "off") {
431
- console.warn(...args);
432
- }
433
- }
434
- /**
435
- * Log an error message (shown in minimal mode)
436
- */
437
- error(...args) {
438
- if (this.level !== "off") {
439
- console.error(...args);
440
- }
441
- }
442
- /**
443
- * Check if full logging is enabled
444
- */
445
- isEnabled() {
446
- return this.level === "on";
447
- }
448
- /**
449
- * Check if minimal logging is enabled
450
- */
451
- isMinimal() {
452
- return this.level === "minimal";
453
- }
454
- /**
455
- * Check if logging is completely disabled
456
- */
457
- isDisabled() {
458
- return this.level === "off";
459
- }
460
- };
461
- var logger = new Logger();
462
-
463
- // src/core/span-processor.ts
464
24
  var PatternSpanProcessor = class {
465
25
  constructor(config, wrappedProcessor) {
466
26
  __publicField(this, "matcher");
467
27
  __publicField(this, "wrappedProcessor");
468
- this.matcher = new PatternMatcher(config);
28
+ this.matcher = new instrumentCore.PatternMatcher(config);
469
29
  this.wrappedProcessor = wrappedProcessor;
470
30
  }
471
31
  /**
@@ -538,8 +98,6 @@ function getOtlpEndpoint(options = {}) {
538
98
  const endpoint = options.endpoint || process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTLP_ENDPOINT;
539
99
  return normalizeEndpoint(endpoint);
540
100
  }
541
-
542
- // src/core/safe-exporter.ts
543
101
  var SafeSpanExporter = class {
544
102
  // Log errors max once per minute
545
103
  constructor(exporter) {
@@ -576,7 +134,7 @@ var SafeSpanExporter = class {
576
134
  try {
577
135
  await this.exporter.shutdown();
578
136
  } catch (error) {
579
- logger.error(
137
+ instrumentCore.logger.error(
580
138
  "@atrim/instrumentation: Error during exporter shutdown (non-critical):",
581
139
  error instanceof Error ? error.message : String(error)
582
140
  );
@@ -605,14 +163,14 @@ var SafeSpanExporter = class {
605
163
  if (shouldLog) {
606
164
  const errorMessage = error instanceof Error ? error.message : String(error);
607
165
  if (this.isConnectionError(error)) {
608
- logger.warn(`@atrim/instrumentation: Unable to export spans - collector not available`);
609
- logger.warn(` Error: ${errorMessage}`);
610
- logger.warn(` Spans will be dropped. Ensure OTEL collector is running.`);
166
+ instrumentCore.logger.warn(`@atrim/instrumentation: Unable to export spans - collector not available`);
167
+ instrumentCore.logger.warn(` Error: ${errorMessage}`);
168
+ instrumentCore.logger.warn(` Spans will be dropped. Ensure OTEL collector is running.`);
611
169
  } else {
612
- logger.error("@atrim/instrumentation: Span export failed:", errorMessage);
170
+ instrumentCore.logger.error("@atrim/instrumentation: Span export failed:", errorMessage);
613
171
  }
614
172
  if (this.errorCount > 1) {
615
- logger.warn(` (${this.errorCount} errors total, throttled to 1/min)`);
173
+ instrumentCore.logger.warn(` (${this.errorCount} errors total, throttled to 1/min)`);
616
174
  }
617
175
  this.lastErrorTime = now;
618
176
  this.errorCount = 0;
@@ -639,21 +197,21 @@ var SafeSpanExporter = class {
639
197
  return false;
640
198
  }
641
199
  };
642
- var ConfigError2 = class extends effect.Data.TaggedError("ConfigError") {
200
+ var ConfigError = class extends effect.Data.TaggedError("ConfigError") {
643
201
  };
644
- var ConfigUrlError2 = class extends effect.Data.TaggedError("ConfigUrlError") {
202
+ var ConfigUrlError = class extends effect.Data.TaggedError("ConfigUrlError") {
645
203
  };
646
- var ConfigValidationError2 = class extends effect.Data.TaggedError("ConfigValidationError") {
204
+ var ConfigValidationError = class extends effect.Data.TaggedError("ConfigValidationError") {
647
205
  };
648
- var ConfigFileError2 = class extends effect.Data.TaggedError("ConfigFileError") {
206
+ var ConfigFileError = class extends effect.Data.TaggedError("ConfigFileError") {
649
207
  };
650
- var ServiceDetectionError2 = class extends effect.Data.TaggedError("ServiceDetectionError") {
208
+ var ServiceDetectionError = class extends effect.Data.TaggedError("ServiceDetectionError") {
651
209
  };
652
- var InitializationError2 = class extends effect.Data.TaggedError("InitializationError") {
210
+ var InitializationError = class extends effect.Data.TaggedError("InitializationError") {
653
211
  };
654
- var ExportError2 = class extends effect.Data.TaggedError("ExportError") {
212
+ var ExportError = class extends effect.Data.TaggedError("ExportError") {
655
213
  };
656
- var ShutdownError2 = class extends effect.Data.TaggedError("ShutdownError") {
214
+ var ShutdownError = class extends effect.Data.TaggedError("ShutdownError") {
657
215
  };
658
216
 
659
217
  // src/core/service-detector.ts
@@ -670,7 +228,7 @@ var detectServiceInfo = effect.Effect.gen(
670
228
  const packageJsonPath = path.join(process.cwd(), "package.json");
671
229
  const packageJsonContent = yield* effect.Effect.tryPromise({
672
230
  try: () => promises.readFile(packageJsonPath, "utf-8"),
673
- catch: (error) => new ServiceDetectionError2({
231
+ catch: (error) => new ServiceDetectionError({
674
232
  reason: `Failed to read package.json at ${packageJsonPath}`,
675
233
  cause: error
676
234
  })
@@ -680,7 +238,7 @@ var detectServiceInfo = effect.Effect.gen(
680
238
  parsed = JSON.parse(packageJsonContent);
681
239
  } catch (error) {
682
240
  yield* effect.Effect.fail(
683
- new ServiceDetectionError2({
241
+ new ServiceDetectionError({
684
242
  reason: "Invalid JSON in package.json",
685
243
  cause: error
686
244
  })
@@ -696,7 +254,7 @@ var detectServiceInfo = effect.Effect.gen(
696
254
  }
697
255
  }
698
256
  return yield* effect.Effect.fail(
699
- new ServiceDetectionError2({
257
+ new ServiceDetectionError({
700
258
  reason: 'package.json exists but has no "name" field'
701
259
  })
702
260
  );
@@ -727,6 +285,84 @@ async function getServiceNameAsync() {
727
285
  async function getServiceVersionAsync() {
728
286
  return effect.Effect.runPromise(getServiceVersion);
729
287
  }
288
+ var NodeConfigLoaderLive = instrumentCore.ConfigLoaderLive.pipe(
289
+ effect.Layer.provide(effect.Layer.mergeAll(platformNode.NodeContext.layer, platform.FetchHttpClient.layer))
290
+ );
291
+ var cachedLoaderPromise = null;
292
+ function getCachedLoader() {
293
+ if (!cachedLoaderPromise) {
294
+ cachedLoaderPromise = effect.Effect.runPromise(
295
+ effect.Effect.gen(function* () {
296
+ return yield* instrumentCore.ConfigLoader;
297
+ }).pipe(effect.Effect.provide(NodeConfigLoaderLive))
298
+ );
299
+ }
300
+ return cachedLoaderPromise;
301
+ }
302
+ function _resetConfigLoaderCache() {
303
+ cachedLoaderPromise = null;
304
+ }
305
+ async function loadConfig(uri, options) {
306
+ if (options?.cacheTimeout === 0) {
307
+ const program = effect.Effect.gen(function* () {
308
+ const loader2 = yield* instrumentCore.ConfigLoader;
309
+ return yield* loader2.loadFromUri(uri);
310
+ });
311
+ return effect.Effect.runPromise(program.pipe(effect.Effect.provide(NodeConfigLoaderLive)));
312
+ }
313
+ const loader = await getCachedLoader();
314
+ return effect.Effect.runPromise(loader.loadFromUri(uri));
315
+ }
316
+ async function loadConfigFromInline(content) {
317
+ const loader = await getCachedLoader();
318
+ return effect.Effect.runPromise(loader.loadFromInline(content));
319
+ }
320
+ function getDefaultConfig() {
321
+ return {
322
+ version: "1.0",
323
+ instrumentation: {
324
+ enabled: true,
325
+ logging: "on",
326
+ description: "Default instrumentation configuration",
327
+ instrument_patterns: [
328
+ { pattern: "^app\\.", enabled: true, description: "Application operations" },
329
+ { pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
330
+ { pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
331
+ ],
332
+ ignore_patterns: [
333
+ { pattern: "^test\\.", description: "Test utilities" },
334
+ { pattern: "^internal\\.", description: "Internal operations" },
335
+ { pattern: "^health\\.", description: "Health checks" }
336
+ ]
337
+ },
338
+ effect: {
339
+ auto_extract_metadata: true
340
+ }
341
+ };
342
+ }
343
+ async function loadConfigWithOptions(options = {}) {
344
+ const loadOptions = options.cacheTimeout !== void 0 ? { cacheTimeout: options.cacheTimeout } : void 0;
345
+ if (options.config) {
346
+ return loadConfigFromInline(options.config);
347
+ }
348
+ const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
349
+ if (envConfigPath) {
350
+ return loadConfig(envConfigPath, loadOptions);
351
+ }
352
+ if (options.configUrl) {
353
+ return loadConfig(options.configUrl, loadOptions);
354
+ }
355
+ if (options.configPath) {
356
+ return loadConfig(options.configPath, loadOptions);
357
+ }
358
+ const { existsSync } = await import('fs');
359
+ const { join: join2 } = await import('path');
360
+ const defaultPath = join2(process.cwd(), "instrumentation.yaml");
361
+ if (existsSync(defaultPath)) {
362
+ return loadConfig(defaultPath, loadOptions);
363
+ }
364
+ return getDefaultConfig();
365
+ }
730
366
 
731
367
  // src/core/sdk-initializer.ts
732
368
  var sdkInstance = null;
@@ -739,7 +375,7 @@ function buildHttpInstrumentationConfig(options, config, _otlpEndpoint) {
739
375
  ...programmaticPatterns.map((p) => typeof p === "string" ? new RegExp(p) : p),
740
376
  ...yamlPatterns.map((p) => new RegExp(p))
741
377
  ];
742
- logger.log(`HTTP filtering: ${allOutgoingPatterns.length} outgoing patterns configured`);
378
+ instrumentCore.logger.log(`HTTP filtering: ${allOutgoingPatterns.length} outgoing patterns configured`);
743
379
  if (options.http?.ignoreOutgoingRequestHook) {
744
380
  httpConfig.ignoreOutgoingRequestHook = options.http.ignoreOutgoingRequestHook;
745
381
  } else if (allOutgoingPatterns.length > 0) {
@@ -808,9 +444,9 @@ function shouldEnableAutoInstrumentation(explicitValue, hasWebFramework) {
808
444
  }
809
445
  const isEffect = isEffectProject();
810
446
  if (isEffect && !hasWebFramework) {
811
- logger.log("@atrim/instrumentation: Detected Effect-TS without web framework");
812
- logger.log(" - Auto-instrumentation disabled by default");
813
- logger.log(" - Effect.withSpan() will create spans");
447
+ instrumentCore.logger.log("@atrim/instrumentation: Detected Effect-TS without web framework");
448
+ instrumentCore.logger.log(" - Auto-instrumentation disabled by default");
449
+ instrumentCore.logger.log(" - Effect.withSpan() will create spans");
814
450
  return false;
815
451
  }
816
452
  return true;
@@ -848,11 +484,11 @@ function isTracingAlreadyInitialized() {
848
484
  }
849
485
  async function initializeSdk(options = {}) {
850
486
  if (sdkInstance) {
851
- logger.warn("@atrim/instrumentation: SDK already initialized. Returning existing instance.");
487
+ instrumentCore.logger.warn("@atrim/instrumentation: SDK already initialized. Returning existing instance.");
852
488
  return sdkInstance;
853
489
  }
854
490
  if (initializationPromise) {
855
- logger.log(
491
+ instrumentCore.logger.log(
856
492
  "@atrim/instrumentation: SDK already initialized, waiting for initialization to complete..."
857
493
  );
858
494
  return initializationPromise;
@@ -866,20 +502,20 @@ async function initializeSdk(options = {}) {
866
502
  }
867
503
  }
868
504
  async function performInitialization(options) {
869
- const config = await loadConfig(options);
505
+ const config = await loadConfigWithOptions(options);
870
506
  const loggingLevel = config.instrumentation.logging || "on";
871
- logger.setLevel(loggingLevel);
507
+ instrumentCore.logger.setLevel(loggingLevel);
872
508
  const alreadyInitialized = isTracingAlreadyInitialized();
873
509
  if (alreadyInitialized) {
874
- logger.log("@atrim/instrumentation: Detected existing OpenTelemetry initialization.");
875
- logger.log(" - Skipping NodeSDK setup");
876
- logger.log(" - Setting up pattern-based filtering only");
877
- logger.log("");
878
- initializePatternMatcher(config);
879
- logger.log("@atrim/instrumentation: Pattern filtering initialized");
880
- logger.log(" \u26A0\uFE0F Note: Pattern filtering will only work with manual spans");
881
- logger.log(" \u26A0\uFE0F Auto-instrumentation must be configured separately");
882
- logger.log("");
510
+ instrumentCore.logger.log("@atrim/instrumentation: Detected existing OpenTelemetry initialization.");
511
+ instrumentCore.logger.log(" - Skipping NodeSDK setup");
512
+ instrumentCore.logger.log(" - Setting up pattern-based filtering only");
513
+ instrumentCore.logger.log("");
514
+ instrumentCore.initializePatternMatcher(config);
515
+ instrumentCore.logger.log("@atrim/instrumentation: Pattern filtering initialized");
516
+ instrumentCore.logger.log(" \u26A0\uFE0F Note: Pattern filtering will only work with manual spans");
517
+ instrumentCore.logger.log(" \u26A0\uFE0F Auto-instrumentation must be configured separately");
518
+ instrumentCore.logger.log("");
883
519
  return null;
884
520
  }
885
521
  const serviceInfo = await detectServiceInfoAsync();
@@ -915,7 +551,7 @@ async function performInitialization(options) {
915
551
  "@opentelemetry/instrumentation-dns": { enabled: false }
916
552
  })
917
553
  );
918
- logger.log(`Auto-instrumentation: ${instrumentations.length} instrumentations enabled`);
554
+ instrumentCore.logger.log(`Auto-instrumentation: ${instrumentations.length} instrumentations enabled`);
919
555
  }
920
556
  if (options.instrumentations) {
921
557
  instrumentations.push(...options.instrumentations);
@@ -923,14 +559,14 @@ async function performInitialization(options) {
923
559
  if (!enableAutoInstrumentation && instrumentations.length === 0) {
924
560
  const wasExplicit = options.autoInstrument === false;
925
561
  const detectionMessage = wasExplicit ? "@atrim/instrumentation: Auto-instrumentation: disabled" : "@atrim/instrumentation: Pure Effect-TS app detected (auto-detected)";
926
- logger.log(detectionMessage);
927
- logger.log(" - Skipping NodeSDK setup");
928
- logger.log(" - Pattern matching configured from instrumentation.yaml");
562
+ instrumentCore.logger.log(detectionMessage);
563
+ instrumentCore.logger.log(" - Skipping NodeSDK setup");
564
+ instrumentCore.logger.log(" - Pattern matching configured from instrumentation.yaml");
929
565
  if (!wasExplicit) {
930
- logger.log(" - Use EffectInstrumentationLive for tracing");
566
+ instrumentCore.logger.log(" - Use EffectInstrumentationLive for tracing");
931
567
  }
932
- logger.log("");
933
- initializePatternMatcher(config);
568
+ instrumentCore.logger.log("");
569
+ instrumentCore.initializePatternMatcher(config);
934
570
  return null;
935
571
  }
936
572
  const sdkConfig = {
@@ -966,14 +602,14 @@ function resetSdk() {
966
602
  }
967
603
  function registerShutdownHandlers(sdk) {
968
604
  const shutdown = async (signal) => {
969
- logger.log(`
605
+ instrumentCore.logger.log(`
970
606
  @atrim/instrumentation: Received ${signal}, shutting down gracefully...`);
971
607
  try {
972
608
  await sdk.shutdown();
973
- logger.log("@atrim/instrumentation: Shutdown complete");
609
+ instrumentCore.logger.log("@atrim/instrumentation: Shutdown complete");
974
610
  process.exit(0);
975
611
  } catch (error) {
976
- logger.error(
612
+ instrumentCore.logger.error(
977
613
  "@atrim/instrumentation: Error during shutdown:",
978
614
  error instanceof Error ? error.message : String(error)
979
615
  );
@@ -983,77 +619,75 @@ function registerShutdownHandlers(sdk) {
983
619
  process.on("SIGTERM", () => shutdown("SIGTERM"));
984
620
  process.on("SIGINT", () => shutdown("SIGINT"));
985
621
  process.on("uncaughtException", async (error) => {
986
- logger.error("@atrim/instrumentation: Uncaught exception:", error);
622
+ instrumentCore.logger.error("@atrim/instrumentation: Uncaught exception:", error);
987
623
  await sdk.shutdown();
988
624
  process.exit(1);
989
625
  });
990
626
  process.on("unhandledRejection", async (reason) => {
991
- logger.error("@atrim/instrumentation: Unhandled rejection:", reason);
627
+ instrumentCore.logger.error("@atrim/instrumentation: Unhandled rejection:", reason);
992
628
  await sdk.shutdown();
993
629
  process.exit(1);
994
630
  });
995
631
  }
996
632
  function logInitialization(config, serviceName, serviceVersion, options, autoInstrumentEnabled) {
997
- logger.minimal("@atrim/instrumentation: SDK initialized successfully");
998
- logger.log(` - Service: ${serviceName}${serviceVersion ? ` v${serviceVersion}` : ""}`);
633
+ instrumentCore.logger.minimal("@atrim/instrumentation: SDK initialized successfully");
634
+ instrumentCore.logger.log(` - Service: ${serviceName}${serviceVersion ? ` v${serviceVersion}` : ""}`);
999
635
  if (config.instrumentation.enabled) {
1000
636
  const instrumentCount = config.instrumentation.instrument_patterns.filter(
1001
637
  (p) => p.enabled !== false
1002
638
  ).length;
1003
639
  const ignoreCount = config.instrumentation.ignore_patterns.length;
1004
- logger.log(` - Pattern filtering: enabled`);
1005
- logger.log(` - Instrument patterns: ${instrumentCount}`);
1006
- logger.log(` - Ignore patterns: ${ignoreCount}`);
640
+ instrumentCore.logger.log(` - Pattern filtering: enabled`);
641
+ instrumentCore.logger.log(` - Instrument patterns: ${instrumentCount}`);
642
+ instrumentCore.logger.log(` - Ignore patterns: ${ignoreCount}`);
1007
643
  } else {
1008
- logger.log(` - Pattern filtering: disabled`);
644
+ instrumentCore.logger.log(` - Pattern filtering: disabled`);
1009
645
  }
1010
646
  const autoInstrumentLabel = autoInstrumentEnabled ? "enabled" : "disabled";
1011
647
  const autoDetected = options.autoInstrument === void 0 ? " (auto-detected)" : "";
1012
- logger.log(` - Auto-instrumentation: ${autoInstrumentLabel}${autoDetected}`);
648
+ instrumentCore.logger.log(` - Auto-instrumentation: ${autoInstrumentLabel}${autoDetected}`);
1013
649
  if (options.instrumentations && options.instrumentations.length > 0) {
1014
- logger.log(` - Custom instrumentations: ${options.instrumentations.length}`);
650
+ instrumentCore.logger.log(` - Custom instrumentations: ${options.instrumentations.length}`);
1015
651
  }
1016
652
  const endpoint = options.otlp?.endpoint || process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318/v1/traces";
1017
- logger.log(` - OTLP endpoint: ${endpoint}`);
1018
- logger.log("");
653
+ instrumentCore.logger.log(` - OTLP endpoint: ${endpoint}`);
654
+ instrumentCore.logger.log("");
1019
655
  }
1020
-
1021
- // src/api.ts
1022
656
  async function initializeInstrumentation(options = {}) {
1023
657
  const sdk = await initializeSdk(options);
1024
658
  if (sdk) {
1025
- const config = await loadConfig(options);
1026
- initializePatternMatcher(config);
659
+ const config = await loadConfigWithOptions(options);
660
+ instrumentCore.initializePatternMatcher(config);
1027
661
  }
1028
662
  return sdk;
1029
663
  }
1030
664
  async function initializePatternMatchingOnly(options = {}) {
1031
- const config = await loadConfig(options);
1032
- initializePatternMatcher(config);
1033
- logger.log("@atrim/instrumentation: Pattern matching initialized (legacy mode)");
1034
- logger.log(
665
+ const config = await loadConfigWithOptions(options);
666
+ instrumentCore.initializePatternMatcher(config);
667
+ instrumentCore.logger.log("@atrim/instrumentation: Pattern matching initialized (legacy mode)");
668
+ instrumentCore.logger.log(
1035
669
  " Note: NodeSDK is not initialized. Use initializeInstrumentation() for complete setup."
1036
670
  );
1037
671
  }
1038
672
  var initializeInstrumentationEffect = (options = {}) => effect.Effect.gen(function* () {
1039
673
  const sdk = yield* effect.Effect.tryPromise({
1040
674
  try: () => initializeSdk(options),
1041
- catch: (error) => new InitializationError2({
675
+ catch: (error) => new InitializationError({
1042
676
  reason: "SDK initialization failed",
1043
677
  cause: error
1044
678
  })
1045
679
  });
1046
680
  if (sdk) {
1047
681
  yield* effect.Effect.tryPromise({
1048
- try: () => loadConfig(options),
1049
- catch: (error) => new ConfigError2({
682
+ try: () => loadConfigWithOptions(options),
683
+ catch: (error) => new ConfigError({
1050
684
  reason: "Failed to load config for pattern matcher",
1051
685
  cause: error
1052
686
  })
1053
687
  }).pipe(
1054
688
  effect.Effect.tap(
1055
689
  (config) => effect.Effect.sync(() => {
1056
- initializePatternMatcher(config);
690
+ instrumentCore.initializePatternMatcher(config);
1057
691
  })
1058
692
  )
1059
693
  );
@@ -1062,16 +696,16 @@ var initializeInstrumentationEffect = (options = {}) => effect.Effect.gen(functi
1062
696
  });
1063
697
  var initializePatternMatchingOnlyEffect = (options = {}) => effect.Effect.gen(function* () {
1064
698
  const config = yield* effect.Effect.tryPromise({
1065
- try: () => loadConfig(options),
1066
- catch: (error) => new ConfigError2({
699
+ try: () => loadConfigWithOptions(options),
700
+ catch: (error) => new ConfigError({
1067
701
  reason: "Failed to load configuration",
1068
702
  cause: error
1069
703
  })
1070
704
  });
1071
705
  yield* effect.Effect.sync(() => {
1072
- initializePatternMatcher(config);
1073
- logger.log("@atrim/instrumentation: Pattern matching initialized (legacy mode)");
1074
- logger.log(
706
+ instrumentCore.initializePatternMatcher(config);
707
+ instrumentCore.logger.log("@atrim/instrumentation: Pattern matching initialized (legacy mode)");
708
+ instrumentCore.logger.log(
1075
709
  " Note: NodeSDK is not initialized. Use initializeInstrumentation() for complete setup."
1076
710
  );
1077
711
  });
@@ -1171,24 +805,35 @@ function suppressShutdownErrors() {
1171
805
  });
1172
806
  }
1173
807
 
1174
- exports.ConfigError = ConfigError2;
1175
- exports.ConfigFileError = ConfigFileError2;
1176
- exports.ConfigUrlError = ConfigUrlError2;
1177
- exports.ConfigValidationError = ConfigValidationError2;
1178
- exports.ExportError = ExportError2;
1179
- exports.InitializationError = InitializationError2;
1180
- exports.PatternMatcher = PatternMatcher;
808
+ Object.defineProperty(exports, "PatternMatcher", {
809
+ enumerable: true,
810
+ get: function () { return instrumentCore.PatternMatcher; }
811
+ });
812
+ Object.defineProperty(exports, "getPatternMatcher", {
813
+ enumerable: true,
814
+ get: function () { return instrumentCore.getPatternMatcher; }
815
+ });
816
+ Object.defineProperty(exports, "shouldInstrumentSpan", {
817
+ enumerable: true,
818
+ get: function () { return instrumentCore.shouldInstrumentSpan; }
819
+ });
820
+ exports.ConfigError = ConfigError;
821
+ exports.ConfigFileError = ConfigFileError;
822
+ exports.ConfigUrlError = ConfigUrlError;
823
+ exports.ConfigValidationError = ConfigValidationError;
824
+ exports.ExportError = ExportError;
825
+ exports.InitializationError = InitializationError;
1181
826
  exports.PatternSpanProcessor = PatternSpanProcessor;
1182
- exports.ServiceDetectionError = ServiceDetectionError2;
1183
- exports.ShutdownError = ShutdownError2;
827
+ exports.ServiceDetectionError = ServiceDetectionError;
828
+ exports.ShutdownError = ShutdownError;
1184
829
  exports.annotateCacheOperation = annotateCacheOperation;
1185
830
  exports.annotateDbQuery = annotateDbQuery;
1186
831
  exports.annotateHttpRequest = annotateHttpRequest;
832
+ exports.clearConfigCache = _resetConfigLoaderCache;
1187
833
  exports.createOtlpExporter = createOtlpExporter;
1188
834
  exports.detectServiceInfo = detectServiceInfoAsync;
1189
835
  exports.detectServiceInfoEffect = detectServiceInfo;
1190
836
  exports.getOtlpEndpoint = getOtlpEndpoint;
1191
- exports.getPatternMatcher = getPatternMatcher;
1192
837
  exports.getSdkInstance = getSdkInstance;
1193
838
  exports.getServiceInfoWithFallback = getServiceInfoWithFallback;
1194
839
  exports.getServiceName = getServiceNameAsync;
@@ -1200,12 +845,13 @@ exports.initializeInstrumentationEffect = initializeInstrumentationEffect;
1200
845
  exports.initializePatternMatchingOnly = initializePatternMatchingOnly;
1201
846
  exports.initializePatternMatchingOnlyEffect = initializePatternMatchingOnlyEffect;
1202
847
  exports.loadConfig = loadConfig;
848
+ exports.loadConfigFromInline = loadConfigFromInline;
849
+ exports.loadConfigWithOptions = loadConfigWithOptions;
1203
850
  exports.markSpanError = markSpanError;
1204
851
  exports.markSpanSuccess = markSpanSuccess;
1205
852
  exports.recordException = recordException;
1206
853
  exports.resetSdk = resetSdk;
1207
854
  exports.setSpanAttributes = setSpanAttributes;
1208
- exports.shouldInstrumentSpan = shouldInstrumentSpan;
1209
855
  exports.shutdownSdk = shutdownSdk;
1210
856
  exports.suppressShutdownErrors = suppressShutdownErrors;
1211
857
  //# sourceMappingURL=index.cjs.map