@atrim/instrument-node 0.7.1-dev.14fdea7.20260108220010 → 0.7.1-dev.14fdea7.20260108231232

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.
@@ -3,6 +3,84 @@ import * as OtelApi from '@opentelemetry/api';
3
3
  import { AutoInstrumentationConfig, InstrumentationConfig } from '@atrim/instrument-core';
4
4
  export { AutoInstrumentationConfig } from '@atrim/instrument-core';
5
5
 
6
+ /**
7
+ * Effect-Native Tracing Layer
8
+ *
9
+ * Uses @effect/opentelemetry's NodeSdk.layer for proper Effect integration.
10
+ * This provides automatic HTTP request tracing and Effect.withSpan() support.
11
+ *
12
+ * Requires @effect/opentelemetry peer dependency to be installed.
13
+ */
14
+
15
+ /**
16
+ * Create a layer that provides Effect-native tracing via NodeSdk.layer
17
+ *
18
+ * This integrates with Effect's built-in tracing system, which means:
19
+ * - HTTP requests are automatically traced by @effect/platform
20
+ * - Effect.withSpan() creates proper OTel spans
21
+ * - Parent-child span relationships work correctly
22
+ * - No need to fork fibers for tracing to work
23
+ *
24
+ * Configuration is loaded from instrumentation.yaml (exporter_config section).
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * import { EffectTracingLive } from '@atrim/instrument-node/effect/auto'
29
+ *
30
+ * // HTTP requests automatically traced!
31
+ * const HttpLive = router.pipe(
32
+ * HttpServer.serve(),
33
+ * Layer.provide(ServerLive),
34
+ * Layer.provide(EffectTracingLive),
35
+ * )
36
+ * ```
37
+ */
38
+ declare const createEffectTracingLayer: () => Layer.Layer<never>;
39
+ /**
40
+ * Effect-native tracing layer using @effect/opentelemetry
41
+ *
42
+ * This is the **recommended** layer for Effect HTTP applications. It provides:
43
+ * - Automatic HTTP request tracing (built into @effect/platform)
44
+ * - Full Effect.withSpan() support for manual spans
45
+ * - Proper parent-child span relationships
46
+ * - No need to fork fibers manually
47
+ *
48
+ * Configuration is loaded from your instrumentation.yaml file.
49
+ *
50
+ * @example
51
+ * ```yaml
52
+ * # instrumentation.yaml
53
+ * effect:
54
+ * exporter_config:
55
+ * type: otlp # or 'console' for dev
56
+ * endpoint: http://localhost:4318
57
+ * headers:
58
+ * x-api-key: your-key
59
+ * processor: batch # or 'simple' for immediate export
60
+ * ```
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * import { EffectTracingLive } from '@atrim/instrument-node/effect/auto'
65
+ * import { HttpRouter, HttpServer } from "@effect/platform"
66
+ * import { NodeHttpServer, NodeRuntime } from "@effect/platform-node"
67
+ *
68
+ * const router = HttpRouter.empty.pipe(
69
+ * HttpRouter.get("/", Effect.succeed(HttpServerResponse.text("Hello!"))),
70
+ * )
71
+ *
72
+ * const HttpLive = router.pipe(
73
+ * HttpServer.serve(),
74
+ * Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 })),
75
+ * Layer.provide(EffectTracingLive), // <- Just add this!
76
+ * )
77
+ *
78
+ * NodeRuntime.runMain(Layer.launch(HttpLive))
79
+ * // All HTTP requests now automatically traced!
80
+ * ```
81
+ */
82
+ declare const EffectTracingLive: Layer.Layer<never>;
83
+
6
84
  /**
7
85
  * Auto-Tracing Supervisor for Effect-TS
8
86
  *
@@ -356,4 +434,4 @@ declare function inferSpanName(fiberId: number, sourceInfo: SourceInfo | undefin
356
434
  */
357
435
  declare function sanitizeSpanName(name: string): string;
358
436
 
359
- export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, FullAutoTracingLive, type SourceInfo, type TemplateVariables, createAutoTracingLayer, createAutoTracingSupervisor, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
437
+ export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, EffectTracingLive, FullAutoTracingLive, type SourceInfo, type TemplateVariables, createAutoTracingLayer, createAutoTracingSupervisor, createEffectTracingLayer, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
@@ -3,6 +3,84 @@ import * as OtelApi from '@opentelemetry/api';
3
3
  import { AutoInstrumentationConfig, InstrumentationConfig } from '@atrim/instrument-core';
