@atrim/instrument-node 0.5.2-dev.ac2fbfe.20251221205322 → 0.6.0
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 +92 -330
- package/package.json +17 -16
- package/target/dist/index.cjs +135 -59
- package/target/dist/index.cjs.map +1 -1
- package/target/dist/index.d.cts +28 -13
- package/target/dist/index.d.ts +28 -13
- package/target/dist/index.js +134 -59
- package/target/dist/index.js.map +1 -1
- package/target/dist/integrations/effect/index.cjs +139 -128
- package/target/dist/integrations/effect/index.cjs.map +1 -1
- package/target/dist/integrations/effect/index.d.cts +19 -24
- package/target/dist/integrations/effect/index.d.ts +19 -24
- package/target/dist/integrations/effect/index.js +140 -131
- package/target/dist/integrations/effect/index.js.map +1 -1
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var effect = require('effect');
|
|
4
|
+
var Tracer = 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,16 +31,13 @@ function _interopNamespace(e) {
|
|
|
29
31
|
return Object.freeze(n);
|
|
30
32
|
}
|
|
31
33
|
|
|
34
|
+
var Tracer__namespace = /*#__PURE__*/_interopNamespace(Tracer);
|
|
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);
|
|
35
39
|
|
|
36
40
|
// 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";
|
|
42
41
|
var __defProp = Object.defineProperty;
|
|
43
42
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
44
43
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -100,11 +99,50 @@ var InstrumentationConfigSchema = zod.z.object({
|
|
|
100
99
|
ignore_patterns: zod.z.array(PatternConfigSchema)
|
|
101
100
|
}),
|
|
102
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"),
|
|
103
109
|
auto_extract_metadata: zod.z.boolean(),
|
|
104
110
|
auto_isolation: AutoIsolationConfigSchema.optional()
|
|
105
111
|
}).optional(),
|
|
106
112
|
http: HttpFilteringConfigSchema.optional()
|
|
107
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
|
+
}
|
|
108
146
|
(class extends effect.Data.TaggedError("ConfigError") {
|
|
109
147
|
get message() {
|
|
110
148
|
return this.reason;
|
|
@@ -282,7 +320,7 @@ var makeConfigLoader = effect.Effect.gen(function* () {
|
|
|
282
320
|
})
|
|
283
321
|
});
|
|
284
322
|
});
|
|
285
|
-
|
|
323
|
+
effect.Layer.effect(ConfigLoader, makeConfigLoader);
|
|
286
324
|
var PatternMatcher = class {
|
|
287
325
|
constructor(config) {
|
|
288
326
|
__publicField(this, "ignorePatterns", []);
|
|
@@ -430,84 +468,58 @@ var Logger = class {
|
|
|
430
468
|
}
|
|
431
469
|
};
|
|
432
470
|
var logger = new Logger();
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
);
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}).pipe(effect.Effect.provide(NodeConfigLoaderLive))
|
|
443
|
-
);
|
|
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}`);
|
|
444
480
|
}
|
|
445
|
-
|
|
481
|
+
const content = await response.text();
|
|
482
|
+
return parseAndValidateConfig(content);
|
|
446
483
|
}
|
|
447
|
-
async function loadConfig(uri,
|
|
448
|
-
if (
|
|
449
|
-
|
|
450
|
-
const loader2 = yield* ConfigLoader;
|
|
451
|
-
return yield* loader2.loadFromUri(uri);
|
|
452
|
-
});
|
|
453
|
-
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);
|
|
454
487
|
}
|
|
455
|
-
|
|
456
|
-
|
|
488
|
+
if (uri.startsWith("file://")) {
|
|
489
|
+
const filePath = uri.slice(7);
|
|
490
|
+
return loadFromFile(filePath);
|
|
491
|
+
}
|
|
492
|
+
return loadFromFile(uri);
|
|
457
493
|
}
|
|
458
494
|
async function loadConfigFromInline(content) {
|
|
459
|
-
|
|
460
|
-
return effect.Effect.runPromise(loader.loadFromInline(content));
|
|
461
|
-
}
|
|
462
|
-
function getDefaultConfig() {
|
|
463
|
-
return {
|
|
464
|
-
version: "1.0",
|
|
465
|
-
instrumentation: {
|
|
466
|
-
enabled: true,
|
|
467
|
-
logging: "on",
|
|
468
|
-
description: "Default instrumentation configuration",
|
|
469
|
-
instrument_patterns: [
|
|
470
|
-
{ pattern: "^app\\.", enabled: true, description: "Application operations" },
|
|
471
|
-
{ pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
|
|
472
|
-
{ pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
|
|
473
|
-
],
|
|
474
|
-
ignore_patterns: [
|
|
475
|
-
{ pattern: "^test\\.", description: "Test utilities" },
|
|
476
|
-
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
477
|
-
{ pattern: "^health\\.", description: "Health checks" }
|
|
478
|
-
]
|
|
479
|
-
},
|
|
480
|
-
effect: {
|
|
481
|
-
auto_extract_metadata: true
|
|
482
|
-
}
|
|
483
|
-
};
|
|
495
|
+
return parseAndValidateConfig(content);
|
|
484
496
|
}
|
|
485
497
|
async function loadConfigWithOptions(options = {}) {
|
|
486
|
-
const loadOptions = options.cacheTimeout !== void 0 ? { cacheTimeout: options.cacheTimeout } : void 0;
|
|
487
498
|
if (options.config) {
|
|
488
499
|
return loadConfigFromInline(options.config);
|
|
489
500
|
}
|
|
490
501
|
const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
|
|
491
502
|
if (envConfigPath) {
|
|
492
|
-
return loadConfig(envConfigPath
|
|
503
|
+
return loadConfig(envConfigPath);
|
|
493
504
|
}
|
|
494
505
|
if (options.configUrl) {
|
|
495
|
-
return loadConfig(options.configUrl
|
|
506
|
+
return loadConfig(options.configUrl);
|
|
496
507
|
}
|
|
497
508
|
if (options.configPath) {
|
|
498
|
-
return loadConfig(options.configPath
|
|
509
|
+
return loadConfig(options.configPath);
|
|
499
510
|
}
|
|
500
511
|
const { existsSync } = await import('fs');
|
|
501
512
|
const { join } = await import('path');
|
|
502
513
|
const defaultPath = join(process.cwd(), "instrumentation.yaml");
|
|
503
514
|
if (existsSync(defaultPath)) {
|
|
504
|
-
return loadConfig(defaultPath
|
|
515
|
+
return loadConfig(defaultPath);
|
|
505
516
|
}
|
|
506
|
-
return
|
|
517
|
+
return defaultConfig;
|
|
507
518
|
}
|
|
508
519
|
|
|
509
520
|
// src/integrations/effect/effect-tracer.ts
|
|
510
|
-
var SDK_NAME = "@effect/opentelemetry
|
|
521
|
+
var SDK_NAME = "@effect/opentelemetry";
|
|
522
|
+
var ATTR_TELEMETRY_EXPORTER_MODE = "telemetry.exporter.mode";
|
|
511
523
|
function createEffectInstrumentation(options = {}) {
|
|
512
524
|
return effect.Layer.unwrapEffect(
|
|
513
525
|
effect.Effect.gen(function* () {
|
|
@@ -518,90 +530,89 @@ function createEffectInstrumentation(options = {}) {
|
|
|
518
530
|
message: error instanceof Error ? error.message : String(error)
|
|
519
531
|
})
|
|
520
532
|
});
|
|
533
|
+
const effectEnabled = process.env.OTEL_EFFECT_ENABLED !== "false" && (config.effect?.enabled ?? true);
|
|
534
|
+
if (!effectEnabled) {
|
|
535
|
+
logger.log("@atrim/instrumentation/effect: Effect tracing disabled via config");
|
|
536
|
+
return effect.Layer.empty;
|
|
537
|
+
}
|
|
521
538
|
yield* effect.Effect.sync(() => {
|
|
522
539
|
const loggingLevel = config.instrumentation.logging || "on";
|
|
523
540
|
logger.setLevel(loggingLevel);
|
|
524
541
|
});
|
|
525
542
|
yield* effect.Effect.sync(() => initializePatternMatcher(config));
|
|
526
|
-
const otlpEndpoint = options.otlpEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
|
|
527
543
|
const serviceName = options.serviceName || process.env.OTEL_SERVICE_NAME || "effect-service";
|
|
528
544
|
const serviceVersion = options.serviceVersion || process.env.npm_package_version || "1.0.0";
|
|
529
|
-
const
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
545
|
+
const exporterMode = options.exporterMode ?? config.effect?.exporter ?? "unified";
|
|
546
|
+
const resourceAttributes = {
|
|
547
|
+
"platform.component": "effect",
|
|
548
|
+
[semanticConventions.ATTR_TELEMETRY_SDK_LANGUAGE]: semanticConventions.TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
|
|
549
|
+
[semanticConventions.ATTR_TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
550
|
+
[ATTR_TELEMETRY_EXPORTER_MODE]: exporterMode
|
|
551
|
+
};
|
|
552
|
+
if (exporterMode === "standalone") {
|
|
553
|
+
const otlpEndpoint = options.otlpEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
|
|
554
|
+
logger.log("Effect OpenTelemetry instrumentation (standalone)");
|
|
555
|
+
logger.log(` Service: ${serviceName}`);
|
|
556
|
+
logger.log(` Endpoint: ${otlpEndpoint}`);
|
|
557
|
+
logger.log(" WARNING: Standalone mode bypasses Node SDK filtering");
|
|
558
|
+
return Otlp__namespace.layer({
|
|
559
|
+
baseUrl: otlpEndpoint,
|
|
560
|
+
resource: {
|
|
561
|
+
serviceName,
|
|
562
|
+
serviceVersion,
|
|
563
|
+
attributes: resourceAttributes
|
|
564
|
+
},
|
|
565
|
+
// Bridge Effect context to OpenTelemetry global context
|
|
566
|
+
tracerContext: (f, span) => {
|
|
567
|
+
if (span._tag !== "Span") {
|
|
568
|
+
return f();
|
|
569
|
+
}
|
|
570
|
+
const spanContext = {
|
|
571
|
+
traceId: span.traceId,
|
|
572
|
+
spanId: span.spanId,
|
|
573
|
+
traceFlags: span.sampled ? api.TraceFlags.SAMPLED : api.TraceFlags.NONE
|
|
574
|
+
};
|
|
575
|
+
const otelSpan = api.trace.wrapSpanContext(spanContext);
|
|
576
|
+
return api.context.with(api.trace.setSpan(api.context.active(), otelSpan), f);
|
|
554
577
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
578
|
+
}).pipe(effect.Layer.provide(platform.FetchHttpClient.layer));
|
|
579
|
+
} else {
|
|
580
|
+
logger.log("Effect OpenTelemetry instrumentation (unified)");
|
|
581
|
+
logger.log(` Service: ${serviceName}`);
|
|
582
|
+
logger.log(" Using global TracerProvider for span export");
|
|
583
|
+
return Tracer__namespace.layerGlobal.pipe(
|
|
584
|
+
effect.Layer.provide(
|
|
585
|
+
Resource__namespace.layer({
|
|
586
|
+
serviceName,
|
|
587
|
+
serviceVersion,
|
|
588
|
+
attributes: resourceAttributes
|
|
589
|
+
})
|
|
590
|
+
)
|
|
591
|
+
);
|
|
566
592
|
}
|
|
567
|
-
return otlpLayer;
|
|
568
593
|
})
|
|
569
594
|
).pipe(effect.Layer.orDie);
|
|
570
595
|
}
|
|
571
596
|
var EffectInstrumentationLive = effect.Effect.sync(() => {
|
|
572
|
-
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
|
|
573
597
|
const serviceName = process.env.OTEL_SERVICE_NAME || "effect-service";
|
|
574
598
|
const serviceVersion = process.env.npm_package_version || "1.0.0";
|
|
575
599
|
logger.minimal(`@atrim/instrumentation/effect: Effect tracing enabled (${serviceName})`);
|
|
576
|
-
logger.log("
|
|
577
|
-
logger.log(`
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
tracerContext: (f, span) => {
|
|
593
|
-
if (span._tag !== "Span") {
|
|
594
|
-
return f();
|
|
595
|
-
}
|
|
596
|
-
const spanContext = {
|
|
597
|
-
traceId: span.traceId,
|
|
598
|
-
spanId: span.spanId,
|
|
599
|
-
traceFlags: span.sampled ? api.TraceFlags.SAMPLED : api.TraceFlags.NONE
|
|
600
|
-
};
|
|
601
|
-
const otelSpan = api.trace.wrapSpanContext(spanContext);
|
|
602
|
-
return api.context.with(api.trace.setSpan(api.context.active(), otelSpan), f);
|
|
603
|
-
}
|
|
604
|
-
}).pipe(effect.Layer.provide(platform.FetchHttpClient.layer));
|
|
600
|
+
logger.log("Effect OpenTelemetry tracer (unified)");
|
|
601
|
+
logger.log(` Service: ${serviceName}`);
|
|
602
|
+
return Tracer__namespace.layerGlobal.pipe(
|
|
603
|
+
effect.Layer.provide(
|
|
604
|
+
Resource__namespace.layer({
|
|
605
|
+
serviceName,
|
|
606
|
+
serviceVersion,
|
|
607
|
+
attributes: {
|
|
608
|
+
"platform.component": "effect",
|
|
609
|
+
[semanticConventions.ATTR_TELEMETRY_SDK_LANGUAGE]: semanticConventions.TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
|
|
610
|
+
[semanticConventions.ATTR_TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
611
|
+
[ATTR_TELEMETRY_EXPORTER_MODE]: "unified"
|
|
612
|
+
}
|
|
613
|
+
})
|
|
614
|
+
)
|
|
615
|
+
);
|
|
605
616
|
}).pipe(effect.Layer.unwrapEffect);
|
|
606
617
|
function annotateUser(userId, email, username) {
|
|
607
618
|
const attributes = {
|