@atrim/instrument-node 0.4.0 → 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.
- package/README.md +66 -0
- package/package.json +13 -7
- package/target/dist/index.cjs +310 -197
- package/target/dist/index.cjs.map +1 -1
- package/target/dist/index.d.cts +57 -3
- package/target/dist/index.d.ts +57 -3
- package/target/dist/index.js +288 -199
- package/target/dist/index.js.map +1 -1
- package/target/dist/integrations/effect/auto/index.cjs +276 -0
- package/target/dist/integrations/effect/auto/index.cjs.map +1 -0
- package/target/dist/integrations/effect/auto/index.d.cts +1513 -0
- package/target/dist/integrations/effect/auto/index.d.ts +1513 -0
- package/target/dist/integrations/effect/auto/index.js +264 -0
- package/target/dist/integrations/effect/auto/index.js.map +1 -0
- package/target/dist/integrations/effect/index.cjs +424 -206
- package/target/dist/integrations/effect/index.cjs.map +1 -1
- package/target/dist/integrations/effect/index.d.cts +204 -13
- package/target/dist/integrations/effect/index.d.ts +204 -13
- package/target/dist/integrations/effect/index.js +421 -208
- package/target/dist/integrations/effect/index.js.map +1 -1
|
@@ -4,10 +4,12 @@ var effect = require('effect');
|
|
|
4
4
|
var Otlp = require('@effect/opentelemetry/Otlp');
|
|
5
5
|
var platform = require('@effect/platform');
|
|
6
6
|
var api = require('@opentelemetry/api');
|
|
7
|
-
var
|
|
8
|
-
var
|
|
7
|
+
var FileSystem = require('@effect/platform/FileSystem');
|
|
8
|
+
var HttpClient = require('@effect/platform/HttpClient');
|
|
9
|
+
var HttpClientRequest = require('@effect/platform/HttpClientRequest');
|
|
9
10
|
var yaml = require('yaml');
|
|
10
11
|
var zod = require('zod');
|
|
12
|
+
var platformNode = require('@effect/platform-node');
|
|
11
13
|
|
|
12
14
|
function _interopNamespace(e) {
|
|
13
15
|
if (e && e.__esModule) return e;
|
|
@@ -28,8 +30,15 @@ function _interopNamespace(e) {
|
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
var Otlp__namespace = /*#__PURE__*/_interopNamespace(Otlp);
|
|
33
|
+
var HttpClient__namespace = /*#__PURE__*/_interopNamespace(HttpClient);
|
|
34
|
+
var HttpClientRequest__namespace = /*#__PURE__*/_interopNamespace(HttpClientRequest);
|
|
31
35
|
|
|
32
36
|
// src/integrations/effect/effect-tracer.ts
|
|
37
|
+
|
|
38
|
+
// ../../node_modules/.pnpm/@opentelemetry+semantic-conventions@1.38.0/node_modules/@opentelemetry/semantic-conventions/build/esm/stable_attributes.js
|
|
39
|
+
var ATTR_TELEMETRY_SDK_LANGUAGE = "telemetry.sdk.language";
|
|
40
|
+
var TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS = "nodejs";
|
|
41
|
+
var ATTR_TELEMETRY_SDK_NAME = "telemetry.sdk.name";
|
|
33
42
|
var __defProp = Object.defineProperty;
|
|
34
43
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
35
44
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -60,13 +69,69 @@ var AutoIsolationConfigSchema = zod.z.object({
|
|
|
60
69
|
add_metadata: zod.z.boolean().default(true)
|
|
61
70
|
}).default({})
|
|
62
71
|
});
|
|
72
|
+
var SpanNamingRuleSchema = zod.z.object({
|
|
73
|
+
// Match conditions (all specified conditions must match)
|
|
74
|
+
match: zod.z.object({
|
|
75
|
+
// Match by file path pattern (regex)
|
|
76
|
+
file: zod.z.string().optional(),
|
|
77
|
+
// Match by function name pattern (regex)
|
|
78
|
+
function: zod.z.string().optional(),
|
|
79
|
+
// Match by operator type (gen, all, forEach, etc.)
|
|
80
|
+
operator: zod.z.string().optional(),
|
|
81
|
+
// Match by call stack pattern (regex)
|
|
82
|
+
stack: zod.z.string().optional(),
|
|
83
|
+
// Match by fiber annotation key
|
|
84
|
+
annotation: zod.z.string().optional()
|
|
85
|
+
}),
|
|
86
|
+
// Name template with substitution variables
|
|
87
|
+
// Available: {operator}, {function}, {module}, {file}, {line}, {class}, {match:N}
|
|
88
|
+
name: zod.z.string()
|
|
89
|
+
});
|
|
90
|
+
var AutoTracingConfigSchema = zod.z.object({
|
|
91
|
+
// Global enable/disable for auto-tracing
|
|
92
|
+
enabled: zod.z.boolean().default(true),
|
|
93
|
+
// Span naming configuration
|
|
94
|
+
span_naming: zod.z.object({
|
|
95
|
+
// Default name template when no rules match
|
|
96
|
+
default: zod.z.string().default("effect.{operator}"),
|
|
97
|
+
// Custom naming rules (applied in order, first match wins)
|
|
98
|
+
rules: zod.z.array(SpanNamingRuleSchema).default([])
|
|
99
|
+
}).default({}),
|
|
100
|
+
// Pattern filtering
|
|
101
|
+
filter_patterns: zod.z.object({
|
|
102
|
+
// Only trace spans matching these patterns
|
|
103
|
+
include: zod.z.array(zod.z.string()).default([]),
|
|
104
|
+
// Exclude spans matching these patterns (takes precedence)
|
|
105
|
+
exclude: zod.z.array(zod.z.string()).default([])
|
|
106
|
+
}).default({}),
|
|
107
|
+
// Sampling configuration
|
|
108
|
+
sampling: zod.z.object({
|
|
109
|
+
// Sampling rate (0.0 to 1.0)
|
|
110
|
+
rate: zod.z.number().min(0).max(1).default(1),
|
|
111
|
+
// Only trace effects with duration > this value
|
|
112
|
+
min_duration: zod.z.string().default("0 millis")
|
|
113
|
+
}).default({})
|
|
114
|
+
});
|
|
63
115
|
var HttpFilteringConfigSchema = zod.z.object({
|
|
64
116
|
// Patterns to ignore for outgoing HTTP requests (string patterns only in YAML)
|
|
65
117
|
ignore_outgoing_urls: zod.z.array(zod.z.string()).optional(),
|
|
66
118
|
// Patterns to ignore for incoming HTTP requests (string patterns only in YAML)
|
|
67
119
|
ignore_incoming_paths: zod.z.array(zod.z.string()).optional(),
|
|
68
120
|
// Require parent span for outgoing requests (prevents root spans for HTTP calls)
|
|
69
|
-
require_parent_for_outgoing_spans: zod.z.boolean().optional()
|
|
121
|
+
require_parent_for_outgoing_spans: zod.z.boolean().optional(),
|
|
122
|
+
// Trace context propagation configuration
|
|
123
|
+
// Controls which cross-origin requests receive W3C Trace Context headers (traceparent, tracestate)
|
|
124
|
+
propagate_trace_context: zod.z.object({
|
|
125
|
+
// Strategy for trace propagation
|
|
126
|
+
// - "all": Propagate to all cross-origin requests (may cause CORS errors)
|
|
127
|
+
// - "none": Never propagate trace headers
|
|
128
|
+
// - "same-origin": Only propagate to same-origin requests (default, safe)
|
|
129
|
+
// - "patterns": Propagate based on include_urls patterns
|
|
130
|
+
strategy: zod.z.enum(["all", "none", "same-origin", "patterns"]).default("same-origin"),
|
|
131
|
+
// URL patterns to include when strategy is "patterns"
|
|
132
|
+
// Supports regex patterns (e.g., "^https://api\\.myapp\\.com")
|
|
133
|
+
include_urls: zod.z.array(zod.z.string()).optional()
|
|
134
|
+
}).optional()
|
|
70
135
|
});
|
|
71
136
|
var InstrumentationConfigSchema = zod.z.object({
|
|
72
137
|
version: zod.z.string(),
|
|
@@ -79,238 +144,189 @@ var InstrumentationConfigSchema = zod.z.object({
|
|
|
79
144
|
}),
|
|
80
145
|
effect: zod.z.object({
|
|
81
146
|
auto_extract_metadata: zod.z.boolean(),
|
|
82
|
-
auto_isolation: AutoIsolationConfigSchema.optional()
|
|
147
|
+
auto_isolation: AutoIsolationConfigSchema.optional(),
|
|
148
|
+
auto_tracing: AutoTracingConfigSchema.optional()
|
|
83
149
|
}).optional(),
|
|
84
150
|
http: HttpFilteringConfigSchema.optional()
|
|
85
151
|
});
|
|
86
152
|
(class extends effect.Data.TaggedError("ConfigError") {
|
|
153
|
+
get message() {
|
|
154
|
+
return this.reason;
|
|
155
|
+
}
|
|
87
156
|
});
|
|
88
157
|
var ConfigUrlError = class extends effect.Data.TaggedError("ConfigUrlError") {
|
|
158
|
+
get message() {
|
|
159
|
+
return this.reason;
|
|
160
|
+
}
|
|
89
161
|
};
|
|
90
162
|
var ConfigValidationError = class extends effect.Data.TaggedError("ConfigValidationError") {
|
|
163
|
+
get message() {
|
|
164
|
+
return this.reason;
|
|
165
|
+
}
|
|
91
166
|
};
|
|
92
167
|
var ConfigFileError = class extends effect.Data.TaggedError("ConfigFileError") {
|
|
168
|
+
get message() {
|
|
169
|
+
return this.reason;
|
|
170
|
+
}
|
|
93
171
|
};
|
|
94
172
|
(class extends effect.Data.TaggedError("ServiceDetectionError") {
|
|
173
|
+
get message() {
|
|
174
|
+
return this.reason;
|
|
175
|
+
}
|
|
95
176
|
});
|
|
96
177
|
(class extends effect.Data.TaggedError("InitializationError") {
|
|
178
|
+
get message() {
|
|
179
|
+
return this.reason;
|
|
180
|
+
}
|
|
97
181
|
});
|
|
98
182
|
(class extends effect.Data.TaggedError("ExportError") {
|
|
183
|
+
get message() {
|
|
184
|
+
return this.reason;
|
|
185
|
+
}
|
|
99
186
|
});
|
|
100
187
|
(class extends effect.Data.TaggedError("ShutdownError") {
|
|
188
|
+
get message() {
|
|
189
|
+
return this.reason;
|
|
190
|
+
}
|
|
101
191
|
});
|
|
102
192
|
var SECURITY_DEFAULTS = {
|
|
103
193
|
maxConfigSize: 1e6,
|
|
104
194
|
// 1MB
|
|
105
|
-
requestTimeout: 5e3
|
|
106
|
-
|
|
107
|
-
// Only HTTPS for remote configs
|
|
108
|
-
cacheTimeout: 3e5
|
|
109
|
-
// 5 minutes
|
|
195
|
+
requestTimeout: 5e3
|
|
196
|
+
// 5 seconds
|
|
110
197
|
};
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
126
|
-
{ pattern: "^health\\.", description: "Health checks" }
|
|
127
|
-
]
|
|
128
|
-
},
|
|
129
|
-
effect: {
|
|
130
|
-
auto_extract_metadata: true
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
var validateConfigEffect = (rawConfig) => effect.Effect.try({
|
|
135
|
-
try: () => InstrumentationConfigSchema.parse(rawConfig),
|
|
136
|
-
catch: (error) => new ConfigValidationError({
|
|
137
|
-
reason: "Invalid configuration schema",
|
|
138
|
-
cause: error
|
|
139
|
-
})
|
|
140
|
-
});
|
|
141
|
-
var loadConfigFromFileEffect = (filePath) => effect.Effect.gen(function* () {
|
|
142
|
-
const fileContents = yield* effect.Effect.try({
|
|
143
|
-
try: () => fs.readFileSync(filePath, "utf8"),
|
|
144
|
-
catch: (error) => new ConfigFileError({
|
|
145
|
-
reason: `Failed to read config file at ${filePath}`,
|
|
198
|
+
var ConfigLoader = class extends effect.Context.Tag("ConfigLoader")() {
|
|
199
|
+
};
|
|
200
|
+
var parseYamlContent = (content, uri) => effect.Effect.gen(function* () {
|
|
201
|
+
const parsed = yield* effect.Effect.try({
|
|
202
|
+
try: () => yaml.parse(content),
|
|
203
|
+
catch: (error) => new ConfigValidationError({
|
|
204
|
+
reason: uri ? `Failed to parse YAML from ${uri}` : "Failed to parse YAML",
|
|
205
|
+
cause: error
|
|
206
|
+
})
|
|
207
|
+
});
|
|
208
|
+
return yield* effect.Effect.try({
|
|
209
|
+
try: () => InstrumentationConfigSchema.parse(parsed),
|
|
210
|
+
catch: (error) => new ConfigValidationError({
|
|
211
|
+
reason: uri ? `Invalid configuration schema from ${uri}` : "Invalid configuration schema",
|
|
146
212
|
cause: error
|
|
147
213
|
})
|
|
148
214
|
});
|
|
149
|
-
|
|
215
|
+
});
|
|
216
|
+
var loadFromFileWithFs = (fs, path, uri) => effect.Effect.gen(function* () {
|
|
217
|
+
const content = yield* fs.readFileString(path).pipe(
|
|
218
|
+
effect.Effect.mapError(
|
|
219
|
+
(error) => new ConfigFileError({
|
|
220
|
+
reason: `Failed to read config file at ${uri}`,
|
|
221
|
+
cause: error
|
|
222
|
+
})
|
|
223
|
+
)
|
|
224
|
+
);
|
|
225
|
+
if (content.length > SECURITY_DEFAULTS.maxConfigSize) {
|
|
150
226
|
return yield* effect.Effect.fail(
|
|
151
227
|
new ConfigFileError({
|
|
152
228
|
reason: `Config file exceeds maximum size of ${SECURITY_DEFAULTS.maxConfigSize} bytes`
|
|
153
229
|
})
|
|
154
230
|
);
|
|
155
231
|
}
|
|
156
|
-
|
|
157
|
-
try {
|
|
158
|
-
rawConfig = yaml.parse(fileContents);
|
|
159
|
-
} catch (error) {
|
|
160
|
-
return yield* effect.Effect.fail(
|
|
161
|
-
new ConfigValidationError({
|
|
162
|
-
reason: "Invalid YAML syntax",
|
|
163
|
-
cause: error
|
|
164
|
-
})
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
return yield* validateConfigEffect(rawConfig);
|
|
232
|
+
return yield* parseYamlContent(content, uri);
|
|
168
233
|
});
|
|
169
|
-
var
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
234
|
+
var loadFromHttpWithClient = (client, url) => effect.Effect.scoped(
|
|
235
|
+
effect.Effect.gen(function* () {
|
|
236
|
+
if (url.startsWith("http://")) {
|
|
237
|
+
return yield* effect.Effect.fail(
|
|
238
|
+
new ConfigUrlError({
|
|
239
|
+
reason: "Insecure protocol: only HTTPS URLs are allowed"
|
|
240
|
+
})
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
const request = HttpClientRequest__namespace.get(url).pipe(
|
|
244
|
+
HttpClientRequest__namespace.setHeaders({
|
|
245
|
+
Accept: "application/yaml, text/yaml, application/x-yaml"
|
|
178
246
|
})
|
|
179
247
|
);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
248
|
+
const response = yield* client.execute(request).pipe(
|
|
249
|
+
effect.Effect.timeout(`${SECURITY_DEFAULTS.requestTimeout} millis`),
|
|
250
|
+
effect.Effect.mapError((error) => {
|
|
251
|
+
if (error._tag === "TimeoutException") {
|
|
252
|
+
return new ConfigUrlError({
|
|
253
|
+
reason: `Config fetch timeout after ${SECURITY_DEFAULTS.requestTimeout}ms from ${url}`
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
return new ConfigUrlError({
|
|
257
|
+
reason: `Failed to load config from URL: ${url}`,
|
|
258
|
+
cause: error
|
|
259
|
+
});
|
|
185
260
|
})
|
|
186
261
|
);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
262
|
+
if (response.status >= 400) {
|
|
263
|
+
return yield* effect.Effect.fail(
|
|
264
|
+
new ConfigUrlError({
|
|
265
|
+
reason: `HTTP ${response.status} from ${url}`
|
|
266
|
+
})
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
const text = yield* response.text.pipe(
|
|
270
|
+
effect.Effect.mapError(
|
|
271
|
+
(error) => new ConfigUrlError({
|
|
272
|
+
reason: `Failed to read response body from ${url}`,
|
|
273
|
+
cause: error
|
|
274
|
+
})
|
|
275
|
+
)
|
|
276
|
+
);
|
|
277
|
+
if (text.length > SECURITY_DEFAULTS.maxConfigSize) {
|
|
278
|
+
return yield* effect.Effect.fail(
|
|
279
|
+
new ConfigUrlError({
|
|
280
|
+
reason: `Config exceeds maximum size of ${SECURITY_DEFAULTS.maxConfigSize} bytes`
|
|
281
|
+
})
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
return yield* parseYamlContent(text, url);
|
|
285
|
+
})
|
|
286
|
+
);
|
|
287
|
+
var makeConfigLoader = effect.Effect.gen(function* () {
|
|
288
|
+
const fs = yield* effect.Effect.serviceOption(FileSystem.FileSystem);
|
|
289
|
+
const http = yield* HttpClient__namespace.HttpClient;
|
|
290
|
+
const loadFromUriUncached = (uri) => effect.Effect.gen(function* () {
|
|
291
|
+
if (uri.startsWith("file://")) {
|
|
292
|
+
const path = uri.slice(7);
|
|
293
|
+
if (fs._tag === "None") {
|
|
294
|
+
return yield* effect.Effect.fail(
|
|
295
|
+
new ConfigFileError({
|
|
296
|
+
reason: "FileSystem not available (browser environment?)",
|
|
297
|
+
cause: { uri }
|
|
210
298
|
})
|
|
211
299
|
);
|
|
212
300
|
}
|
|
213
|
-
return
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
301
|
+
return yield* loadFromFileWithFs(fs.value, path, uri);
|
|
302
|
+
}
|
|
303
|
+
if (uri.startsWith("http://") || uri.startsWith("https://")) {
|
|
304
|
+
return yield* loadFromHttpWithClient(http, uri);
|
|
305
|
+
}
|
|
306
|
+
if (fs._tag === "Some") {
|
|
307
|
+
return yield* loadFromFileWithFs(fs.value, uri, uri);
|
|
308
|
+
} else {
|
|
309
|
+
return yield* loadFromHttpWithClient(http, uri);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
const loadFromUriCached = yield* effect.Effect.cachedFunction(loadFromUriUncached);
|
|
313
|
+
return ConfigLoader.of({
|
|
314
|
+
loadFromUri: loadFromUriCached,
|
|
315
|
+
loadFromInline: (content) => effect.Effect.gen(function* () {
|
|
316
|
+
if (typeof content === "string") {
|
|
317
|
+
return yield* parseYamlContent(content);
|
|
318
|
+
}
|
|
319
|
+
return yield* effect.Effect.try({
|
|
320
|
+
try: () => InstrumentationConfigSchema.parse(content),
|
|
321
|
+
catch: (error) => new ConfigValidationError({
|
|
322
|
+
reason: "Invalid configuration schema",
|
|
323
|
+
cause: error
|
|
324
|
+
})
|
|
325
|
+
});
|
|
236
326
|
})
|
|
237
327
|
});
|
|
238
|
-
if (text.length > SECURITY_DEFAULTS.maxConfigSize) {
|
|
239
|
-
return yield* effect.Effect.fail(
|
|
240
|
-
new ConfigUrlError({
|
|
241
|
-
reason: `Config exceeds maximum size of ${SECURITY_DEFAULTS.maxConfigSize} bytes`
|
|
242
|
-
})
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
let rawConfig;
|
|
246
|
-
try {
|
|
247
|
-
rawConfig = yaml.parse(text);
|
|
248
|
-
} catch (error) {
|
|
249
|
-
return yield* effect.Effect.fail(
|
|
250
|
-
new ConfigValidationError({
|
|
251
|
-
reason: "Invalid YAML syntax",
|
|
252
|
-
cause: error
|
|
253
|
-
})
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
return yield* validateConfigEffect(rawConfig);
|
|
257
|
-
});
|
|
258
|
-
var makeConfigCache = () => effect.Cache.make({
|
|
259
|
-
capacity: 100,
|
|
260
|
-
timeToLive: effect.Duration.minutes(5),
|
|
261
|
-
lookup: (url) => fetchAndParseConfig(url)
|
|
262
328
|
});
|
|
263
|
-
var
|
|
264
|
-
var getCache = effect.Effect.gen(function* () {
|
|
265
|
-
if (!cacheInstance) {
|
|
266
|
-
cacheInstance = yield* makeConfigCache();
|
|
267
|
-
}
|
|
268
|
-
return cacheInstance;
|
|
269
|
-
});
|
|
270
|
-
var loadConfigFromUrlEffect = (url, cacheTimeout = SECURITY_DEFAULTS.cacheTimeout) => effect.Effect.gen(function* () {
|
|
271
|
-
if (cacheTimeout === 0) {
|
|
272
|
-
return yield* fetchAndParseConfig(url);
|
|
273
|
-
}
|
|
274
|
-
const cache = yield* getCache;
|
|
275
|
-
return yield* cache.get(url);
|
|
276
|
-
});
|
|
277
|
-
var loadConfigEffect = (options = {}) => effect.Effect.gen(function* () {
|
|
278
|
-
if (options.config) {
|
|
279
|
-
return yield* validateConfigEffect(options.config);
|
|
280
|
-
}
|
|
281
|
-
const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
|
|
282
|
-
if (envConfigPath) {
|
|
283
|
-
if (envConfigPath.startsWith("http://") || envConfigPath.startsWith("https://")) {
|
|
284
|
-
return yield* loadConfigFromUrlEffect(envConfigPath, options.cacheTimeout);
|
|
285
|
-
}
|
|
286
|
-
return yield* loadConfigFromFileEffect(envConfigPath);
|
|
287
|
-
}
|
|
288
|
-
if (options.configUrl) {
|
|
289
|
-
return yield* loadConfigFromUrlEffect(options.configUrl, options.cacheTimeout);
|
|
290
|
-
}
|
|
291
|
-
if (options.configPath) {
|
|
292
|
-
return yield* loadConfigFromFileEffect(options.configPath);
|
|
293
|
-
}
|
|
294
|
-
const defaultPath = path.join(process.cwd(), "instrumentation.yaml");
|
|
295
|
-
const exists = yield* effect.Effect.sync(() => fs.existsSync(defaultPath));
|
|
296
|
-
if (exists) {
|
|
297
|
-
return yield* loadConfigFromFileEffect(defaultPath);
|
|
298
|
-
}
|
|
299
|
-
return getDefaultConfig();
|
|
300
|
-
});
|
|
301
|
-
async function loadConfig(options = {}) {
|
|
302
|
-
return effect.Effect.runPromise(
|
|
303
|
-
loadConfigEffect(options).pipe(
|
|
304
|
-
// Convert typed errors to regular Error with reason message for backward compatibility
|
|
305
|
-
effect.Effect.mapError((error) => {
|
|
306
|
-
const message = error.reason;
|
|
307
|
-
const newError = new Error(message);
|
|
308
|
-
newError.cause = error.cause;
|
|
309
|
-
return newError;
|
|
310
|
-
})
|
|
311
|
-
)
|
|
312
|
-
);
|
|
313
|
-
}
|
|
329
|
+
var ConfigLoaderLive = effect.Layer.effect(ConfigLoader, makeConfigLoader);
|
|
314
330
|
var PatternMatcher = class {
|
|
315
331
|
constructor(config) {
|
|
316
332
|
__publicField(this, "ignorePatterns", []);
|
|
@@ -458,13 +474,89 @@ var Logger = class {
|
|
|
458
474
|
}
|
|
459
475
|
};
|
|
460
476
|
var logger = new Logger();
|
|
477
|
+
var NodeConfigLoaderLive = ConfigLoaderLive.pipe(
|
|
478
|
+
effect.Layer.provide(effect.Layer.mergeAll(platformNode.NodeContext.layer, platform.FetchHttpClient.layer))
|
|
479
|
+
);
|
|
480
|
+
var cachedLoaderPromise = null;
|
|
481
|
+
function getCachedLoader() {
|
|
482
|
+
if (!cachedLoaderPromise) {
|
|
483
|
+
cachedLoaderPromise = effect.Effect.runPromise(
|
|
484
|
+
effect.Effect.gen(function* () {
|
|
485
|
+
return yield* ConfigLoader;
|
|
486
|
+
}).pipe(effect.Effect.provide(NodeConfigLoaderLive))
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
return cachedLoaderPromise;
|
|
490
|
+
}
|
|
491
|
+
async function loadConfig(uri, options) {
|
|
492
|
+
if (options?.cacheTimeout === 0) {
|
|
493
|
+
const program = effect.Effect.gen(function* () {
|
|
494
|
+
const loader2 = yield* ConfigLoader;
|
|
495
|
+
return yield* loader2.loadFromUri(uri);
|
|
496
|
+
});
|
|
497
|
+
return effect.Effect.runPromise(program.pipe(effect.Effect.provide(NodeConfigLoaderLive)));
|
|
498
|
+
}
|
|
499
|
+
const loader = await getCachedLoader();
|
|
500
|
+
return effect.Effect.runPromise(loader.loadFromUri(uri));
|
|
501
|
+
}
|
|
502
|
+
async function loadConfigFromInline(content) {
|
|
503
|
+
const loader = await getCachedLoader();
|
|
504
|
+
return effect.Effect.runPromise(loader.loadFromInline(content));
|
|
505
|
+
}
|
|
506
|
+
function getDefaultConfig() {
|
|
507
|
+
return {
|
|
508
|
+
version: "1.0",
|
|
509
|
+
instrumentation: {
|
|
510
|
+
enabled: true,
|
|
511
|
+
logging: "on",
|
|
512
|
+
description: "Default instrumentation configuration",
|
|
513
|
+
instrument_patterns: [
|
|
514
|
+
{ pattern: "^app\\.", enabled: true, description: "Application operations" },
|
|
515
|
+
{ pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
|
|
516
|
+
{ pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
|
|
517
|
+
],
|
|
518
|
+
ignore_patterns: [
|
|
519
|
+
{ pattern: "^test\\.", description: "Test utilities" },
|
|
520
|
+
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
521
|
+
{ pattern: "^health\\.", description: "Health checks" }
|
|
522
|
+
]
|
|
523
|
+
},
|
|
524
|
+
effect: {
|
|
525
|
+
auto_extract_metadata: true
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
async function loadConfigWithOptions(options = {}) {
|
|
530
|
+
const loadOptions = options.cacheTimeout !== void 0 ? { cacheTimeout: options.cacheTimeout } : void 0;
|
|
531
|
+
if (options.config) {
|
|
532
|
+
return loadConfigFromInline(options.config);
|
|
533
|
+
}
|
|
534
|
+
const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
|
|
535
|
+
if (envConfigPath) {
|
|
536
|
+
return loadConfig(envConfigPath, loadOptions);
|
|
537
|
+
}
|
|
538
|
+
if (options.configUrl) {
|
|
539
|
+
return loadConfig(options.configUrl, loadOptions);
|
|
540
|
+
}
|
|
541
|
+
if (options.configPath) {
|
|
542
|
+
return loadConfig(options.configPath, loadOptions);
|
|
543
|
+
}
|
|
544
|
+
const { existsSync } = await import('fs');
|
|
545
|
+
const { join } = await import('path');
|
|
546
|
+
const defaultPath = join(process.cwd(), "instrumentation.yaml");
|
|
547
|
+
if (existsSync(defaultPath)) {
|
|
548
|
+
return loadConfig(defaultPath, loadOptions);
|
|
549
|
+
}
|
|
550
|
+
return getDefaultConfig();
|
|
551
|
+
}
|
|
461
552
|
|
|
462
553
|
// src/integrations/effect/effect-tracer.ts
|
|
554
|
+
var SDK_NAME = "@effect/opentelemetry-otlp";
|
|
463
555
|
function createEffectInstrumentation(options = {}) {
|
|
464
556
|
return effect.Layer.unwrapEffect(
|
|
465
557
|
effect.Effect.gen(function* () {
|
|
466
558
|
const config = yield* effect.Effect.tryPromise({
|
|
467
|
-
try: () =>
|
|
559
|
+
try: () => loadConfigWithOptions(options),
|
|
468
560
|
catch: (error) => ({
|
|
469
561
|
_tag: "ConfigError",
|
|
470
562
|
message: error instanceof Error ? error.message : String(error)
|
|
@@ -493,7 +585,9 @@ function createEffectInstrumentation(options = {}) {
|
|
|
493
585
|
attributes: {
|
|
494
586
|
"platform.component": "effect",
|
|
495
587
|
"effect.auto_metadata": autoExtractMetadata,
|
|
496
|
-
"effect.context_propagation": continueExistingTraces
|
|
588
|
+
"effect.context_propagation": continueExistingTraces,
|
|
589
|
+
[ATTR_TELEMETRY_SDK_LANGUAGE]: TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
|
|
590
|
+
[ATTR_TELEMETRY_SDK_NAME]: SDK_NAME
|
|
497
591
|
}
|
|
498
592
|
},
|
|
499
593
|
// Bridge Effect context to OpenTelemetry global context
|
|
@@ -532,7 +626,9 @@ var EffectInstrumentationLive = effect.Effect.sync(() => {
|
|
|
532
626
|
serviceName,
|
|
533
627
|
serviceVersion,
|
|
534
628
|
attributes: {
|
|
535
|
-
"platform.component": "effect"
|
|
629
|
+
"platform.component": "effect",
|
|
630
|
+
[ATTR_TELEMETRY_SDK_LANGUAGE]: TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
|
|
631
|
+
[ATTR_TELEMETRY_SDK_NAME]: SDK_NAME
|
|
536
632
|
}
|
|
537
633
|
},
|
|
538
634
|
// CRITICAL: Bridge Effect context to OpenTelemetry global context
|
|
@@ -551,25 +647,144 @@ var EffectInstrumentationLive = effect.Effect.sync(() => {
|
|
|
551
647
|
}
|
|
552
648
|
}).pipe(effect.Layer.provide(platform.FetchHttpClient.layer));
|
|
553
649
|
}).pipe(effect.Layer.unwrapEffect);
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
650
|
+
function annotateUser(userId, email, username) {
|
|
651
|
+
const attributes = {
|
|
652
|
+
"user.id": userId
|
|
653
|
+
};
|
|
654
|
+
if (email) attributes["user.email"] = email;
|
|
655
|
+
if (username) attributes["user.name"] = username;
|
|
656
|
+
return effect.Effect.annotateCurrentSpan(attributes);
|
|
557
657
|
}
|
|
558
|
-
function annotateDataSize(
|
|
658
|
+
function annotateDataSize(bytes, items, compressionRatio) {
|
|
659
|
+
const attributes = {
|
|
660
|
+
"data.size.bytes": bytes,
|
|
661
|
+
"data.size.items": items
|
|
662
|
+
};
|
|
663
|
+
if (compressionRatio !== void 0) {
|
|
664
|
+
attributes["data.compression.ratio"] = compressionRatio;
|
|
665
|
+
}
|
|
666
|
+
return effect.Effect.annotateCurrentSpan(attributes);
|
|
559
667
|
}
|
|
560
|
-
function annotateBatch(
|
|
668
|
+
function annotateBatch(totalItems, batchSize, successCount, failureCount) {
|
|
669
|
+
const attributes = {
|
|
670
|
+
"batch.size": batchSize,
|
|
671
|
+
"batch.total_items": totalItems,
|
|
672
|
+
"batch.count": Math.ceil(totalItems / batchSize)
|
|
673
|
+
};
|
|
674
|
+
if (successCount !== void 0) {
|
|
675
|
+
attributes["batch.success_count"] = successCount;
|
|
676
|
+
}
|
|
677
|
+
if (failureCount !== void 0) {
|
|
678
|
+
attributes["batch.failure_count"] = failureCount;
|
|
679
|
+
}
|
|
680
|
+
return effect.Effect.annotateCurrentSpan(attributes);
|
|
681
|
+
}
|
|
682
|
+
function annotateLLM(model, provider, tokens) {
|
|
683
|
+
const attributes = {
|
|
684
|
+
"llm.model": model,
|
|
685
|
+
"llm.provider": provider
|
|
686
|
+
};
|
|
687
|
+
if (tokens) {
|
|
688
|
+
if (tokens.prompt !== void 0) attributes["llm.tokens.prompt"] = tokens.prompt;
|
|
689
|
+
if (tokens.completion !== void 0) attributes["llm.tokens.completion"] = tokens.completion;
|
|
690
|
+
if (tokens.total !== void 0) attributes["llm.tokens.total"] = tokens.total;
|
|
691
|
+
}
|
|
692
|
+
return effect.Effect.annotateCurrentSpan(attributes);
|
|
693
|
+
}
|
|
694
|
+
function annotateQuery(query, duration, rowCount, database) {
|
|
695
|
+
const attributes = {
|
|
696
|
+
"db.statement": query.length > 1e3 ? query.substring(0, 1e3) + "..." : query
|
|
697
|
+
};
|
|
698
|
+
if (duration !== void 0) attributes["db.duration.ms"] = duration;
|
|
699
|
+
if (rowCount !== void 0) attributes["db.row_count"] = rowCount;
|
|
700
|
+
if (database) attributes["db.name"] = database;
|
|
701
|
+
return effect.Effect.annotateCurrentSpan(attributes);
|
|
702
|
+
}
|
|
703
|
+
function annotateHttpRequest(method, url, statusCode, contentLength) {
|
|
704
|
+
const attributes = {
|
|
705
|
+
"http.method": method,
|
|
706
|
+
"http.url": url
|
|
707
|
+
};
|
|
708
|
+
if (statusCode !== void 0) attributes["http.status_code"] = statusCode;
|
|
709
|
+
if (contentLength !== void 0) attributes["http.response.content_length"] = contentLength;
|
|
710
|
+
return effect.Effect.annotateCurrentSpan(attributes);
|
|
561
711
|
}
|
|
562
|
-
function
|
|
712
|
+
function annotateError(error, recoverable, errorType) {
|
|
713
|
+
const errorMessage = typeof error === "string" ? error : error.message;
|
|
714
|
+
const errorStack = typeof error === "string" ? void 0 : error.stack;
|
|
715
|
+
const attributes = {
|
|
716
|
+
"error.message": errorMessage,
|
|
717
|
+
"error.recoverable": recoverable
|
|
718
|
+
};
|
|
719
|
+
if (errorType) attributes["error.type"] = errorType;
|
|
720
|
+
if (errorStack) attributes["error.stack"] = errorStack;
|
|
721
|
+
return effect.Effect.annotateCurrentSpan(attributes);
|
|
563
722
|
}
|
|
564
|
-
function
|
|
723
|
+
function annotatePriority(priority, reason) {
|
|
724
|
+
const attributes = {
|
|
725
|
+
"operation.priority": priority
|
|
726
|
+
};
|
|
727
|
+
if (reason) attributes["operation.priority.reason"] = reason;
|
|
728
|
+
return effect.Effect.annotateCurrentSpan(attributes);
|
|
565
729
|
}
|
|
566
|
-
function
|
|
730
|
+
function annotateCache(hit, key, ttl) {
|
|
731
|
+
const attributes = {
|
|
732
|
+
"cache.hit": hit,
|
|
733
|
+
"cache.key": key
|
|
734
|
+
};
|
|
735
|
+
if (ttl !== void 0) attributes["cache.ttl.seconds"] = ttl;
|
|
736
|
+
return effect.Effect.annotateCurrentSpan(attributes);
|
|
567
737
|
}
|
|
568
|
-
function
|
|
738
|
+
function extractEffectMetadata() {
|
|
739
|
+
return effect.Effect.gen(function* () {
|
|
740
|
+
const metadata = {};
|
|
741
|
+
const currentFiber = effect.Fiber.getCurrentFiber();
|
|
742
|
+
if (effect.Option.isSome(currentFiber)) {
|
|
743
|
+
const fiber = currentFiber.value;
|
|
744
|
+
const fiberId = fiber.id();
|
|
745
|
+
metadata["effect.fiber.id"] = effect.FiberId.threadName(fiberId);
|
|
746
|
+
const status = yield* effect.Fiber.status(fiber);
|
|
747
|
+
if (status._tag) {
|
|
748
|
+
metadata["effect.fiber.status"] = status._tag;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
const parentSpanResult = yield* effect.Effect.currentSpan.pipe(
|
|
752
|
+
effect.Effect.option
|
|
753
|
+
// Convert NoSuchElementException to Option
|
|
754
|
+
);
|
|
755
|
+
if (effect.Option.isSome(parentSpanResult)) {
|
|
756
|
+
const parentSpan = parentSpanResult.value;
|
|
757
|
+
metadata["effect.operation.nested"] = true;
|
|
758
|
+
metadata["effect.operation.root"] = false;
|
|
759
|
+
if (parentSpan.spanId) {
|
|
760
|
+
metadata["effect.parent.span.id"] = parentSpan.spanId;
|
|
761
|
+
}
|
|
762
|
+
if (parentSpan.name) {
|
|
763
|
+
metadata["effect.parent.span.name"] = parentSpan.name;
|
|
764
|
+
}
|
|
765
|
+
if (parentSpan.traceId) {
|
|
766
|
+
metadata["effect.parent.trace.id"] = parentSpan.traceId;
|
|
767
|
+
}
|
|
768
|
+
} else {
|
|
769
|
+
metadata["effect.operation.nested"] = false;
|
|
770
|
+
metadata["effect.operation.root"] = true;
|
|
771
|
+
}
|
|
772
|
+
return metadata;
|
|
773
|
+
});
|
|
569
774
|
}
|
|
570
|
-
function
|
|
775
|
+
function autoEnrichSpan() {
|
|
776
|
+
return effect.Effect.gen(function* () {
|
|
777
|
+
const metadata = yield* extractEffectMetadata();
|
|
778
|
+
yield* effect.Effect.annotateCurrentSpan(metadata);
|
|
779
|
+
});
|
|
571
780
|
}
|
|
572
|
-
function
|
|
781
|
+
function withAutoEnrichedSpan(spanName, options) {
|
|
782
|
+
return (self) => {
|
|
783
|
+
return effect.Effect.gen(function* () {
|
|
784
|
+
yield* autoEnrichSpan();
|
|
785
|
+
return yield* self;
|
|
786
|
+
}).pipe(effect.Effect.withSpan(spanName, options));
|
|
787
|
+
};
|
|
573
788
|
}
|
|
574
789
|
var createLogicalParentLink = (parentSpan, useSpanLinks) => {
|
|
575
790
|
if (!useSpanLinks) {
|
|
@@ -708,8 +923,11 @@ exports.annotatePriority = annotatePriority;
|
|
|
708
923
|
exports.annotateQuery = annotateQuery;
|
|
709
924
|
exports.annotateSpawnedTasks = annotateSpawnedTasks;
|
|
710
925
|
exports.annotateUser = annotateUser;
|
|
926
|
+
exports.autoEnrichSpan = autoEnrichSpan;
|
|
711
927
|
exports.createEffectInstrumentation = createEffectInstrumentation;
|
|
928
|
+
exports.extractEffectMetadata = extractEffectMetadata;
|
|
712
929
|
exports.runIsolated = runIsolated;
|
|
713
930
|
exports.runWithSpan = runWithSpan;
|
|
931
|
+
exports.withAutoEnrichedSpan = withAutoEnrichedSpan;
|
|
714
932
|
//# sourceMappingURL=index.cjs.map
|
|
715
933
|
//# sourceMappingURL=index.cjs.map
|