@atrim/instrument-node 0.7.2-dev.e12da4b.20260116190926 → 0.8.1-dev.ae570af.20260116211540
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.
- package/README.md +39 -0
- package/package.json +2 -2
- package/target/dist/integrations/effect/auto/index.cjs +65 -26
- package/target/dist/integrations/effect/auto/index.cjs.map +1 -1
- package/target/dist/integrations/effect/auto/index.d.cts +5 -3
- package/target/dist/integrations/effect/auto/index.d.ts +5 -3
- package/target/dist/integrations/effect/auto/index.js +64 -25
- package/target/dist/integrations/effect/auto/index.js.map +1 -1
package/README.md
CHANGED
|
@@ -80,6 +80,45 @@ const process = Effect.gen(function* () {
|
|
|
80
80
|
|
|
81
81
|
Available: `annotateUser`, `annotateBatch`, `annotateDataSize`, `annotateLLM`, `annotateQuery`, `annotateHttpRequest`, `annotateError`, `annotatePriority`, `annotateCache`
|
|
82
82
|
|
|
83
|
+
### Operation Tracing (Automatic)
|
|
84
|
+
|
|
85
|
+
Automatically trace `Effect.all`, `Effect.forEach`, and other operations without manual `Effect.withSpan()` calls:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { Effect } from 'effect'
|
|
89
|
+
import { withOperationTracing } from '@atrim/instrument-node/effect/auto'
|
|
90
|
+
|
|
91
|
+
const program = Effect.gen(function* () {
|
|
92
|
+
// Automatically creates span "effect.all (index.ts:42)" with item_count=3
|
|
93
|
+
yield* Effect.all([fetchUser(), fetchOrders(), fetchPrefs()])
|
|
94
|
+
|
|
95
|
+
// Automatically creates span "effect.forEach (index.ts:45)"
|
|
96
|
+
yield* Effect.forEach(items, processItem)
|
|
97
|
+
}).pipe(withOperationTracing)
|
|
98
|
+
|
|
99
|
+
await Effect.runPromise(program)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**What you get:**
|
|
103
|
+
- Span name with source location: `effect.all (index.ts:42)`
|
|
104
|
+
- Attributes: `effect.operation`, `effect.item_count`, `code.filepath`, `code.lineno`
|
|
105
|
+
- Zero code changes to existing Effect code
|
|
106
|
+
|
|
107
|
+
**Configuration (optional):**
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
effect:
|
|
111
|
+
operation_tracing:
|
|
112
|
+
enabled: true
|
|
113
|
+
operations:
|
|
114
|
+
- name: all
|
|
115
|
+
include_count: true
|
|
116
|
+
- name: forEach
|
|
117
|
+
include_count: true
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
> **Note:** Requires `@clayroach/effect` fork with OperationMeta support. See [examples/effect-op-tracing](../../examples/effect-op-tracing/) for a complete example.
|
|
121
|
+
|
|
83
122
|
### Effect Fiber Metadata Extraction
|
|
84
123
|
|
|
85
124
|
To add Effect fiber metadata (fiber ID, status, parent span info) to your spans, you must **explicitly call** the enrichment functions:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atrim/instrument-node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1-dev.ae570af.20260116211540",
|
|
4
4
|
"description": "OpenTelemetry instrumentation for Node.js with centralized YAML configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"tsx": "^4.7.0",
|
|
90
90
|
"typescript": "^5.7.2",
|
|
91
91
|
"vitest": "^4.0.16",
|
|
92
|
-
"@atrim/instrument-core": "0.
|
|
92
|
+
"@atrim/instrument-core": "0.7.0"
|
|
93
93
|
},
|
|
94
94
|
"peerDependencies": {
|
|
95
95
|
"@opentelemetry/api": "^1.0.0",
|
|
@@ -14,7 +14,7 @@ var yaml = require('yaml');
|
|
|
14
14
|
var zod = require('zod');
|
|
15
15
|
var fs = require('fs');
|
|
16
16
|
var path2 = require('path');
|
|
17
|
-
var
|
|
17
|
+
var TracerModule = require('effect/Tracer');
|
|
18
18
|
|
|
19
19
|
function _interopNamespace(e) {
|
|
20
20
|
if (e && e.__esModule) return e;
|
|
@@ -40,7 +40,7 @@ var HttpClientRequest__namespace = /*#__PURE__*/_interopNamespace(HttpClientRequ
|
|
|
40
40
|
var yaml__namespace = /*#__PURE__*/_interopNamespace(yaml);
|
|
41
41
|
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
42
42
|
var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
|
|
43
|
-
var
|
|
43
|
+
var TracerModule__namespace = /*#__PURE__*/_interopNamespace(TracerModule);
|
|
44
44
|
|
|
45
45
|
var __defProp = Object.defineProperty;
|
|
46
46
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -1573,6 +1573,8 @@ var SourceCaptureSupervisor = class extends effect.Supervisor.AbstractSupervisor
|
|
|
1573
1573
|
this.config = config;
|
|
1574
1574
|
// WeakMap to associate fibers with their OTel spans
|
|
1575
1575
|
__publicField(this, "fiberSpans", /* @__PURE__ */ new WeakMap());
|
|
1576
|
+
// WeakMap to associate fibers with their OTel contexts (for child fiber lookups)
|
|
1577
|
+
__publicField(this, "fiberContexts", /* @__PURE__ */ new WeakMap());
|
|
1576
1578
|
// WeakMap for fiber start times (for min_duration filtering)
|
|
1577
1579
|
__publicField(this, "fiberStartTimes", /* @__PURE__ */ new WeakMap());
|
|
1578
1580
|
// OpenTelemetry tracer - lazily initialized
|
|
@@ -1668,25 +1670,51 @@ var SourceCaptureSupervisor = class extends effect.Supervisor.AbstractSupervisor
|
|
|
1668
1670
|
}
|
|
1669
1671
|
let parentContext = OtelApi__namespace.ROOT_CONTEXT;
|
|
1670
1672
|
let parentFiberId;
|
|
1671
|
-
const
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
const
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1673
|
+
const inheritedOtelContext = effect.FiberRefs.getOrDefault(
|
|
1674
|
+
fiberRefsValue,
|
|
1675
|
+
TracerModule__namespace.currentOtelSpanContext
|
|
1676
|
+
);
|
|
1677
|
+
if (inheritedOtelContext) {
|
|
1678
|
+
parentContext = inheritedOtelContext;
|
|
1679
|
+
const inheritedSpan = OtelApi__namespace.trace.getSpan(inheritedOtelContext);
|
|
1680
|
+
if (inheritedSpan) {
|
|
1681
|
+
const spanCtx = inheritedSpan.spanContext();
|
|
1682
|
+
logger.log(
|
|
1683
|
+
`@atrim/source-capture: Using inherited OTel context - traceId=${spanCtx.traceId}, spanId=${spanCtx.spanId}`
|
|
1684
|
+
);
|
|
1685
|
+
}
|
|
1686
|
+
} else {
|
|
1687
|
+
const maybeEffectParentSpan = effect.Context.getOption(_context, effect.Tracer.ParentSpan);
|
|
1688
|
+
if (effect.Option.isSome(maybeEffectParentSpan)) {
|
|
1689
|
+
const effectSpan = maybeEffectParentSpan.value;
|
|
1690
|
+
logger.log(
|
|
1691
|
+
`@atrim/source-capture: Found ParentSpan - traceId=${effectSpan.traceId}, spanId=${effectSpan.spanId}`
|
|
1692
|
+
);
|
|
1693
|
+
const otelSpanContext = {
|
|
1694
|
+
traceId: effectSpan.traceId,
|
|
1695
|
+
spanId: effectSpan.spanId,
|
|
1696
|
+
traceFlags: effectSpan.sampled ? OtelApi__namespace.TraceFlags.SAMPLED : OtelApi__namespace.TraceFlags.NONE,
|
|
1697
|
+
isRemote: false
|
|
1698
|
+
};
|
|
1699
|
+
const wrappedSpan = OtelApi__namespace.trace.wrapSpanContext(otelSpanContext);
|
|
1700
|
+
parentContext = OtelApi__namespace.trace.setSpan(OtelApi__namespace.ROOT_CONTEXT, wrappedSpan);
|
|
1701
|
+
} else if (effect.Option.isSome(parent)) {
|
|
1702
|
+
parentFiberId = parent.value.id().id;
|
|
1703
|
+
const parentOtelContext = this.fiberContexts.get(parent.value);
|
|
1704
|
+
if (parentOtelContext) {
|
|
1705
|
+
parentContext = parentOtelContext;
|
|
1706
|
+
const parentSpan = OtelApi__namespace.trace.getSpan(parentOtelContext);
|
|
1707
|
+
if (parentSpan) {
|
|
1708
|
+
logger.log(
|
|
1709
|
+
`@atrim/source-capture: Using parent fiber's OTel context - traceId=${parentSpan.spanContext().traceId}`
|
|
1710
|
+
);
|
|
1711
|
+
}
|
|
1712
|
+
} else {
|
|
1713
|
+
const parentSpan = this.fiberSpans.get(parent.value);
|
|
1714
|
+
if (parentSpan) {
|
|
1715
|
+
parentContext = OtelApi__namespace.trace.setSpan(OtelApi__namespace.ROOT_CONTEXT, parentSpan);
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1690
1718
|
}
|
|
1691
1719
|
}
|
|
1692
1720
|
if (effect.Option.isSome(parent)) {
|
|
@@ -1715,7 +1743,9 @@ var SourceCaptureSupervisor = class extends effect.Supervisor.AbstractSupervisor
|
|
|
1715
1743
|
parentContext
|
|
1716
1744
|
);
|
|
1717
1745
|
logger.log(`@atrim/source-capture: Created span "${spanName}" for fiber ${fiberId}`);
|
|
1746
|
+
const newContext = OtelApi__namespace.trace.setSpan(parentContext, span);
|
|
1718
1747
|
this.fiberSpans.set(fiber, span);
|
|
1748
|
+
this.fiberContexts.set(fiber, newContext);
|
|
1719
1749
|
this.fiberStartTimes.set(fiber, process.hrtime.bigint());
|
|
1720
1750
|
this.activeFiberCount++;
|
|
1721
1751
|
}
|
|
@@ -1736,6 +1766,7 @@ var SourceCaptureSupervisor = class extends effect.Supervisor.AbstractSupervisor
|
|
|
1736
1766
|
const minDuration = this.parseMinDuration(this.config.performance?.min_duration);
|
|
1737
1767
|
if (minDuration > 0 && duration < minDuration) {
|
|
1738
1768
|
this.fiberSpans.delete(fiber);
|
|
1769
|
+
this.fiberContexts.delete(fiber);
|
|
1739
1770
|
this.fiberStartTimes.delete(fiber);
|
|
1740
1771
|
this.activeFiberCount--;
|
|
1741
1772
|
return;
|
|
@@ -1753,6 +1784,7 @@ var SourceCaptureSupervisor = class extends effect.Supervisor.AbstractSupervisor
|
|
|
1753
1784
|
span.end();
|
|
1754
1785
|
logger.log(`@atrim/source-capture: Ended span for fiber ${fiberId}`);
|
|
1755
1786
|
this.fiberSpans.delete(fiber);
|
|
1787
|
+
this.fiberContexts.delete(fiber);
|
|
1756
1788
|
this.fiberStartTimes.delete(fiber);
|
|
1757
1789
|
this.activeFiberCount--;
|
|
1758
1790
|
}
|
|
@@ -2010,7 +2042,7 @@ var OperationTracingSupervisor = class extends effect.Supervisor.AbstractSupervi
|
|
|
2010
2042
|
}
|
|
2011
2043
|
let parentContext = OtelApi__namespace.ROOT_CONTEXT;
|
|
2012
2044
|
const fiberContext = fiber.currentContext;
|
|
2013
|
-
const maybeEffectParentSpan = effect.Context.getOption(fiberContext,
|
|
2045
|
+
const maybeEffectParentSpan = effect.Context.getOption(fiberContext, TracerModule__namespace.ParentSpan);
|
|
2014
2046
|
if (effect.Option.isSome(maybeEffectParentSpan)) {
|
|
2015
2047
|
const effectSpan = maybeEffectParentSpan.value;
|
|
2016
2048
|
parentContext = OtelApi__namespace.trace.setSpan(
|
|
@@ -2088,8 +2120,8 @@ var defaultOperations = [
|
|
|
2088
2120
|
{ name: "all", includeCount: true, includeStack: true },
|
|
2089
2121
|
{ name: "forEach", includeCount: true, includeStack: true }
|
|
2090
2122
|
];
|
|
2091
|
-
var makeOperationTracingLayer = (operations = defaultOperations) => {
|
|
2092
|
-
const supervisor = new OperationTracingSupervisor(operations);
|
|
2123
|
+
var makeOperationTracingLayer = (operations = defaultOperations, spanNaming = defaultSpanNaming) => {
|
|
2124
|
+
const supervisor = new OperationTracingSupervisor(operations, spanNaming);
|
|
2093
2125
|
return effect.Supervisor.addSupervisor(supervisor);
|
|
2094
2126
|
};
|
|
2095
2127
|
var enableOpSupervision = (effect$1) => effect.Effect.withRuntimeFlagsPatch(effect$1, effect.RuntimeFlagsPatch.enable(effect.RuntimeFlags.OpSupervision));
|
|
@@ -2107,9 +2139,16 @@ var loadOperationTracingLayer = () => effect.Layer.unwrapEffect(
|
|
|
2107
2139
|
logger.log("@atrim/operation-tracing: Operation tracing disabled in config");
|
|
2108
2140
|
return effect.Layer.empty;
|
|
2109
2141
|
}
|
|
2142
|
+
const spanNaming = {
|
|
2143
|
+
includeLocation: opTracingConfig?.span_naming?.include_location ?? true,
|
|
2144
|
+
template: opTracingConfig?.span_naming?.template ?? "effect.{op} ({filename}:{line})"
|
|
2145
|
+
};
|
|
2146
|
+
logger.log(
|
|
2147
|
+
`@atrim/operation-tracing: Span naming - includeLocation=${spanNaming.includeLocation}, template="${spanNaming.template}"`
|
|
2148
|
+
);
|
|
2110
2149
|
const operations = opTracingConfig?.operations ? opTracingConfig.operations.map((op) => ({
|
|
2111
2150
|
name: op.name,
|
|
2112
|
-
...op.span_name && {
|
|
2151
|
+
...op.span_name && { spanNameTemplate: op.span_name },
|
|
2113
2152
|
includeCount: op.include_count ?? true,
|
|
2114
2153
|
includeStack: op.include_stack ?? true
|
|
2115
2154
|
})) : defaultOperations;
|
|
@@ -2117,7 +2156,7 @@ var loadOperationTracingLayer = () => effect.Layer.unwrapEffect(
|
|
|
2117
2156
|
logger.log(
|
|
2118
2157
|
`@atrim/operation-tracing: Loaded ${operations.length} operation configs from ${source}`
|
|
2119
2158
|
);
|
|
2120
|
-
return makeOperationTracingLayer(operations);
|
|
2159
|
+
return makeOperationTracingLayer(operations, spanNaming);
|
|
2121
2160
|
})
|
|
2122
2161
|
);
|
|
2123
2162
|
var OperationTracingLive = loadOperationTracingLayer();
|