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