4
4
  export { AutoInstrumentationConfig } from '@atrim/instrument-core';
5
5
 
6
+ /**
7
+ * Effect-Native Tracing Layer
8
+ *
9
+ * Uses @effect/opentelemetry's NodeSdk.layer for proper Effect integration.
10
+ * This provides automatic HTTP request tracing and Effect.withSpan() support.
11
+ *
12
+ * Requires @effect/opentelemetry peer dependency to be installed.
13
+ */
14
+
15
+ /**
16
+ * Create a layer that provides Effect-native tracing via NodeSdk.layer
17
+ *
18
+ * This integrates with Effect's built-in tracing system, which means:
19
+ * - HTTP requests are automatically traced by @effect/platform
20
+ * - Effect.withSpan() creates proper OTel spans
21
+ * - Parent-child span relationships work correctly
22
+ * - No need to fork fibers for tracing to work
23
+ *
24
+ * Configuration is loaded from instrumentation.yaml (exporter_config section).
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * import { EffectTracingLive } from '@atrim/instrument-node/effect/auto'
29
+ *
30
+ * // HTTP requests automatically traced!
31
+ * const HttpLive = router.pipe(
32
+ * HttpServer.serve(),
33
+ * Layer.provide(ServerLive),
34
+ * Layer.provide(EffectTracingLive),
35
+ * )
36
+ * ```
37
+ */
38
+ declare const createEffectTracingLayer: () => Layer.Layer<never>;
39
+ /**
40
+ * Effect-native tracing layer using @effect/opentelemetry
41
+ *
42
+ * This is the **recommended** layer for Effect HTTP applications. It provides:
43
+ * - Automatic HTTP request tracing (built into @effect/platform)
44
+ * - Full Effect.withSpan() support for manual spans
45
+ * - Proper parent-child span relationships
46
+ * - No need to fork fibers manually
47
+ *
48
+ * Configuration is loaded from your instrumentation.yaml file.
49
+ *
50
+ * @example
51
+ * ```yaml
52
+ * # instrumentation.yaml
53
+ * effect:
54
+ * exporter_config:
55
+ * type: otlp # or 'console' for dev
56
+ * endpoint: http://localhost:4318
57
+ * headers:
58
+ * x-api-key: your-key
59
+ * processor: batch # or 'simple' for immediate export
60
+ * ```
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * import { EffectTracingLive } from '@atrim/instrument-node/effect/auto'
65
+ * import { HttpRouter, HttpServer } from "@effect/platform"
66
+ * import { NodeHttpServer, NodeRuntime } from "@effect/platform-node"
67
+ *
68
+ * const router = HttpRouter.empty.pipe(
69
+ * HttpRouter.get("/", Effect.succeed(HttpServerResponse.text("Hello!"))),
70
+ * )
71
+ *
72
+ * const HttpLive = router.pipe(
73
+ * HttpServer.serve(),
74
+ * Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 })),
75
+ * Layer.provide(EffectTracingLive), // <- Just add this!
76
+ * )
77
+ *
78
+ * NodeRuntime.runMain(Layer.launch(HttpLive))
79
+ * // All HTTP requests now automatically traced!
80
+ * ```
81
+ */
82
+ declare const EffectTracingLive: Layer.Layer<never>;
83
+
6
84
  /**
7
85
  * Auto-Tracing Supervisor for Effect-TS
8
86
  *
@@ -356,4 +434,4 @@ declare function inferSpanName(fiberId: number, sourceInfo: SourceInfo | undefin
356
434
  */
357
435
  declare function sanitizeSpanName(name: string): string;
358
436
 
359
- export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, FullAutoTracingLive, type SourceInfo, type TemplateVariables, createAutoTracingLayer, createAutoTracingSupervisor, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
437
+ export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, EffectTracingLive, FullAutoTracingLive, type SourceInfo, type TemplateVariables, createAutoTracingLayer, createAutoTracingSupervisor, createEffectTracingLayer, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
@@ -1,14 +1,15 @@
1
1
  import { Data, Context, Effect, Layer, FiberRef, Option, Supervisor, FiberRefs, Exit } from 'effect';
