@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
package/target/dist/index.cjs
CHANGED
|
@@ -13,9 +13,9 @@ var zod = require('zod');
|
|
|
13
13
|
var exporterTraceOtlpHttp = require('@opentelemetry/exporter-trace-otlp-http');
|
|
14
14
|
var promises = require('fs/promises');
|
|
15
15
|
var path = require('path');
|
|
16
|
-
var
|
|
17
|
-
var platform = require('@effect/platform');
|
|
16
|
+
var module$1 = require('module');
|
|
18
17
|
|
|
18
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
19
19
|
function _interopNamespace(e) {
|
|
20
20
|
if (e && e.__esModule) return e;
|
|
21
21
|
var n = Object.create(null);
|
|
@@ -107,11 +107,50 @@ var InstrumentationConfigSchema = zod.z.object({
|
|
|
107
107
|
ignore_patterns: zod.z.array(PatternConfigSchema)
|
|
108
108
|
}),
|
|
109
109
|
effect: zod.z.object({
|
|
110
|
+
// Enable/disable Effect tracing entirely
|
|
111
|
+
// When false, EffectInstrumentationLive returns Layer.empty
|
|
112
|
+
enabled: zod.z.boolean().default(true),
|
|
113
|
+
// Exporter mode:
|
|
114
|
+
// - "unified": Use global TracerProvider from Node SDK (recommended, enables filtering)
|
|
115
|
+
// - "standalone": Use Effect's own OTLP exporter (bypasses Node SDK filtering)
|
|
116
|
+
exporter: zod.z.enum(["unified", "standalone"]).default("unified"),
|
|
110
117
|
auto_extract_metadata: zod.z.boolean(),
|
|
111
118
|
auto_isolation: AutoIsolationConfigSchema.optional()
|
|
112
119
|
}).optional(),
|
|
113
120
|
http: HttpFilteringConfigSchema.optional()
|
|
114
121
|
});
|
|
122
|
+
var defaultConfig = {
|
|
123
|
+
version: "1.0",
|
|
124
|
+
instrumentation: {
|
|
125
|
+
enabled: true,
|
|
126
|
+
logging: "on",
|
|
127
|
+
description: "Default instrumentation configuration",
|
|
128
|
+
instrument_patterns: [
|
|
129
|
+
{ pattern: "^app\\.", enabled: true, description: "Application operations" },
|
|
130
|
+
{ pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
|
|
131
|
+
{ pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
|
|
132
|
+
],
|
|
133
|
+
ignore_patterns: [
|
|
134
|
+
{ pattern: "^test\\.", description: "Test utilities" },
|
|
135
|
+
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
136
|
+
{ pattern: "^health\\.", description: "Health checks" }
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
effect: {
|
|
140
|
+
enabled: true,
|
|
141
|
+
exporter: "unified",
|
|
142
|
+
auto_extract_metadata: true
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
function parseAndValidateConfig(content) {
|
|
146
|
+
let parsed;
|
|
147
|
+
if (typeof content === "string") {
|
|
148
|
+
parsed = yaml.parse(content);
|
|
149
|
+
} else {
|
|
150
|
+
parsed = content;
|
|
151
|
+
}
|
|
152
|
+
return InstrumentationConfigSchema.parse(parsed);
|
|
153
|
+
}
|
|
115
154
|
(class extends effect.Data.TaggedError("ConfigError") {
|
|
116
155
|
get message() {
|
|
117
156
|
return this.reason;
|
|
@@ -289,7 +328,7 @@ var makeConfigLoader = effect.Effect.gen(function* () {
|
|
|
289
328
|
})
|
|
290
329
|
});
|
|
291
330
|
});
|
|
292
|
-
|
|
331
|
+
effect.Layer.effect(ConfigLoader, makeConfigLoader);
|
|
293
332
|
var PatternMatcher = class {
|
|
294
333
|
constructor(config) {
|
|
295
334
|
__publicField2(this, "ignorePatterns", []);
|
|
@@ -453,8 +492,14 @@ var PatternSpanProcessor = class {
|
|
|
453
492
|
constructor(config, wrappedProcessor) {
|
|
454
493
|
__publicField(this, "matcher");
|
|
455
494
|
__publicField(this, "wrappedProcessor");
|
|
495
|
+
__publicField(this, "httpIgnorePatterns", []);
|
|
456
496
|
this.matcher = new PatternMatcher(config);
|
|
457
497
|
this.wrappedProcessor = wrappedProcessor;
|
|
498
|
+
if (config.http?.ignore_incoming_paths) {
|
|
499
|
+
this.httpIgnorePatterns = config.http.ignore_incoming_paths.map(
|
|
500
|
+
(pattern) => new RegExp(pattern)
|
|
501
|
+
);
|
|
502
|
+
}
|
|
458
503
|
}
|
|
459
504
|
/**
|
|
460
505
|
* Called when a span is started
|
|
@@ -472,12 +517,40 @@ var PatternSpanProcessor = class {
|
|
|
472
517
|
* Called when a span is ended
|
|
473
518
|
*
|
|
474
519
|
* This is where we make the final decision on whether to export the span.
|
|
520
|
+
* We check both span name patterns and HTTP path patterns.
|
|
475
521
|
*/
|
|
476
522
|
onEnd(span) {
|
|
477
523
|
const spanName = span.name;
|
|
478
|
-
if (this.matcher.shouldInstrument(spanName)) {
|
|
479
|
-
|
|
524
|
+
if (!this.matcher.shouldInstrument(spanName)) {
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
if (this.shouldIgnoreHttpSpan(span)) {
|
|
528
|
+
return;
|
|
480
529
|
}
|
|
530
|
+
this.wrappedProcessor.onEnd(span);
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Check if span should be ignored based on HTTP path attributes
|
|
534
|
+
*
|
|
535
|
+
* This checks the span's url.path, http.route, or http.target attributes
|
|
536
|
+
* against the configured http.ignore_incoming_paths patterns.
|
|
537
|
+
*
|
|
538
|
+
* This enables filtering of Effect HTTP spans (and any other HTTP spans)
|
|
539
|
+
* based on path patterns, which is essential for filtering out OTLP
|
|
540
|
+
* endpoint requests like /v1/traces, /v1/logs, /v1/metrics.
|
|
541
|
+
*/
|
|
542
|
+
shouldIgnoreHttpSpan(span) {
|
|
543
|
+
if (this.httpIgnorePatterns.length === 0) {
|
|
544
|
+
return false;
|
|
545
|
+
}
|
|
546
|
+
const urlPath = span.attributes["url.path"];
|
|
547
|
+
const httpRoute = span.attributes["http.route"];
|
|
548
|
+
const httpTarget = span.attributes["http.target"];
|
|
549
|
+
const pathToCheck = urlPath || httpRoute || httpTarget;
|
|
550
|
+
if (!pathToCheck) {
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
return this.httpIgnorePatterns.some((pattern) => pattern.test(pathToCheck));
|
|
481
554
|
}
|
|
482
555
|
/**
|
|
483
556
|
* Shutdown the processor
|
|
@@ -715,83 +788,55 @@ async function getServiceNameAsync() {
|
|
|
715
788
|
async function getServiceVersionAsync() {
|
|
716
789
|
return effect.Effect.runPromise(getServiceVersion);
|
|
717
790
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
);
|
|
721
|
-
|
|
722
|
-
function getCachedLoader() {
|
|
723
|
-
if (!cachedLoaderPromise) {
|
|
724
|
-
cachedLoaderPromise = effect.Effect.runPromise(
|
|
725
|
-
effect.Effect.gen(function* () {
|
|
726
|
-
return yield* ConfigLoader;
|
|
727
|
-
}).pipe(effect.Effect.provide(NodeConfigLoaderLive))
|
|
728
|
-
);
|
|
729
|
-
}
|
|
730
|
-
return cachedLoaderPromise;
|
|
791
|
+
async function loadFromFile(filePath) {
|
|
792
|
+
const { readFile: readFile2 } = await import('fs/promises');
|
|
793
|
+
const content = await readFile2(filePath, "utf-8");
|
|
794
|
+
return parseAndValidateConfig(content);
|
|
731
795
|
}
|
|
732
|
-
function
|
|
733
|
-
|
|
796
|
+
async function loadFromUrl(url) {
|
|
797
|
+
const response = await fetch(url);
|
|
798
|
+
if (!response.ok) {
|
|
799
|
+
throw new Error(`Failed to fetch config from ${url}: ${response.statusText}`);
|
|
800
|
+
}
|
|
801
|
+
const content = await response.text();
|
|
802
|
+
return parseAndValidateConfig(content);
|
|
734
803
|
}
|
|
735
|
-
async function loadConfig(uri,
|
|
736
|
-
if (
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
return
|
|
804
|
+
async function loadConfig(uri, _options) {
|
|
805
|
+
if (uri.startsWith("http://") || uri.startsWith("https://")) {
|
|
806
|
+
return loadFromUrl(uri);
|
|
807
|
+
}
|
|
808
|
+
if (uri.startsWith("file://")) {
|
|
809
|
+
const filePath = uri.slice(7);
|
|
810
|
+
return loadFromFile(filePath);
|
|
742
811
|
}
|
|
743
|
-
|
|
744
|
-
return effect.Effect.runPromise(loader.loadFromUri(uri));
|
|
812
|
+
return loadFromFile(uri);
|
|
745
813
|
}
|
|
746
814
|
async function loadConfigFromInline(content) {
|
|
747
|
-
|
|
748
|
-
return effect.Effect.runPromise(loader.loadFromInline(content));
|
|
815
|
+
return parseAndValidateConfig(content);
|
|
749
816
|
}
|
|
750
|
-
function
|
|
751
|
-
return {
|
|
752
|
-
version: "1.0",
|
|
753
|
-
instrumentation: {
|
|
754
|
-
enabled: true,
|
|
755
|
-
logging: "on",
|
|
756
|
-
description: "Default instrumentation configuration",
|
|
757
|
-
instrument_patterns: [
|
|
758
|
-
{ pattern: "^app\\.", enabled: true, description: "Application operations" },
|
|
759
|
-
{ pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
|
|
760
|
-
{ pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
|
|
761
|
-
],
|
|
762
|
-
ignore_patterns: [
|
|
763
|
-
{ pattern: "^test\\.", description: "Test utilities" },
|
|
764
|
-
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
765
|
-
{ pattern: "^health\\.", description: "Health checks" }
|
|
766
|
-
]
|
|
767
|
-
},
|
|
768
|
-
effect: {
|
|
769
|
-
auto_extract_metadata: true
|
|
770
|
-
}
|
|
771
|
-
};
|
|
817
|
+
function _resetConfigLoaderCache() {
|
|
772
818
|
}
|
|
773
819
|
async function loadConfigWithOptions(options = {}) {
|
|
774
|
-
const loadOptions = options.cacheTimeout !== void 0 ? { cacheTimeout: options.cacheTimeout } : void 0;
|
|
775
820
|
if (options.config) {
|
|
776
821
|
return loadConfigFromInline(options.config);
|
|
777
822
|
}
|
|
778
823
|
const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
|
|
779
824
|
if (envConfigPath) {
|
|
780
|
-
return loadConfig(envConfigPath
|
|
825
|
+
return loadConfig(envConfigPath);
|
|
781
826
|
}
|
|
782
827
|
if (options.configUrl) {
|
|
783
|
-
return loadConfig(options.configUrl
|
|
828
|
+
return loadConfig(options.configUrl);
|
|
784
829
|
}
|
|
785
830
|
if (options.configPath) {
|
|
786
|
-
return loadConfig(options.configPath
|
|
831
|
+
return loadConfig(options.configPath);
|
|
787
832
|
}
|
|
788
833
|
const { existsSync } = await import('fs');
|
|
789
834
|
const { join: join2 } = await import('path');
|
|
790
835
|
const defaultPath = join2(process.cwd(), "instrumentation.yaml");
|
|
791
836
|
if (existsSync(defaultPath)) {
|
|
792
|
-
return loadConfig(defaultPath
|
|
837
|
+
return loadConfig(defaultPath);
|
|
793
838
|
}
|
|
794
|
-
return
|
|
839
|
+
return defaultConfig;
|
|
795
840
|
}
|
|
796
841
|
|
|
797
842
|
// src/core/sdk-initializer.ts
|
|
@@ -1083,9 +1128,39 @@ function logInitialization(config, serviceName, serviceVersion, options, autoIns
|
|
|
1083
1128
|
logger.log(` - OTLP endpoint: ${endpoint}`);
|
|
1084
1129
|
logger.log("");
|
|
1085
1130
|
}
|
|
1131
|
+
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
1132
|
+
function validateOpenTelemetryApi() {
|
|
1133
|
+
try {
|
|
1134
|
+
require2.resolve("@opentelemetry/api");
|
|
1135
|
+
} catch {
|
|
1136
|
+
throw new Error(
|
|
1137
|
+
"@atrim/instrument-node requires @opentelemetry/api as a peer dependency.\n\nInstall it with:\n npm install @opentelemetry/api\n\nOr with your preferred package manager:\n pnpm add @opentelemetry/api\n yarn add @opentelemetry/api\n bun add @opentelemetry/api"
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
function validateEffectDependencies() {
|
|
1142
|
+
const packages = ["effect", "@effect/opentelemetry", "@effect/platform"];
|
|
1143
|
+
for (const pkg of packages) {
|
|
1144
|
+
try {
|
|
1145
|
+
require2.resolve(pkg);
|
|
1146
|
+
} catch {
|
|
1147
|
+
return false;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
return true;
|
|
1151
|
+
}
|
|
1152
|
+
var validateDependencies = effect.Effect.try({
|
|
1153
|
+
try: () => validateOpenTelemetryApi(),
|
|
1154
|
+
catch: (error) => new InitializationError2({
|
|
1155
|
+
reason: error instanceof Error ? error.message : "Dependency validation failed",
|
|
1156
|
+
cause: error
|
|
1157
|
+
})
|
|
1158
|
+
});
|
|
1159
|
+
effect.Effect.sync(() => validateEffectDependencies());
|
|
1086
1160
|
|
|
1087
1161
|
// src/api.ts
|
|
1088
1162
|
async function initializeInstrumentation(options = {}) {
|
|
1163
|
+
validateOpenTelemetryApi();
|
|
1089
1164
|
const sdk = await initializeSdk(options);
|
|
1090
1165
|
if (sdk) {
|
|
1091
1166
|
const config = await loadConfigWithOptions(options);
|
|
@@ -1102,6 +1177,7 @@ async function initializePatternMatchingOnly(options = {}) {
|
|
|
1102
1177
|
);
|
|
1103
1178
|
}
|
|
1104
1179
|
var initializeInstrumentationEffect = (options = {}) => effect.Effect.gen(function* () {
|
|
1180
|
+
yield* validateDependencies;
|
|
1105
1181
|
const sdk = yield* effect.Effect.tryPromise({
|
|
1106
1182
|
try: () => initializeSdk(options),
|
|
1107
1183
|
catch: (error) => new InitializationError2({
|