@atrim/instrument-node 0.5.0 → 0.5.1-1451fcf-20260105212505

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.
@@ -1,15 +1,17 @@
1
1
  'use strict';
2
2
 
3
3
  var effect = require('effect');
4
+ var OtelTracer = require('@effect/opentelemetry/Tracer');
5
+ var Resource = require('@effect/opentelemetry/Resource');
4
6
  var Otlp = require('@effect/opentelemetry/Otlp');
5
7
  var platform = require('@effect/platform');
6
8
  var api = require('@opentelemetry/api');
9
+ var semanticConventions = require('@opentelemetry/semantic-conventions');
7
10
  var FileSystem = require('@effect/platform/FileSystem');
8
11
  var HttpClient = require('@effect/platform/HttpClient');
9
12
  var HttpClientRequest = require('@effect/platform/HttpClientRequest');
10
13
  var yaml = require('yaml');
11
14
  var zod = require('zod');
12
- var platformNode = require('@effect/platform-node');
13
15
 
14
16
  function _interopNamespace(e) {
15
17
  if (e && e.__esModule) return e;
@@ -29,6 +31,8 @@ function _interopNamespace(e) {
29
31
  return Object.freeze(n);
30
32
  }
31
33
 
34
+ var OtelTracer__namespace = /*#__PURE__*/_interopNamespace(OtelTracer);
35
+ var Resource__namespace = /*#__PURE__*/_interopNamespace(Resource);
32
36
  var Otlp__namespace = /*#__PURE__*/_interopNamespace(Otlp);
33
37
  var HttpClient__namespace = /*#__PURE__*/_interopNamespace(HttpClient);
34
38
  var HttpClientRequest__namespace = /*#__PURE__*/_interopNamespace(HttpClientRequest);
@@ -70,7 +74,20 @@ var HttpFilteringConfigSchema = zod.z.object({
70
74
  // Patterns to ignore for incoming HTTP requests (string patterns only in YAML)
71
75
  ignore_incoming_paths: zod.z.array(zod.z.string()).optional(),
72
76
  // Require parent span for outgoing requests (prevents root spans for HTTP calls)
73
- require_parent_for_outgoing_spans: zod.z.boolean().optional()
77
+ require_parent_for_outgoing_spans: zod.z.boolean().optional(),
78
+ // Trace context propagation configuration
79
+ // Controls which cross-origin requests receive W3C Trace Context headers (traceparent, tracestate)
80
+ propagate_trace_context: zod.z.object({
81
+ // Strategy for trace propagation
82
+ // - "all": Propagate to all cross-origin requests (may cause CORS errors)
83
+ // - "none": Never propagate trace headers
84
+ // - "same-origin": Only propagate to same-origin requests (default, safe)
85
+ // - "patterns": Propagate based on include_urls patterns
86
+ strategy: zod.z.enum(["all", "none", "same-origin", "patterns"]).default("same-origin"),
87
+ // URL patterns to include when strategy is "patterns"
88
+ // Supports regex patterns (e.g., "^https://api\\.myapp\\.com")
89
+ include_urls: zod.z.array(zod.z.string()).optional()
90
+ }).optional()
74
91
  });
75
92
  var InstrumentationConfigSchema = zod.z.object({
76
93
  version: zod.z.string(),
@@ -82,11 +99,50 @@ var InstrumentationConfigSchema = zod.z.object({
82
99
  ignore_patterns: zod.z.array(PatternConfigSchema)
83
100
  }),
84
101
  effect: zod.z.object({
102
+ // Enable/disable Effect tracing entirely
103
+ // When false, EffectInstrumentationLive returns Layer.empty
104
+ enabled: zod.z.boolean().default(true),
105
+ // Exporter mode:
106
+ // - "unified": Use global TracerProvider from Node SDK (recommended, enables filtering)
107
+ // - "standalone": Use Effect's own OTLP exporter (bypasses Node SDK filtering)
108
+ exporter: zod.z.enum(["unified", "standalone"]).default("unified"),
85
109
  auto_extract_metadata: zod.z.boolean(),
86
110
  auto_isolation: AutoIsolationConfigSchema.optional()
87
111
  }).optional(),
88
112
  http: HttpFilteringConfigSchema.optional()
89
113
  });
114
+ var defaultConfig = {
115
+ version: "1.0",
116
+ instrumentation: {
117
+ enabled: true,
118
+ logging: "on",
119
+ description: "Default instrumentation configuration",
120
+ instrument_patterns: [
121
+ { pattern: "^app\\.", enabled: true, description: "Application operations" },
122
+ { pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
123
+ { pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
124
+ ],
125
+ ignore_patterns: [
126
+ { pattern: "^test\\.", description: "Test utilities" },
127
+ { pattern: "^internal\\.", description: "Internal operations" },
128
+ { pattern: "^health\\.", description: "Health checks" }
129
+ ]
130
+ },
131
+ effect: {
132
+ enabled: true,
133
+ exporter: "unified",
134
+ auto_extract_metadata: true
135
+ }
136
+ };
137
+ function parseAndValidateConfig(content) {
138
+ let parsed;
139
+ if (typeof content === "string") {
140
+ parsed = yaml.parse(content);
141
+ } else {
142
+ parsed = content;
143
+ }
144
+ return InstrumentationConfigSchema.parse(parsed);
145
+ }
90
146
  (class extends effect.Data.TaggedError("ConfigError") {
91
147
  get message() {
92
148
  return this.reason;
@@ -264,7 +320,7 @@ var makeConfigLoader = effect.Effect.gen(function* () {
264
320
  })
265
321
  });
266
322
  });
267
- var ConfigLoaderLive = effect.Layer.effect(ConfigLoader, makeConfigLoader);
323
+ effect.Layer.effect(ConfigLoader, makeConfigLoader);
268
324
  var PatternMatcher = class {
269
325
  constructor(config) {
270
326
  __publicField(this, "ignorePatterns", []);
@@ -412,83 +468,73 @@ var Logger = class {
412
468
  }
413
469
  };
414
470
  var logger = new Logger();
415
- var NodeConfigLoaderLive = ConfigLoaderLive.pipe(
416
- effect.Layer.provide(effect.Layer.mergeAll(platformNode.NodeContext.layer, platform.FetchHttpClient.layer))
417
- );
418
- var cachedLoaderPromise = null;
419
- function getCachedLoader() {
420
- if (!cachedLoaderPromise) {
421
- cachedLoaderPromise = effect.Effect.runPromise(
422
- effect.Effect.gen(function* () {
423
- return yield* ConfigLoader;
424
- }).pipe(effect.Effect.provide(NodeConfigLoaderLive))
425
- );
471
+ async function loadFromFile(filePath) {
472
+ const { readFile } = await import('fs/promises');
473
+ const content = await readFile(filePath, "utf-8");
474
+ return parseAndValidateConfig(content);
475
+ }
476
+ async function loadFromUrl(url) {
477
+ const response = await fetch(url);
478
+ if (!response.ok) {
479
+ throw new Error(`Failed to fetch config from ${url}: ${response.statusText}`);
426
480
  }
427
- return cachedLoaderPromise;
481
+ const content = await response.text();
482
+ return parseAndValidateConfig(content);
428
483
  }
429
- async function loadConfig(uri, options) {
430
- if (options?.cacheTimeout === 0) {
431
- const program = effect.Effect.gen(function* () {
432
- const loader2 = yield* ConfigLoader;
433
- return yield* loader2.loadFromUri(uri);
434
- });
435
- return effect.Effect.runPromise(program.pipe(effect.Effect.provide(NodeConfigLoaderLive)));
484
+ async function loadConfig(uri, _options) {
485
+ if (uri.startsWith("http://") || uri.startsWith("https://")) {
486
+ return loadFromUrl(uri);
487
+ }
488
+ if (uri.startsWith("file://")) {
489
+ const filePath = uri.slice(7);
490
+ return loadFromFile(filePath);
436
491
  }
437
- const loader = await getCachedLoader();
438
- return effect.Effect.runPromise(loader.loadFromUri(uri));
492
+ return loadFromFile(uri);
439
493
  }
440
494
  async function loadConfigFromInline(content) {
441
- const loader = await getCachedLoader();
442
- return effect.Effect.runPromise(loader.loadFromInline(content));
443
- }
444
- function getDefaultConfig() {
445
- return {
446
- version: "1.0",
447
- instrumentation: {
448
- enabled: true,
449
- logging: "on",
450
- description: "Default instrumentation configuration",
451
- instrument_patterns: [
452
- { pattern: "^app\\.", enabled: true, description: "Application operations" },
453
- { pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
454
- { pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
455
- ],
456
- ignore_patterns: [
457
- { pattern: "^test\\.", description: "Test utilities" },
458
- { pattern: "^internal\\.", description: "Internal operations" },
459
- { pattern: "^health\\.", description: "Health checks" }
460
- ]
461
- },
462
- effect: {
463
- auto_extract_metadata: true
464
- }
465
- };
495
+ return parseAndValidateConfig(content);
466
496
  }
467
497
  async function loadConfigWithOptions(options = {}) {
468
- const loadOptions = options.cacheTimeout !== void 0 ? { cacheTimeout: options.cacheTimeout } : void 0;
469
498
  if (options.config) {
470
499
  return loadConfigFromInline(options.config);
471
500
  }
472
501
  const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
473
502
  if (envConfigPath) {
474
- return loadConfig(envConfigPath, loadOptions);
503
+ return loadConfig(envConfigPath);
475
504
  }
476
505
  if (options.configUrl) {
477
- return loadConfig(options.configUrl, loadOptions);
506
+ return loadConfig(options.configUrl);
478
507
  }
479
508
  if (options.configPath) {
480
- return loadConfig(options.configPath, loadOptions);
509
+ return loadConfig(options.configPath);
481
510
  }
482
511
  const { existsSync } = await import('fs');
483
512
  const { join } = await import('path');
484
513
  const defaultPath = join(process.cwd(), "instrumentation.yaml");
485
514
  if (existsSync(defaultPath)) {
486
- return loadConfig(defaultPath, loadOptions);
515
+ return loadConfig(defaultPath);
487
516
  }
488
- return getDefaultConfig();
517
+ return defaultConfig;
489
518
  }
490
519
 
491
520
  // src/integrations/effect/effect-tracer.ts
521
+ var SDK_NAME = "@effect/opentelemetry";
522
+ var ATTR_TELEMETRY_EXPORTER_MODE = "telemetry.exporter.mode";
523
+ var ATTR_EFFECT_INSTRUMENTED = "effect.instrumented";
524
+ var EffectAttributeTracerLayer = effect.Layer.effect(
525
+ effect.Tracer.Tracer,
526
+ effect.Effect.gen(function* () {
527
+ const baseTracer = yield* OtelTracer__namespace.make;
528
+ return effect.Tracer.make({
529
+ span: (name, parent, context2, links, startTime, kind, options) => {
530
+ const span = baseTracer.span(name, parent, context2, links, startTime, kind, options);
531
+ span.attribute(ATTR_EFFECT_INSTRUMENTED, true);
532
+ return span;
533
+ },
534
+ context: (f, fiber) => baseTracer.context(f, fiber)
535
+ });
536
+ }).pipe(effect.Effect.provide(OtelTracer__namespace.layerGlobalTracer))
537
+ );
492
538
  function createEffectInstrumentation(options = {}) {
493
539
  return effect.Layer.unwrapEffect(
494
540
  effect.Effect.gen(function* () {
@@ -499,106 +545,228 @@ function createEffectInstrumentation(options = {}) {
499
545
  message: error instanceof Error ? error.message : String(error)
500
546
  })
501
547
  });
548
+ const effectEnabled = process.env.OTEL_EFFECT_ENABLED !== "false" && (config.effect?.enabled ?? true);
549
+ if (!effectEnabled) {
550
+ logger.log("@atrim/instrumentation/effect: Effect tracing disabled via config");
551
+ return effect.Layer.empty;
552
+ }
502
553
  yield* effect.Effect.sync(() => {
503
554
  const loggingLevel = config.instrumentation.logging || "on";
504
555
  logger.setLevel(loggingLevel);
505
556
  });
506
557
  yield* effect.Effect.sync(() => initializePatternMatcher(config));
507
- const otlpEndpoint = options.otlpEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
508
558
  const serviceName = options.serviceName || process.env.OTEL_SERVICE_NAME || "effect-service";
509
559
  const serviceVersion = options.serviceVersion || process.env.npm_package_version || "1.0.0";
510
- const autoExtractMetadata = options.autoExtractMetadata ?? config.effect?.auto_extract_metadata ?? true;
511
- const continueExistingTraces = options.continueExistingTraces ?? true;
512
- logger.log("\u{1F50D} Effect OpenTelemetry instrumentation");
513
- logger.log(` \u{1F4E1} Endpoint: ${otlpEndpoint}`);
514
- logger.log(` \u{1F3F7}\uFE0F Service: ${serviceName}`);
515
- logger.log(` \u2705 Auto metadata extraction: ${autoExtractMetadata}`);
516
- logger.log(` \u2705 Continue existing traces: ${continueExistingTraces}`);
517
- const otlpLayer = Otlp__namespace.layer({
518
- baseUrl: otlpEndpoint,
519
- resource: {
520
- serviceName,
521
- serviceVersion,
522
- attributes: {
523
- "platform.component": "effect",
524
- "effect.auto_metadata": autoExtractMetadata,
525
- "effect.context_propagation": continueExistingTraces
526
- }
527
- },
528
- // Bridge Effect context to OpenTelemetry global context
529
- // This is essential for context propagation to work properly
530
- tracerContext: (f, span) => {
531
- if (span._tag !== "Span") {
532
- return f();
560
+ const exporterMode = options.exporterMode ?? config.effect?.exporter ?? "unified";
561
+ const resourceAttributes = {
562
+ "platform.component": "effect",
563
+ [semanticConventions.ATTR_TELEMETRY_SDK_LANGUAGE]: semanticConventions.TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
564
+ [semanticConventions.ATTR_TELEMETRY_SDK_NAME]: SDK_NAME,
565
+ [ATTR_TELEMETRY_EXPORTER_MODE]: exporterMode
566
+ };
567
+ if (exporterMode === "standalone") {
568
+ const otlpEndpoint = options.otlpEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
569
+ logger.log("Effect OpenTelemetry instrumentation (standalone)");
570
+ logger.log(` Service: ${serviceName}`);
571
+ logger.log(` Endpoint: ${otlpEndpoint}`);
572
+ logger.log(" WARNING: Standalone mode bypasses Node SDK filtering");
573
+ return Otlp__namespace.layer({
574
+ baseUrl: otlpEndpoint,
575
+ resource: {
576
+ serviceName,
577
+ serviceVersion,
578
+ attributes: resourceAttributes
579
+ },
580
+ // Bridge Effect context to OpenTelemetry global context
581
+ tracerContext: (f, span) => {
582
+ if (span._tag !== "Span") {
583
+ return f();
584
+ }
585
+ const spanContext = {
586
+ traceId: span.traceId,
587
+ spanId: span.spanId,
588
+ traceFlags: span.sampled ? api.TraceFlags.SAMPLED : api.TraceFlags.NONE
589
+ };
590
+ const otelSpan = api.trace.wrapSpanContext(spanContext);
591
+ return api.context.with(api.trace.setSpan(api.context.active(), otelSpan), f);
533
592
  }
534
- const spanContext = {
535
- traceId: span.traceId,
536
- spanId: span.spanId,
537
- traceFlags: span.sampled ? api.TraceFlags.SAMPLED : api.TraceFlags.NONE
538
- };
539
- const otelSpan = api.trace.wrapSpanContext(spanContext);
540
- return api.context.with(api.trace.setSpan(api.context.active(), otelSpan), f);
541
- }
542
- }).pipe(effect.Layer.provide(platform.FetchHttpClient.layer));
543
- if (autoExtractMetadata) {
544
- return otlpLayer;
593
+ }).pipe(effect.Layer.provide(platform.FetchHttpClient.layer));
594
+ } else {
595
+ logger.log("Effect OpenTelemetry instrumentation (unified)");
596
+ logger.log(` Service: ${serviceName}`);
597
+ logger.log(" Using global TracerProvider for span export");
598
+ return EffectAttributeTracerLayer.pipe(
599
+ effect.Layer.provide(
600
+ Resource__namespace.layer({
601
+ serviceName,
602
+ serviceVersion,
603
+ attributes: resourceAttributes
604
+ })
605
+ )
606
+ );
545
607
  }
546
- return otlpLayer;
547
608
  })
548
609
  ).pipe(effect.Layer.orDie);
549
610
  }
550
611
  var EffectInstrumentationLive = effect.Effect.sync(() => {
551
- const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
552
612
  const serviceName = process.env.OTEL_SERVICE_NAME || "effect-service";
553
613
  const serviceVersion = process.env.npm_package_version || "1.0.0";
554
614
  logger.minimal(`@atrim/instrumentation/effect: Effect tracing enabled (${serviceName})`);
555
- logger.log("\u{1F50D} Effect OpenTelemetry tracer");
556
- logger.log(` \u{1F4E1} Endpoint: ${endpoint}`);
557
- logger.log(` \u{1F3F7}\uFE0F Service: ${serviceName}`);
558
- return Otlp__namespace.layer({
559
- baseUrl: endpoint,
560
- resource: {
561
- serviceName,
562
- serviceVersion,
563
- attributes: {
564
- "platform.component": "effect"
565
- }
566
- },
567
- // CRITICAL: Bridge Effect context to OpenTelemetry global context
568
- // This allows NodeSDK auto-instrumentation to see Effect spans as parent spans
569
- tracerContext: (f, span) => {
570
- if (span._tag !== "Span") {
571
- return f();
572
- }
573
- const spanContext = {
574
- traceId: span.traceId,
575
- spanId: span.spanId,
576
- traceFlags: span.sampled ? api.TraceFlags.SAMPLED : api.TraceFlags.NONE
577
- };
578
- const otelSpan = api.trace.wrapSpanContext(spanContext);
579
- return api.context.with(api.trace.setSpan(api.context.active(), otelSpan), f);
580
- }
581
- }).pipe(effect.Layer.provide(platform.FetchHttpClient.layer));
615
+ logger.log("Effect OpenTelemetry tracer (unified)");
616
+ logger.log(` Service: ${serviceName}`);
617
+ return EffectAttributeTracerLayer.pipe(
618
+ effect.Layer.provide(
619
+ Resource__namespace.layer({
620
+ serviceName,
621
+ serviceVersion,
622
+ attributes: {
623
+ "platform.component": "effect",
624
+ [semanticConventions.ATTR_TELEMETRY_SDK_LANGUAGE]: semanticConventions.TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
625
+ [semanticConventions.ATTR_TELEMETRY_SDK_NAME]: SDK_NAME,
626
+ [ATTR_TELEMETRY_EXPORTER_MODE]: "unified"
627
+ }
628
+ })
629
+ )
630
+ );
582
631
  }).pipe(effect.Layer.unwrapEffect);
583
-
584
- // src/integrations/effect/effect-helpers.ts
585
- function annotateUser(_userId, _email) {
632
+ function annotateUser(userId, email, username) {
633
+ const attributes = {
634
+ "user.id": userId
635
+ };
636
+ if (email) attributes["user.email"] = email;
637
+ if (username) attributes["user.name"] = username;
638
+ return effect.Effect.annotateCurrentSpan(attributes);
586
639
  }
587
- function annotateDataSize(_bytes, _count) {
640
+ function annotateDataSize(bytes, items, compressionRatio) {
641
+ const attributes = {
642
+ "data.size.bytes": bytes,
643
+ "data.size.items": items
644
+ };
645
+ if (compressionRatio !== void 0) {
646
+ attributes["data.compression.ratio"] = compressionRatio;
647
+ }
648
+ return effect.Effect.annotateCurrentSpan(attributes);
588
649
  }
589
- function annotateBatch(_size, _batchSize) {
650
+ function annotateBatch(totalItems, batchSize, successCount, failureCount) {
651
+ const attributes = {
652
+ "batch.size": batchSize,
653
+ "batch.total_items": totalItems,
654
+ "batch.count": Math.ceil(totalItems / batchSize)
655
+ };
656
+ if (successCount !== void 0) {
657
+ attributes["batch.success_count"] = successCount;
658
+ }
659
+ if (failureCount !== void 0) {
660
+ attributes["batch.failure_count"] = failureCount;
661
+ }
662
+ return effect.Effect.annotateCurrentSpan(attributes);
590
663
  }
591
- function annotateLLM(_model, _operation, _inputTokens, _outputTokens) {
664
+ function annotateLLM(model, provider, tokens) {
665
+ const attributes = {
666
+ "llm.model": model,
667
+ "llm.provider": provider
668
+ };
669
+ if (tokens) {
670
+ if (tokens.prompt !== void 0) attributes["llm.tokens.prompt"] = tokens.prompt;
671
+ if (tokens.completion !== void 0) attributes["llm.tokens.completion"] = tokens.completion;
672
+ if (tokens.total !== void 0) attributes["llm.tokens.total"] = tokens.total;
673
+ }
674
+ return effect.Effect.annotateCurrentSpan(attributes);
675
+ }
676
+ function annotateQuery(query, duration, rowCount, database) {
677
+ const attributes = {
678
+ "db.statement": query.length > 1e3 ? query.substring(0, 1e3) + "..." : query
679
+ };
680
+ if (duration !== void 0) attributes["db.duration.ms"] = duration;
681
+ if (rowCount !== void 0) attributes["db.row_count"] = rowCount;
682
+ if (database) attributes["db.name"] = database;
683
+ return effect.Effect.annotateCurrentSpan(attributes);
684
+ }
685
+ function annotateHttpRequest(method, url, statusCode, contentLength) {
686
+ const attributes = {
687
+ "http.method": method,
688
+ "http.url": url
689
+ };
690
+ if (statusCode !== void 0) attributes["http.status_code"] = statusCode;
691
+ if (contentLength !== void 0) attributes["http.response.content_length"] = contentLength;
692
+ return effect.Effect.annotateCurrentSpan(attributes);
693
+ }
694
+ function annotateError(error, recoverable, errorType) {
695
+ const errorMessage = typeof error === "string" ? error : error.message;
696
+ const errorStack = typeof error === "string" ? void 0 : error.stack;
697
+ const attributes = {
698
+ "error.message": errorMessage,
699
+ "error.recoverable": recoverable
700
+ };
701
+ if (errorType) attributes["error.type"] = errorType;
702
+ if (errorStack) attributes["error.stack"] = errorStack;
703
+ return effect.Effect.annotateCurrentSpan(attributes);
592
704
  }
593
- function annotateQuery(_query, _database) {
705
+ function annotatePriority(priority, reason) {
706
+ const attributes = {
707
+ "operation.priority": priority
708
+ };
709
+ if (reason) attributes["operation.priority.reason"] = reason;
710
+ return effect.Effect.annotateCurrentSpan(attributes);
594
711
  }
595
- function annotateHttpRequest(_method, _url, _statusCode) {
712
+ function annotateCache(hit, key, ttl) {
713
+ const attributes = {
714
+ "cache.hit": hit,
715
+ "cache.key": key
716
+ };
717
+ if (ttl !== void 0) attributes["cache.ttl.seconds"] = ttl;
718
+ return effect.Effect.annotateCurrentSpan(attributes);
596
719
  }
597
- function annotateError(_error, _context) {
720
+ function extractEffectMetadata() {
721
+ return effect.Effect.gen(function* () {
722
+ const metadata = {};
723
+ const currentFiber = effect.Fiber.getCurrentFiber();
724
+ if (effect.Option.isSome(currentFiber)) {
725
+ const fiber = currentFiber.value;
726
+ const fiberId = fiber.id();
727
+ metadata["effect.fiber.id"] = effect.FiberId.threadName(fiberId);
728
+ const status = yield* effect.Fiber.status(fiber);
729
+ if (status._tag) {
730
+ metadata["effect.fiber.status"] = status._tag;
731
+ }
732
+ }
733
+ const parentSpanResult = yield* effect.Effect.currentSpan.pipe(
734
+ effect.Effect.option
735
+ // Convert NoSuchElementException to Option
736
+ );
737
+ if (effect.Option.isSome(parentSpanResult)) {
738
+ const parentSpan = parentSpanResult.value;
739
+ metadata["effect.operation.nested"] = true;
740
+ metadata["effect.operation.root"] = false;
741
+ if (parentSpan.spanId) {
742
+ metadata["effect.parent.span.id"] = parentSpan.spanId;
743
+ }
744
+ if (parentSpan.name) {
745
+ metadata["effect.parent.span.name"] = parentSpan.name;
746
+ }
747
+ if (parentSpan.traceId) {
748
+ metadata["effect.parent.trace.id"] = parentSpan.traceId;
749
+ }
750
+ } else {
751
+ metadata["effect.operation.nested"] = false;
752
+ metadata["effect.operation.root"] = true;
753
+ }
754
+ return metadata;
755
+ });
598
756
  }
599
- function annotatePriority(_priority) {
757
+ function autoEnrichSpan() {
758
+ return effect.Effect.gen(function* () {
759
+ const metadata = yield* extractEffectMetadata();
760
+ yield* effect.Effect.annotateCurrentSpan(metadata);
761
+ });
600
762
  }
601
- function annotateCache(_operation, _hit) {
763
+ function withAutoEnrichedSpan(spanName, options) {
764
+ return (self) => {
765
+ return effect.Effect.gen(function* () {
766
+ yield* autoEnrichSpan();
767
+ return yield* self;
768
+ }).pipe(effect.Effect.withSpan(spanName, options));
769
+ };
602
770
  }
603
771
  var createLogicalParentLink = (parentSpan, useSpanLinks) => {
604
772
  if (!useSpanLinks) {
@@ -737,8 +905,11 @@ exports.annotatePriority = annotatePriority;
737
905
  exports.annotateQuery = annotateQuery;
738
906
  exports.annotateSpawnedTasks = annotateSpawnedTasks;
739
907
  exports.annotateUser = annotateUser;
908
+ exports.autoEnrichSpan = autoEnrichSpan;
740
909
  exports.createEffectInstrumentation = createEffectInstrumentation;
910
+ exports.extractEffectMetadata = extractEffectMetadata;
741
911
  exports.runIsolated = runIsolated;
742
912
  exports.runWithSpan = runWithSpan;
913
+ exports.withAutoEnrichedSpan = withAutoEnrichedSpan;
743
914
  //# sourceMappingURL=index.cjs.map
744
915
  //# sourceMappingURL=index.cjs.map