@atrim/instrument-node 0.4.1 → 0.5.0-3a3dd2c-20251124202015

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,4 +1,4 @@
1
- import { Data, Context, Effect, Layer, FiberSet as FiberSet$1, Tracer } from 'effect';
1
+ import { Data, Context, Effect, Layer, FiberSet as FiberSet$1, Fiber, Option, FiberId, Tracer } from 'effect';
2
2
  import * as Otlp from '@effect/opentelemetry/Otlp';
3
3
  import { FetchHttpClient } from '@effect/platform';
4
4
  import { TraceFlags, trace, context } from '@opentelemetry/api';
@@ -10,6 +10,11 @@ import { z } from 'zod';
10
10
  import { NodeContext } from '@effect/platform-node';
11
11
 
12
12
  // src/integrations/effect/effect-tracer.ts
13
+
14
+ // ../../node_modules/.pnpm/@opentelemetry+semantic-conventions@1.38.0/node_modules/@opentelemetry/semantic-conventions/build/esm/stable_attributes.js
15
+ var ATTR_TELEMETRY_SDK_LANGUAGE = "telemetry.sdk.language";
16
+ var TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS = "nodejs";
17
+ var ATTR_TELEMETRY_SDK_NAME = "telemetry.sdk.name";
13
18
  var __defProp = Object.defineProperty;
14
19
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
15
20
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -40,13 +45,69 @@ var AutoIsolationConfigSchema = z.object({
40
45
  add_metadata: z.boolean().default(true)
41
46
  }).default({})
42
47
  });
48
+ var SpanNamingRuleSchema = z.object({
49
+ // Match conditions (all specified conditions must match)
50
+ match: z.object({
51
+ // Match by file path pattern (regex)
52
+ file: z.string().optional(),
53
+ // Match by function name pattern (regex)
54
+ function: z.string().optional(),
55
+ // Match by operator type (gen, all, forEach, etc.)
56
+ operator: z.string().optional(),
57
+ // Match by call stack pattern (regex)
58
+ stack: z.string().optional(),
59
+ // Match by fiber annotation key
60
+ annotation: z.string().optional()
61
+ }),
62
+ // Name template with substitution variables
63
+ // Available: {operator}, {function}, {module}, {file}, {line}, {class}, {match:N}
64
+ name: z.string()
65
+ });
66
+ var AutoTracingConfigSchema = z.object({
67
+ // Global enable/disable for auto-tracing
68
+ enabled: z.boolean().default(true),
69
+ // Span naming configuration
70
+ span_naming: z.object({
71
+ // Default name template when no rules match
72
+ default: z.string().default("effect.{operator}"),
73
+ // Custom naming rules (applied in order, first match wins)
74
+ rules: z.array(SpanNamingRuleSchema).default([])
75
+ }).default({}),
76
+ // Pattern filtering
77
+ filter_patterns: z.object({
78
+ // Only trace spans matching these patterns
79
+ include: z.array(z.string()).default([]),
80
+ // Exclude spans matching these patterns (takes precedence)
81
+ exclude: z.array(z.string()).default([])
82
+ }).default({}),
83
+ // Sampling configuration
84
+ sampling: z.object({
85
+ // Sampling rate (0.0 to 1.0)
86
+ rate: z.number().min(0).max(1).default(1),
87
+ // Only trace effects with duration > this value
88
+ min_duration: z.string().default("0 millis")
89
+ }).default({})
90
+ });
43
91
  var HttpFilteringConfigSchema = z.object({
44
92
  // Patterns to ignore for outgoing HTTP requests (string patterns only in YAML)
45
93
  ignore_outgoing_urls: z.array(z.string()).optional(),
46
94
  // Patterns to ignore for incoming HTTP requests (string patterns only in YAML)
47
95
  ignore_incoming_paths: z.array(z.string()).optional(),
48
96
  // Require parent span for outgoing requests (prevents root spans for HTTP calls)
49
- require_parent_for_outgoing_spans: z.boolean().optional()
97
+ require_parent_for_outgoing_spans: z.boolean().optional(),
98
+ // Trace context propagation configuration
99
+ // Controls which cross-origin requests receive W3C Trace Context headers (traceparent, tracestate)
100
+ propagate_trace_context: z.object({
101
+ // Strategy for trace propagation
102
+ // - "all": Propagate to all cross-origin requests (may cause CORS errors)
103
+ // - "none": Never propagate trace headers
104
+ // - "same-origin": Only propagate to same-origin requests (default, safe)
105
+ // - "patterns": Propagate based on include_urls patterns
106
+ strategy: z.enum(["all", "none", "same-origin", "patterns"]).default("same-origin"),
107
+ // URL patterns to include when strategy is "patterns"
108
+ // Supports regex patterns (e.g., "^https://api\\.myapp\\.com")
109
+ include_urls: z.array(z.string()).optional()
110
+ }).optional()
50
111
  });