2
- import * as OtelApi from '@opentelemetry/api';
3
- import { BasicTracerProvider, SimpleSpanProcessor, BatchSpanProcessor, ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base';
2
+ import { NodeSdk } from '@effect/opentelemetry';
3
+ import { SimpleSpanProcessor, ConsoleSpanExporter, BatchSpanProcessor, BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
4
4
  import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
5
- import { resourceFromAttributes } from '@opentelemetry/resources';
6
- import { ATTR_SERVICE_VERSION, ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
7
5
  import { FileSystem } from '@effect/platform/FileSystem';
8
6
  import * as HttpClient from '@effect/platform/HttpClient';
9
7
  import * as HttpClientRequest from '@effect/platform/HttpClientRequest';
10
8
  import { parse } from 'yaml';
11
9
  import { z } from 'zod';
10
+ import * as OtelApi from '@opentelemetry/api';
11
+ import { resourceFromAttributes } from '@opentelemetry/resources';
12
+ import { ATTR_SERVICE_VERSION, ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
12
13
  import * as path from 'path';
13
14
 
14
15
  var __defProp = Object.defineProperty;
@@ -137,6 +138,9 @@ var ExporterConfigSchema = z.object({
137
138
  // OTLP endpoint URL (for type: otlp)
138
139
  // Defaults to OTEL_EXPORTER_OTLP_ENDPOINT env var or http://localhost:4318
139
140
  endpoint: z.string().optional(),
141
+ // Custom headers to send with OTLP requests (for type: otlp)
142
+ // Useful for authentication (x-api-key, Authorization, etc.)
143
+ headers: z.record(z.string()).optional(),
140
144
  // Span processor type
141
145
  // - 'batch': Batch spans for export (production, lower overhead)
142
146
  // - 'simple': Export immediately (development, no batching delay)
@@ -463,121 +467,6 @@ var Logger = class {
463
467
  }
464
468
  };
465
469
  var logger = new Logger();
466
- var compiledRulesCache = /* @__PURE__ */ new WeakMap();
467
- function compileNamingRules(rules) {
468
- const cached = compiledRulesCache.get(rules);
469
- if (cached) return cached;
470
- const compiled = rules.map((rule) => ({
471
- original: rule,
472
- filePattern: rule.match.file ? new RegExp(rule.match.file) : void 0,
473
- functionPattern: rule.match.function ? new RegExp(rule.match.function) : void 0,
474
- modulePattern: rule.match.module ? new RegExp(rule.match.module) : void 0
475
- }));
476
- compiledRulesCache.set(rules, compiled);
477
- return compiled;
478
- }
479
- function extractModuleName(filePath) {
480
- const basename2 = path.basename(filePath, path.extname(filePath));
481
- return basename2.replace(/\.(service|controller|handler|util|helper|model|repo|repository)$/i, "").replace(/(Service|Controller|Handler|Util|Helper|Model|Repo|Repository)$/i, "");
482
- }
483
- function applyTemplate(template, variables, matchGroups) {
484
- let result = template;
485
- for (const [key, value] of Object.entries(variables)) {
486
- result = result.replace(new RegExp(`\\{${key}\\}`, "g"), value);
487
- }
488
- if (matchGroups) {
489
- result = result.replace(
490
- /\{match:(\w+):(\d+)\}/g,
491
- (_fullMatch, field, index) => {
492
- const groups = matchGroups.get(field);
493
- const idx = parseInt(index, 10);
494
- if (groups && groups[idx]) {
495
- return groups[idx];
496
- }
497
- return "";
498
- }
499
- );
500
- }
501
- return result;
502
- }
503
- function findMatchingRule(sourceInfo, config) {
504
- const rules = config.span_naming?.rules;
505
- if (!rules || rules.length === 0) return void 0;
506
- const compiledRules = compileNamingRules(rules);
507
- for (const rule of compiledRules) {
508
- const matchGroups = /* @__PURE__ */ new Map();
509
- let allMatched = true;
510
- if (rule.filePattern) {
511
- if (sourceInfo?.file) {
512
- const match = sourceInfo.file.match(rule.filePattern);
513
- if (match) {
514
- matchGroups.set("file", match.slice(1));
515
- } else {
516
- allMatched = false;
517
- }
518
- } else {
519
- allMatched = false;
520
- }
521
- }
522
- if (rule.functionPattern && allMatched) {
523
- if (sourceInfo?.function) {
524
- const match = sourceInfo.function.match(rule.functionPattern);
525
- if (match) {
526
- matchGroups.set("function", match.slice(1));
527
- } else {
528
- allMatched = false;
529
- }
530
- } else {
531
- allMatched = false;
532
- }
533
- }
534
- if (rule.modulePattern && allMatched) {
535
- const moduleName = sourceInfo?.file ? extractModuleName(sourceInfo.file) : "";
536
- if (moduleName) {
537
- const match = moduleName.match(rule.modulePattern);
538
- if (match) {
539
- matchGroups.set("module", match.slice(1));
540
- } else {
541
- allMatched = false;
542
- }
543
- } else {
544
- allMatched = false;
545
- }
546
- }
547
- if (allMatched) {
548
- return { rule, matchGroups };
549
- }
550
- }
551
- return void 0;
552
- }
553
- function inferSpanName(fiberId, sourceInfo, config) {
554
- const variables = {
555
- fiber_id: String(fiberId),
556
- function: sourceInfo?.function || "anonymous",
557
- module: sourceInfo?.file ? extractModuleName(sourceInfo.file) : "unknown",
558
- file: sourceInfo?.file || "unknown",
559
- line: sourceInfo?.line ? String(sourceInfo.line) : "0",
560
- operator: "gen"
561
- // Default operator, could be enhanced with more context
562
- };
563
- const match = findMatchingRule(sourceInfo, config);
564
- if (match) {
565
- return applyTemplate(match.rule.original.name, variables, match.matchGroups);
566
- }
567
- const defaultTemplate = config.span_naming?.default || "effect.fiber.{fiber_id}";
568
- return applyTemplate(defaultTemplate, variables);
569
- }
570
- function sanitizeSpanName(name) {
571
- if (!name) return "effect.fiber.unknown";
572
- let sanitized = name.replace(/[^a-zA-Z0-9._-]/g, "_");
573
- sanitized = sanitized.replace(/_+/g, "_");
574
- sanitized = sanitized.replace(/^_+|_+$/g, "");
575
- if (!sanitized) return "effect.fiber.unknown";
576
- if (sanitized.length > 256) {
577
- sanitized = sanitized.substring(0, 256);
578
- }
579
- return sanitized;
580
- }
581
470
  async function loadFromFile(filePath) {
582
471
  const { readFile } = await import('fs/promises');
583
472
  const content = await readFile(filePath, "utf-8");
@@ -698,6 +587,182 @@ var loadFullConfig = (options) => Effect.gen(function* () {
698
587
  return config;
699
588
  });
700
589
 
590
+ // src/integrations/effect/auto/effect-tracing.ts
591
+ var createEffectTracingLayer = () => {
592
+ return Layer.unwrapEffect(
593
+ Effect.gen(function* () {
594
+ const config = yield* loadFullConfig();
595
+ const serviceName = process.env.OTEL_SERVICE_NAME || "effect-service";
596
+ const serviceVersion = process.env.npm_package_version || "1.0.0";
597
+ const exporterConfig = config.effect?.exporter_config ?? {
598
+ type: "otlp",
599
+ processor: "batch"
600
+ };
601
+ logger.log("@atrim/auto-trace: Effect-native tracing enabled");
602
+ logger.log(` Service: ${serviceName}`);
603
+ logger.log(` Exporter: ${exporterConfig.type}`);
604
+ if (exporterConfig.type === "none") {
605
+ logger.log('@atrim/auto-trace: Exporter type is "none", using empty layer');
606
+ return Layer.empty;
607
+ }
608
+ const createSpanProcessor = () => {
609
+ if (exporterConfig.type === "console") {
610
+ logger.log("@atrim/auto-trace: Using ConsoleSpanExporter with SimpleSpanProcessor");
611
+ return new SimpleSpanProcessor(new ConsoleSpanExporter());
612
+ }
613
+ const endpoint = exporterConfig.endpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
614
+ logger.log(`@atrim/auto-trace: Using OTLPTraceExporter (${endpoint})`);
615
+ const otlpConfig = {
616
+ url: `${endpoint}/v1/traces`
617
+ };
618
+ if (exporterConfig.headers) {
619
+ otlpConfig.headers = exporterConfig.headers;
620
+ logger.log(`@atrim/auto-trace: Using custom headers: ${Object.keys(exporterConfig.headers).join(", ")}`);
621
+ }
622
+ const exporter = new OTLPTraceExporter(otlpConfig);
623
+ if (exporterConfig.processor === "simple") {
624
+ logger.log("@atrim/auto-trace: Using SimpleSpanProcessor");
625
+ return new SimpleSpanProcessor(exporter);
626
+ }
627
+ const batchConfig = exporterConfig.batch ?? {
628
+ scheduled_delay_millis: 1e3,
629
+ max_export_batch_size: 100
630
+ };
631
+ logger.log("@atrim/auto-trace: Using BatchSpanProcessor");
632
+ return new BatchSpanProcessor(exporter, {
633
+ scheduledDelayMillis: batchConfig.scheduled_delay_millis,
634
+ maxExportBatchSize: batchConfig.max_export_batch_size
635
+ });
636
+ };
637
+ const sdkLayer = NodeSdk.layer(() => ({
638
+ resource: {
639
+ serviceName,
640
+ serviceVersion
641
+ },
642
+ spanProcessor: createSpanProcessor()
643
+ }));
644
+ logger.log("@atrim/auto-trace: NodeSdk layer created - HTTP requests will be auto-traced");
645
+ return Layer.discard(sdkLayer);
646
+ })
647
+ );
648
+ };
649
+ var EffectTracingLive = createEffectTracingLayer();
650
+ var compiledRulesCache = /* @__PURE__ */ new WeakMap();
651
+ function compileNamingRules(rules) {
652
+ const cached = compiledRulesCache.get(rules);
653
+ if (cached) return cached;
654
+ const compiled = rules.map((rule) => ({
655
+ original: rule,
656
+ filePattern: rule.match.file ? new RegExp(rule.match.file) : void 0,
657
+ functionPattern: rule.match.function ? new RegExp(rule.match.function) : void 0,
658
+ modulePattern: rule.match.module ? new RegExp(rule.match.module) : void 0
659
+ }));
660
+ compiledRulesCache.set(rules, compiled);
661
+ return compiled;
662
+ }
663
+ function extractModuleName(filePath) {
664
+ const basename2 = path.basename(filePath, path.extname(filePath));
665
+ return basename2.replace(/\.(service|controller|handler|util|helper|model|repo|repository)$/i, "").replace(/(Service|Controller|Handler|Util|Helper|Model|Repo|Repository)$/i, "");
666
+ }
667
+ function applyTemplate(template, variables, matchGroups) {
668
+ let result = template;
669
+ for (const [key, value] of Object.entries(variables)) {
670
+ result = result.replace(new RegExp(`\\{${key}\\}`, "g"), value);
671
+ }
672
+ if (matchGroups) {
673
+ result = result.replace(
674
+ /\{match:(\w+):(\d+)\}/g,
675
+ (_fullMatch, field, index) => {
676
+ const groups = matchGroups.get(field);
677
+ const idx = parseInt(index, 10);
678
+ if (groups && groups[idx]) {
679
+ return groups[idx];
680
+ }
681
+ return "";
682
+ }
683
+ );
684
+ }
685
+ return result;
686
+ }
687
+ function findMatchingRule(sourceInfo, config) {
688
+ const rules = config.span_naming?.rules;
689
+ if (!rules || rules.length === 0) return void 0;
690
+ const compiledRules = compileNamingRules(rules);
691
+ for (const rule of compiledRules) {
692
+ const matchGroups = /* @__PURE__ */ new Map();
693
+ let allMatched = true;
694
+ if (rule.filePattern) {
695
+ if (sourceInfo?.file) {
696
+ const match = sourceInfo.file.match(rule.filePattern);
697
+ if (match) {
698
+ matchGroups.set("file", match.slice(1));
699
+ } else {
700
+ allMatched = false;
701
+ }
702
+ } else {
703
+ allMatched = false;
704
+ }
705
+ }
706
+ if (rule.functionPattern && allMatched) {
707
+ if (sourceInfo?.function) {
708
+ const match = sourceInfo.function.match(rule.functionPattern);
709
+ if (match) {
710
+ matchGroups.set("function", match.slice(1));
711
+ } else {
712
+ allMatched = false;
713
+ }
714
+ } else {
715
+ allMatched = false;
716
+ }
717
+ }
718
+ if (rule.modulePattern && allMatched) {
719
+ const moduleName = sourceInfo?.file ? extractModuleName(sourceInfo.file) : "";
720
+ if (moduleName) {
721
+ const match = moduleName.match(rule.modulePattern);
722
+ if (match) {
723
+ matchGroups.set("module", match.slice(1));
724
+ } else {
725
+ allMatched = false;
726
+ }
727
+ } else {
728
+ allMatched = false;
729
+ }
730
+ }
731
+ if (allMatched) {
732
+ return { rule, matchGroups };
733
+ }
734
+ }
735
+ return void 0;
736
+ }
737
+ function inferSpanName(fiberId, sourceInfo, config) {
738
+ const variables = {
739
+ fiber_id: String(fiberId),
740
+ function: sourceInfo?.function || "anonymous",
741
+ module: sourceInfo?.file ? extractModuleName(sourceInfo.file) : "unknown",
742
+ file: sourceInfo?.file || "unknown",
743
+ line: sourceInfo?.line ? String(sourceInfo.line) : "0",
744
+ operator: "gen"
745
+ // Default operator, could be enhanced with more context
746
+ };
747
+ const match = findMatchingRule(sourceInfo, config);
748
+ if (match) {
749
+ return applyTemplate(match.rule.original.name, variables, match.matchGroups);
750
+ }
751
+ const defaultTemplate = config.span_naming?.default || "effect.fiber.{fiber_id}";
752
+ return applyTemplate(defaultTemplate, variables);
753
+ }
754
+ function sanitizeSpanName(name) {
755
+ if (!name) return "effect.fiber.unknown";
756
+ let sanitized = name.replace(/[^a-zA-Z0-9._-]/g, "_");
757
+ sanitized = sanitized.replace(/_+/g, "_");
758
+ sanitized = sanitized.replace(/^_+|_+$/g, "");
759
+ if (!sanitized) return "effect.fiber.unknown";
760
+ if (sanitized.length > 256) {
761
+ sanitized = sanitized.substring(0, 256);
762
+ }
763
+ return sanitized;
764
+ }
765
+
701
766
  // src/integrations/effect/auto/supervisor.ts
702
767
  var AutoTracingEnabled = FiberRef.unsafeMake(true);
703
768
  var AutoTracingSpanName = FiberRef.unsafeMake(Option.none());
@@ -998,9 +1063,14 @@ var createExporterLayer = (exporterConfig, serviceName, serviceVersion) => {
998
1063
  }
999
1064
  const endpoint = config.endpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
1000
1065
  logger.log(`@atrim/auto-trace: Using OTLPTraceExporter (${endpoint})`);
1001
- return new OTLPTraceExporter({
1066
+ const exporterConfig2 = {
1002
1067
  url: `${endpoint}/v1/traces`
1003
- });
1068
+ };
1069
+ if (config.headers) {
1070
+ exporterConfig2.headers = config.headers;
1071
+ logger.log(`@atrim/auto-trace: Using custom headers: ${Object.keys(config.headers).join(", ")}`);
1072
+ }
1073
+ return new OTLPTraceExporter(exporterConfig2);
1004
1074
  };
1005
1075
  const createSpanProcessor = () => {
1006
1076
  const exporter = createSpanExporter();
@@ -1061,6 +1131,6 @@ var createFullAutoTracingLayer = () => {
1061
1131
  };
1062
1132
  var FullAutoTracingLive = createFullAutoTracingLayer();
1063
1133
 
1064
- export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, FullAutoTracingLive, createAutoTracingLayer, createAutoTracingSupervisor, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
1134
+ export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, EffectTracingLive, FullAutoTracingLive, createAutoTracingLayer, createAutoTracingSupervisor, createEffectTracingLayer, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
1065
1135
  //# sourceMappingURL=index.js.map
1066
1136
  //# sourceMappingURL=index.js.map