51
112
  var InstrumentationConfigSchema = z.object({
52
113
  version: z.string(),
@@ -59,7 +120,8 @@ var InstrumentationConfigSchema = z.object({
59
120
  }),
60
121
  effect: z.object({
61
122
  auto_extract_metadata: z.boolean(),
62
- auto_isolation: AutoIsolationConfigSchema.optional()
123
+ auto_isolation: AutoIsolationConfigSchema.optional(),
124
+ auto_tracing: AutoTracingConfigSchema.optional()
63
125
  }).optional(),
64
126
  http: HttpFilteringConfigSchema.optional()
65
127
  });
@@ -465,6 +527,7 @@ async function loadConfigWithOptions(options = {}) {
465
527
  }
466
528
 
467
529
  // src/integrations/effect/effect-tracer.ts
530
+ var SDK_NAME = "@effect/opentelemetry-otlp";
468
531
  function createEffectInstrumentation(options = {}) {
469
532
  return Layer.unwrapEffect(
470
533
  Effect.gen(function* () {
@@ -498,7 +561,9 @@ function createEffectInstrumentation(options = {}) {
498
561
  attributes: {
499
562
  "platform.component": "effect",
500
563
  "effect.auto_metadata": autoExtractMetadata,
501
- "effect.context_propagation": continueExistingTraces
564
+ "effect.context_propagation": continueExistingTraces,
565
+ [ATTR_TELEMETRY_SDK_LANGUAGE]: TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
566
+ [ATTR_TELEMETRY_SDK_NAME]: SDK_NAME
502
567
  }
503
568
  },
504
569
  // Bridge Effect context to OpenTelemetry global context
@@ -537,7 +602,9 @@ var EffectInstrumentationLive = Effect.sync(() => {
537
602
  serviceName,
538
603
  serviceVersion,
539
604
  attributes: {
540
- "platform.component": "effect"
605
+ "platform.component": "effect",
606
+ [ATTR_TELEMETRY_SDK_LANGUAGE]: TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
607
+ [ATTR_TELEMETRY_SDK_NAME]: SDK_NAME
541
608
  }
542
609
  },
543
610
  // CRITICAL: Bridge Effect context to OpenTelemetry global context
@@ -556,25 +623,144 @@ var EffectInstrumentationLive = Effect.sync(() => {
556
623
  }
557
624
  }).pipe(Layer.provide(FetchHttpClient.layer));
558
625
  }).pipe(Layer.unwrapEffect);
559
-
560
- // src/integrations/effect/effect-helpers.ts
561
- function annotateUser(_userId, _email) {
626
+ function annotateUser(userId, email, username) {
627
+ const attributes = {
628
+ "user.id": userId
629
+ };
630
+ if (email) attributes["user.email"] = email;
631
+ if (username) attributes["user.name"] = username;
632
+ return Effect.annotateCurrentSpan(attributes);
562
633
  }
563
- function annotateDataSize(_bytes, _count) {
634
+ function annotateDataSize(bytes, items, compressionRatio) {
635
+ const attributes = {
636
+ "data.size.bytes": bytes,
637
+ "data.size.items": items
638
+ };
639
+ if (compressionRatio !== void 0) {
640
+ attributes["data.compression.ratio"] = compressionRatio;
641
+ }
642
+ return Effect.annotateCurrentSpan(attributes);
564
643
  }
565
- function annotateBatch(_size, _batchSize) {
644
+ function annotateBatch(totalItems, batchSize, successCount, failureCount) {
645
+ const attributes = {
646
+ "batch.size": batchSize,
647
+ "batch.total_items": totalItems,
648
+ "batch.count": Math.ceil(totalItems / batchSize)
649
+ };
650
+ if (successCount !== void 0) {
651
+ attributes["batch.success_count"] = successCount;
652
+ }
653
+ if (failureCount !== void 0) {
654
+ attributes["batch.failure_count"] = failureCount;
655
+ }
656
+ return Effect.annotateCurrentSpan(attributes);
566
657
  }
567
- function annotateLLM(_model, _operation, _inputTokens, _outputTokens) {
658
+ function annotateLLM(model, provider, tokens) {
659
+ const attributes = {
660
+ "llm.model": model,
661
+ "llm.provider": provider
662
+ };
663
+ if (tokens) {
664
+ if (tokens.prompt !== void 0) attributes["llm.tokens.prompt"] = tokens.prompt;
665
+ if (tokens.completion !== void 0) attributes["llm.tokens.completion"] = tokens.completion;
666
+ if (tokens.total !== void 0) attributes["llm.tokens.total"] = tokens.total;
667
+ }
668
+ return Effect.annotateCurrentSpan(attributes);
568
669
  }
569
- function annotateQuery(_query, _database) {
670
+ function annotateQuery(query, duration, rowCount, database) {
671
+ const attributes = {
672
+ "db.statement": query.length > 1e3 ? query.substring(0, 1e3) + "..." : query
673
+ };
674
+ if (duration !== void 0) attributes["db.duration.ms"] = duration;
675
+ if (rowCount !== void 0) attributes["db.row_count"] = rowCount;
676
+ if (database) attributes["db.name"] = database;
677
+ return Effect.annotateCurrentSpan(attributes);
570
678
  }
571
- function annotateHttpRequest(_method, _url, _statusCode) {
679
+ function annotateHttpRequest(method, url, statusCode, contentLength) {
680
+ const attributes = {
681
+ "http.method": method,
682
+ "http.url": url
683
+ };
684
+ if (statusCode !== void 0) attributes["http.status_code"] = statusCode;
685
+ if (contentLength !== void 0) attributes["http.response.content_length"] = contentLength;
686
+ return Effect.annotateCurrentSpan(attributes);
572
687
  }
573
- function annotateError(_error, _context) {
688
+ function annotateError(error, recoverable, errorType) {
689
+ const errorMessage = typeof error === "string" ? error : error.message;
690
+ const errorStack = typeof error === "string" ? void 0 : error.stack;
691
+ const attributes = {
692
+ "error.message": errorMessage,
693
+ "error.recoverable": recoverable
694
+ };
695
+ if (errorType) attributes["error.type"] = errorType;
696
+ if (errorStack) attributes["error.stack"] = errorStack;
697
+ return Effect.annotateCurrentSpan(attributes);
574
698
  }
575
- function annotatePriority(_priority) {
699
+ function annotatePriority(priority, reason) {
700
+ const attributes = {
701
+ "operation.priority": priority
702
+ };
703
+ if (reason) attributes["operation.priority.reason"] = reason;
704
+ return Effect.annotateCurrentSpan(attributes);
705
+ }
706
+ function annotateCache(hit, key, ttl) {
707
+ const attributes = {
708
+ "cache.hit": hit,
709
+ "cache.key": key
710
+ };
711
+ if (ttl !== void 0) attributes["cache.ttl.seconds"] = ttl;
712
+ return Effect.annotateCurrentSpan(attributes);
713
+ }
714
+ function extractEffectMetadata() {
715
+ return Effect.gen(function* () {
716
+ const metadata = {};
717
+ const currentFiber = Fiber.getCurrentFiber();
718
+ if (Option.isSome(currentFiber)) {
719
+ const fiber = currentFiber.value;
720
+ const fiberId = fiber.id();
721
+ metadata["effect.fiber.id"] = FiberId.threadName(fiberId);
722
+ const status = yield* Fiber.status(fiber);
723
+ if (status._tag) {
724
+ metadata["effect.fiber.status"] = status._tag;
725
+ }
726
+ }
727
+ const parentSpanResult = yield* Effect.currentSpan.pipe(
728
+ Effect.option
729
+ // Convert NoSuchElementException to Option
730
+ );
731
+ if (Option.isSome(parentSpanResult)) {
732
+ const parentSpan = parentSpanResult.value;
733
+ metadata["effect.operation.nested"] = true;
734
+ metadata["effect.operation.root"] = false;
735
+ if (parentSpan.spanId) {
736
+ metadata["effect.parent.span.id"] = parentSpan.spanId;
737
+ }
738
+ if (parentSpan.name) {
739
+ metadata["effect.parent.span.name"] = parentSpan.name;
740
+ }
741
+ if (parentSpan.traceId) {
742
+ metadata["effect.parent.trace.id"] = parentSpan.traceId;
743
+ }
744
+ } else {
745
+ metadata["effect.operation.nested"] = false;
746
+ metadata["effect.operation.root"] = true;
747
+ }
748
+ return metadata;
749
+ });
576
750
  }
577
- function annotateCache(_operation, _hit) {
751
+ function autoEnrichSpan() {
752
+ return Effect.gen(function* () {
753
+ const metadata = yield* extractEffectMetadata();
754
+ yield* Effect.annotateCurrentSpan(metadata);
755
+ });
756
+ }
757
+ function withAutoEnrichedSpan(spanName, options) {
758
+ return (self) => {
759
+ return Effect.gen(function* () {
760
+ yield* autoEnrichSpan();
761
+ return yield* self;
762
+ }).pipe(Effect.withSpan(spanName, options));
763
+ };
578
764
  }
579
765
  var createLogicalParentLink = (parentSpan, useSpanLinks) => {
580
766
  if (!useSpanLinks) {
@@ -701,6 +887,6 @@ var FiberSet = {
701
887
  runWithSpan
702
888
  };
703
889
 
704
- export { EffectInstrumentationLive, FiberSet, annotateBatch, annotateCache, annotateDataSize, annotateError, annotateHttpRequest, annotateLLM, annotatePriority, annotateQuery, annotateSpawnedTasks, annotateUser, createEffectInstrumentation, runIsolated, runWithSpan };
890
+ export { EffectInstrumentationLive, FiberSet, annotateBatch, annotateCache, annotateDataSize, annotateError, annotateHttpRequest, annotateLLM, annotatePriority, annotateQuery, annotateSpawnedTasks, annotateUser, autoEnrichSpan, createEffectInstrumentation, extractEffectMetadata, runIsolated, runWithSpan, withAutoEnrichedSpan };
705
891
  //# sourceMappingURL=index.js.map
706
892
  //# sourceMappingURL=index.js.map