@atrim/instrument-node 0.7.1-dev.14fdea7.20260108224013 → 0.7.1-dev.14fdea7.20260108231415
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/package.json +2 -1
- package/target/dist/integrations/effect/auto/index.cjs +183 -119
- package/target/dist/integrations/effect/auto/index.cjs.map +1 -1
- package/target/dist/integrations/effect/auto/index.d.cts +79 -1
- package/target/dist/integrations/effect/auto/index.d.ts +79 -1
- package/target/dist/integrations/effect/auto/index.js +182 -120
- package/target/dist/integrations/effect/auto/index.js.map +1 -1
|
@@ -3,6 +3,84 @@ import * as OtelApi from '@opentelemetry/api';
|
|
|
3
3
|
import { AutoInstrumentationConfig, InstrumentationConfig } from '@atrim/instrument-core';
|
|
4
4
|
export { AutoInstrumentationConfig } from '@atrim/instrument-core';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Effect-Native Tracing Layer
|
|
8
|
+
*
|
|
9
|
+
* Uses @effect/opentelemetry's NodeSdk.layer for proper Effect integration.
|
|
10
|
+
* This provides automatic HTTP request tracing and Effect.withSpan() support.
|
|
11
|
+
*
|
|
12
|
+
* Requires @effect/opentelemetry peer dependency to be installed.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create a layer that provides Effect-native tracing via NodeSdk.layer
|
|
17
|
+
*
|
|
18
|
+
* This integrates with Effect's built-in tracing system, which means:
|
|
19
|
+
* - HTTP requests are automatically traced by @effect/platform
|
|
20
|
+
* - Effect.withSpan() creates proper OTel spans
|
|
21
|
+
* - Parent-child span relationships work correctly
|
|
22
|
+
* - No need to fork fibers for tracing to work
|
|
23
|
+
*
|
|
24
|
+
* Configuration is loaded from instrumentation.yaml (exporter_config section).
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { EffectTracingLive } from '@atrim/instrument-node/effect/auto'
|
|
29
|
+
*
|
|
30
|
+
* // HTTP requests automatically traced!
|
|
31
|
+
* const HttpLive = router.pipe(
|
|
32
|
+
* HttpServer.serve(),
|
|
33
|
+
* Layer.provide(ServerLive),
|
|
34
|
+
* Layer.provide(EffectTracingLive),
|
|
35
|
+
* )
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
declare const createEffectTracingLayer: () => Layer.Layer<never>;
|
|
39
|
+
/**
|
|
40
|
+
* Effect-native tracing layer using @effect/opentelemetry
|
|
41
|
+
*
|
|
42
|
+
* This is the **recommended** layer for Effect HTTP applications. It provides:
|
|
43
|
+
* - Automatic HTTP request tracing (built into @effect/platform)
|
|
44
|
+
* - Full Effect.withSpan() support for manual spans
|
|
45
|
+
* - Proper parent-child span relationships
|
|
46
|
+
* - No need to fork fibers manually
|
|
47
|
+
*
|
|
48
|
+
* Configuration is loaded from your instrumentation.yaml file.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```yaml
|
|
52
|
+
* # instrumentation.yaml
|
|
53
|
+
* effect:
|
|
54
|
+
* exporter_config:
|
|
55
|
+
* type: otlp # or 'console' for dev
|
|
56
|
+
* endpoint: http://localhost:4318
|
|
57
|
+
* headers:
|
|
58
|
+
* x-api-key: your-key
|
|
59
|
+
* processor: batch # or 'simple' for immediate export
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import { EffectTracingLive } from '@atrim/instrument-node/effect/auto'
|
|
65
|
+
* import { HttpRouter, HttpServer } from "@effect/platform"
|
|
66
|
+
* import { NodeHttpServer, NodeRuntime } from "@effect/platform-node"
|
|
67
|
+
*
|
|
68
|
+
* const router = HttpRouter.empty.pipe(
|
|
69
|
+
* HttpRouter.get("/", Effect.succeed(HttpServerResponse.text("Hello!"))),
|
|
70
|
+
* )
|
|
71
|
+
*
|
|
72
|
+
* const HttpLive = router.pipe(
|
|
73
|
+
* HttpServer.serve(),
|
|
74
|
+
* Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 })),
|
|
75
|
+
* Layer.provide(EffectTracingLive), // <- Just add this!
|
|
76
|
+
* )
|
|
77
|
+
*
|
|
78
|
+
* NodeRuntime.runMain(Layer.launch(HttpLive))
|
|
79
|
+
* // All HTTP requests now automatically traced!
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
declare const EffectTracingLive: Layer.Layer<never>;
|
|
83
|
+
|
|
6
84
|
/**
|
|
7
85
|
* Auto-Tracing Supervisor for Effect-TS
|
|
8
86
|
*
|
|
@@ -356,4 +434,4 @@ declare function inferSpanName(fiberId: number, sourceInfo: SourceInfo | undefin
|
|
|
356
434
|
*/
|
|
357
435
|
declare function sanitizeSpanName(name: string): string;
|
|
358
436
|
|
|
359
|
-
export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, FullAutoTracingLive, type SourceInfo, type TemplateVariables, createAutoTracingLayer, createAutoTracingSupervisor, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
|
|
437
|
+
export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, EffectTracingLive, FullAutoTracingLive, type SourceInfo, type TemplateVariables, createAutoTracingLayer, createAutoTracingSupervisor, createEffectTracingLayer, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
|
|
@@ -3,6 +3,84 @@ import * as OtelApi from '@opentelemetry/api';
|
|
|
3
3
|
import { AutoInstrumentationConfig, InstrumentationConfig } from '@atrim/instrument-core';
|
|
4
4
|
export { AutoInstrumentationConfig } from '@atrim/instrument-core';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Effect-Native Tracing Layer
|
|
8
|
+
*
|
|
9
|
+
* Uses @effect/opentelemetry's NodeSdk.layer for proper Effect integration.
|
|
10
|
+
* This provides automatic HTTP request tracing and Effect.withSpan() support.
|
|
11
|
+
*
|
|
12
|
+
* Requires @effect/opentelemetry peer dependency to be installed.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create a layer that provides Effect-native tracing via NodeSdk.layer
|
|
17
|
+
*
|
|
18
|
+
* This integrates with Effect's built-in tracing system, which means:
|
|
19
|
+
* - HTTP requests are automatically traced by @effect/platform
|
|
20
|
+
* - Effect.withSpan() creates proper OTel spans
|
|
21
|
+
* - Parent-child span relationships work correctly
|
|
22
|
+
* - No need to fork fibers for tracing to work
|
|
23
|
+
*
|
|
24
|
+
* Configuration is loaded from instrumentation.yaml (exporter_config section).
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { EffectTracingLive } from '@atrim/instrument-node/effect/auto'
|
|
29
|
+
*
|
|
30
|
+
* // HTTP requests automatically traced!
|
|
31
|
+
* const HttpLive = router.pipe(
|
|
32
|
+
* HttpServer.serve(),
|
|
33
|
+
* Layer.provide(ServerLive),
|
|
34
|
+
* Layer.provide(EffectTracingLive),
|
|
35
|
+
* )
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
declare const createEffectTracingLayer: () => Layer.Layer<never>;
|
|
39
|
+
/**
|
|
40
|
+
* Effect-native tracing layer using @effect/opentelemetry
|
|
41
|
+
*
|
|
42
|
+
* This is the **recommended** layer for Effect HTTP applications. It provides:
|
|
43
|
+
* - Automatic HTTP request tracing (built into @effect/platform)
|
|
44
|
+
* - Full Effect.withSpan() support for manual spans
|
|
45
|
+
* - Proper parent-child span relationships
|
|
46
|
+
* - No need to fork fibers manually
|
|
47
|
+
*
|
|
48
|
+
* Configuration is loaded from your instrumentation.yaml file.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```yaml
|
|
52
|
+
* # instrumentation.yaml
|
|
53
|
+
* effect:
|
|
54
|
+
* exporter_config:
|
|
55
|
+
* type: otlp # or 'console' for dev
|
|
56
|
+
* endpoint: http://localhost:4318
|
|
57
|
+
* headers:
|
|
58
|
+
* x-api-key: your-key
|
|
59
|
+
* processor: batch # or 'simple' for immediate export
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import { EffectTracingLive } from '@atrim/instrument-node/effect/auto'
|
|
65
|
+
* import { HttpRouter, HttpServer } from "@effect/platform"
|
|
66
|
+
* import { NodeHttpServer, NodeRuntime } from "@effect/platform-node"
|
|
67
|
+
*
|
|
68
|
+
* const router = HttpRouter.empty.pipe(
|
|
69
|
+
* HttpRouter.get("/", Effect.succeed(HttpServerResponse.text("Hello!"))),
|
|
70
|
+
* )
|
|
71
|
+
*
|
|
72
|
+
* const HttpLive = router.pipe(
|
|
73
|
+
* HttpServer.serve(),
|
|
74
|
+
* Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 })),
|
|
75
|
+
* Layer.provide(EffectTracingLive), // <- Just add this!
|
|
76
|
+
* )
|
|
77
|
+
*
|
|
78
|
+
* NodeRuntime.runMain(Layer.launch(HttpLive))
|
|
79
|
+
* // All HTTP requests now automatically traced!
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
declare const EffectTracingLive: Layer.Layer<never>;
|
|
83
|
+
|
|
6
84
|
/**
|
|
7
85
|
* Auto-Tracing Supervisor for Effect-TS
|
|
8
86
|
*
|
|
@@ -356,4 +434,4 @@ declare function inferSpanName(fiberId: number, sourceInfo: SourceInfo | undefin
|
|
|
356
434
|
*/
|
|
357
435
|
declare function sanitizeSpanName(name: string): string;
|
|
358
436
|
|
|
359
|
-
export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, FullAutoTracingLive, type SourceInfo, type TemplateVariables, createAutoTracingLayer, createAutoTracingSupervisor, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
|
|
437
|
+
export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, EffectTracingLive, FullAutoTracingLive, type SourceInfo, type TemplateVariables, createAutoTracingLayer, createAutoTracingSupervisor, createEffectTracingLayer, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { Data, Context, Effect, Layer, FiberRef, Option, Supervisor, FiberRefs, Exit } from 'effect';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import { NodeSdk } from '@effect/opentelemetry';
|
|
3
|
+
import { SimpleSpanProcessor, ConsoleSpanExporter, BatchSpanProcessor, BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
|
|
4
4
|
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
|
5
|
-
import { resourceFromAttributes } from '@opentelemetry/resources';
|
|
6
|
-
import { ATTR_SERVICE_VERSION, ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
|
|
7
5
|
import { FileSystem } from '@effect/platform/FileSystem';
|
|
8
6
|
import * as HttpClient from '@effect/platform/HttpClient';
|
|
9
7
|
import * as HttpClientRequest from '@effect/platform/HttpClientRequest';
|
|
10
8
|
import { parse } from 'yaml';
|
|
11
9
|
import { z } from 'zod';
|
|
10
|
+
import * as OtelApi from '@opentelemetry/api';
|
|
11
|
+
import { resourceFromAttributes } from '@opentelemetry/resources';
|
|
12
|
+
import { ATTR_SERVICE_VERSION, ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
|
|
12
13
|
import * as path from 'path';
|
|
13
14
|
|
|
14
15
|
var __defProp = Object.defineProperty;
|
|
@@ -466,121 +467,6 @@ var Logger = class {
|
|
|
466
467
|
}
|
|
467
468
|
};
|
|
468
469
|
var logger = new Logger();
|
|
469
|
-
var compiledRulesCache = /* @__PURE__ */ new WeakMap();
|
|
470
|
-
function compileNamingRules(rules) {
|
|
471
|
-
const cached = compiledRulesCache.get(rules);
|
|
472
|
-
if (cached) return cached;
|
|
473
|
-
const compiled = rules.map((rule) => ({
|
|
474
|
-
original: rule,
|
|
475
|
-
filePattern: rule.match.file ? new RegExp(rule.match.file) : void 0,
|
|
476
|
-
functionPattern: rule.match.function ? new RegExp(rule.match.function) : void 0,
|
|
477
|
-
modulePattern: rule.match.module ? new RegExp(rule.match.module) : void 0
|
|
478
|
-
}));
|
|
479
|
-
compiledRulesCache.set(rules, compiled);
|
|
480
|
-
return compiled;
|
|
481
|
-
}
|
|
482
|
-
function extractModuleName(filePath) {
|
|
483
|
-
const basename2 = path.basename(filePath, path.extname(filePath));
|
|
484
|
-
return basename2.replace(/\.(service|controller|handler|util|helper|model|repo|repository)$/i, "").replace(/(Service|Controller|Handler|Util|Helper|Model|Repo|Repository)$/i, "");
|
|
485
|
-
}
|
|
486
|
-
function applyTemplate(template, variables, matchGroups) {
|
|
487
|
-
let result = template;
|
|
488
|
-
for (const [key, value] of Object.entries(variables)) {
|
|
489
|
-
result = result.replace(new RegExp(`\\{${key}\\}`, "g"), value);
|
|
490
|
-
}
|
|
491
|
-
if (matchGroups) {
|
|
492
|
-
result = result.replace(
|
|
493
|
-
/\{match:(\w+):(\d+)\}/g,
|
|
494
|
-
(_fullMatch, field, index) => {
|
|
495
|
-
const groups = matchGroups.get(field);
|
|
496
|
-
const idx = parseInt(index, 10);
|
|
497
|
-
if (groups && groups[idx]) {
|
|
498
|
-
return groups[idx];
|
|
499
|
-
}
|
|
500
|
-
return "";
|
|
501
|
-
}
|
|
502
|
-
);
|
|
503
|
-
}
|
|
504
|
-
return result;
|
|
505
|
-
}
|
|
506
|
-
function findMatchingRule(sourceInfo, config) {
|
|
507
|
-
const rules = config.span_naming?.rules;
|
|
508
|
-
if (!rules || rules.length === 0) return void 0;
|
|
509
|
-
const compiledRules = compileNamingRules(rules);
|
|
510
|
-
for (const rule of compiledRules) {
|
|
511
|
-
const matchGroups = /* @__PURE__ */ new Map();
|
|
512
|
-
let allMatched = true;
|
|
513
|
-
if (rule.filePattern) {
|
|
514
|
-
if (sourceInfo?.file) {
|
|
515
|
-
const match = sourceInfo.file.match(rule.filePattern);
|
|
516
|
-
if (match) {
|
|
517
|
-
matchGroups.set("file", match.slice(1));
|
|
518
|
-
} else {
|
|
519
|
-
allMatched = false;
|
|
520
|
-
}
|
|
521
|
-
} else {
|
|
522
|
-
allMatched = false;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
if (rule.functionPattern && allMatched) {
|
|
526
|
-
if (sourceInfo?.function) {
|
|
527
|
-
const match = sourceInfo.function.match(rule.functionPattern);
|
|
528
|
-
if (match) {
|
|
529
|
-
matchGroups.set("function", match.slice(1));
|
|
530
|
-
} else {
|
|
531
|
-
allMatched = false;
|
|
532
|
-
}
|
|
533
|
-
} else {
|
|
534
|
-
allMatched = false;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
if (rule.modulePattern && allMatched) {
|
|
538
|
-
const moduleName = sourceInfo?.file ? extractModuleName(sourceInfo.file) : "";
|
|
539
|
-
if (moduleName) {
|
|
540
|
-
const match = moduleName.match(rule.modulePattern);
|
|
541
|
-
if (match) {
|
|
542
|
-
matchGroups.set("module", match.slice(1));
|
|
543
|
-
} else {
|
|
544
|
-
allMatched = false;
|
|
545
|
-
}
|
|
546
|
-
} else {
|
|
547
|
-
allMatched = false;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
if (allMatched) {
|
|
551
|
-
return { rule, matchGroups };
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
return void 0;
|
|
555
|
-
}
|
|
556
|
-
function inferSpanName(fiberId, sourceInfo, config) {
|
|
557
|
-
const variables = {
|
|
558
|
-
fiber_id: String(fiberId),
|
|
559
|
-
function: sourceInfo?.function || "anonymous",
|
|
560
|
-
module: sourceInfo?.file ? extractModuleName(sourceInfo.file) : "unknown",
|
|
561
|
-
file: sourceInfo?.file || "unknown",
|
|
562
|
-
line: sourceInfo?.line ? String(sourceInfo.line) : "0",
|
|
563
|
-
operator: "gen"
|
|
564
|
-
// Default operator, could be enhanced with more context
|
|
565
|
-
};
|
|
566
|
-
const match = findMatchingRule(sourceInfo, config);
|
|
567
|
-
if (match) {
|
|
568
|
-
return applyTemplate(match.rule.original.name, variables, match.matchGroups);
|
|
569
|
-
}
|
|
570
|
-
const defaultTemplate = config.span_naming?.default || "effect.fiber.{fiber_id}";
|
|
571
|
-
return applyTemplate(defaultTemplate, variables);
|
|
572
|
-
}
|
|
573
|
-
function sanitizeSpanName(name) {
|
|
574
|
-
if (!name) return "effect.fiber.unknown";
|
|
575
|
-
let sanitized = name.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
576
|
-
sanitized = sanitized.replace(/_+/g, "_");
|
|
577
|
-
sanitized = sanitized.replace(/^_+|_+$/g, "");
|
|
578
|
-
if (!sanitized) return "effect.fiber.unknown";
|
|
579
|
-
if (sanitized.length > 256) {
|
|
580
|
-
sanitized = sanitized.substring(0, 256);
|
|
581
|
-
}
|
|
582
|
-
return sanitized;
|
|
583
|
-
}
|
|
584
470
|
async function loadFromFile(filePath) {
|
|
585
471
|
const { readFile } = await import('fs/promises');
|
|
586
472
|
const content = await readFile(filePath, "utf-8");
|
|
@@ -701,6 +587,182 @@ var loadFullConfig = (options) => Effect.gen(function* () {
|
|
|
701
587
|
return config;
|
|
702
588
|
});
|
|
703
589
|
|
|
590
|
+
// src/integrations/effect/auto/effect-tracing.ts
|
|
591
|
+
var createEffectTracingLayer = () => {
|
|
592
|
+
return Layer.unwrapEffect(
|
|
593
|
+
Effect.gen(function* () {
|
|
594
|
+
const config = yield* loadFullConfig();
|
|
595
|
+
const serviceName = process.env.OTEL_SERVICE_NAME || "effect-service";
|
|
596
|
+
const serviceVersion = process.env.npm_package_version || "1.0.0";
|
|
597
|
+
const exporterConfig = config.effect?.exporter_config ?? {
|
|
598
|
+
type: "otlp",
|
|
599
|
+
processor: "batch"
|
|
600
|
+
};
|
|
601
|
+
logger.log("@atrim/auto-trace: Effect-native tracing enabled");
|
|
602
|
+
logger.log(` Service: ${serviceName}`);
|
|
603
|
+
logger.log(` Exporter: ${exporterConfig.type}`);
|
|
604
|
+
if (exporterConfig.type === "none") {
|
|
605
|
+
logger.log('@atrim/auto-trace: Exporter type is "none", using empty layer');
|
|
606
|
+
return Layer.empty;
|
|
607
|
+
}
|
|
608
|
+
const createSpanProcessor = () => {
|
|
609
|
+
if (exporterConfig.type === "console") {
|
|
610
|
+
logger.log("@atrim/auto-trace: Using ConsoleSpanExporter with SimpleSpanProcessor");
|
|
611
|
+
return new SimpleSpanProcessor(new ConsoleSpanExporter());
|
|
612
|
+
}
|
|
613
|
+
const endpoint = exporterConfig.endpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
|
|
614
|
+
logger.log(`@atrim/auto-trace: Using OTLPTraceExporter (${endpoint})`);
|
|
615
|
+
const otlpConfig = {
|
|
616
|
+
url: `${endpoint}/v1/traces`
|
|
617
|
+
};
|
|
618
|
+
if (exporterConfig.headers) {
|
|
619
|
+
otlpConfig.headers = exporterConfig.headers;
|
|
620
|
+
logger.log(`@atrim/auto-trace: Using custom headers: ${Object.keys(exporterConfig.headers).join(", ")}`);
|
|
621
|
+
}
|
|
622
|
+
const exporter = new OTLPTraceExporter(otlpConfig);
|
|
623
|
+
if (exporterConfig.processor === "simple") {
|
|
624
|
+
logger.log("@atrim/auto-trace: Using SimpleSpanProcessor");
|
|
625
|
+
return new SimpleSpanProcessor(exporter);
|
|
626
|
+
}
|
|
627
|
+
const batchConfig = exporterConfig.batch ?? {
|
|
628
|
+
scheduled_delay_millis: 1e3,
|
|
629
|
+
max_export_batch_size: 100
|
|
630
|
+
};
|
|
631
|
+
logger.log("@atrim/auto-trace: Using BatchSpanProcessor");
|
|
632
|
+
return new BatchSpanProcessor(exporter, {
|
|
633
|
+
scheduledDelayMillis: batchConfig.scheduled_delay_millis,
|
|
634
|
+
maxExportBatchSize: batchConfig.max_export_batch_size
|
|
635
|
+
});
|
|
636
|
+
};
|
|
637
|
+
const sdkLayer = NodeSdk.layer(() => ({
|
|
638
|
+
resource: {
|
|
639
|
+
serviceName,
|
|
640
|
+
serviceVersion
|
|
641
|
+
},
|
|
642
|
+
spanProcessor: createSpanProcessor()
|
|
643
|
+
}));
|
|
644
|
+
logger.log("@atrim/auto-trace: NodeSdk layer created - HTTP requests will be auto-traced");
|
|
645
|
+
return Layer.discard(sdkLayer);
|
|
646
|
+
})
|
|
647
|
+
);
|
|
648
|
+
};
|
|
649
|
+
var EffectTracingLive = createEffectTracingLayer();
|
|
650
|
+
var compiledRulesCache = /* @__PURE__ */ new WeakMap();
|
|
651
|
+
function compileNamingRules(rules) {
|
|
652
|
+
const cached = compiledRulesCache.get(rules);
|
|
653
|
+
if (cached) return cached;
|
|
654
|
+
const compiled = rules.map((rule) => ({
|
|
655
|
+
original: rule,
|
|
656
|
+
filePattern: rule.match.file ? new RegExp(rule.match.file) : void 0,
|
|
657
|
+
functionPattern: rule.match.function ? new RegExp(rule.match.function) : void 0,
|
|
658
|
+
modulePattern: rule.match.module ? new RegExp(rule.match.module) : void 0
|
|
659
|
+
}));
|
|
660
|
+
compiledRulesCache.set(rules, compiled);
|
|
661
|
+
return compiled;
|
|
662
|
+
}
|
|
663
|
+
function extractModuleName(filePath) {
|
|
664
|
+
const basename2 = path.basename(filePath, path.extname(filePath));
|
|
665
|
+
return basename2.replace(/\.(service|controller|handler|util|helper|model|repo|repository)$/i, "").replace(/(Service|Controller|Handler|Util|Helper|Model|Repo|Repository)$/i, "");
|
|
666
|
+
}
|
|
667
|
+
function applyTemplate(template, variables, matchGroups) {
|
|
668
|
+
let result = template;
|
|
669
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
670
|
+
result = result.replace(new RegExp(`\\{${key}\\}`, "g"), value);
|
|
671
|
+
}
|
|
672
|
+
if (matchGroups) {
|
|
673
|
+
result = result.replace(
|
|
674
|
+
/\{match:(\w+):(\d+)\}/g,
|
|
675
|
+
(_fullMatch, field, index) => {
|
|
676
|
+
const groups = matchGroups.get(field);
|
|
677
|
+
const idx = parseInt(index, 10);
|
|
678
|
+
if (groups && groups[idx]) {
|
|
679
|
+
return groups[idx];
|
|
680
|
+
}
|
|
681
|
+
return "";
|
|
682
|
+
}
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
return result;
|
|
686
|
+
}
|
|
687
|
+
function findMatchingRule(sourceInfo, config) {
|
|
688
|
+
const rules = config.span_naming?.rules;
|
|
689
|
+
if (!rules || rules.length === 0) return void 0;
|
|
690
|
+
const compiledRules = compileNamingRules(rules);
|
|
691
|
+
for (const rule of compiledRules) {
|
|
692
|
+
const matchGroups = /* @__PURE__ */ new Map();
|
|
693
|
+
let allMatched = true;
|
|
694
|
+
if (rule.filePattern) {
|
|
695
|
+
if (sourceInfo?.file) {
|
|
696
|
+
const match = sourceInfo.file.match(rule.filePattern);
|
|
697
|
+
if (match) {
|
|
698
|
+
matchGroups.set("file", match.slice(1));
|
|
699
|
+
} else {
|
|
700
|
+
allMatched = false;
|
|
701
|
+
}
|
|
702
|
+
} else {
|
|
703
|
+
allMatched = false;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
if (rule.functionPattern && allMatched) {
|
|
707
|
+
if (sourceInfo?.function) {
|
|
708
|
+
const match = sourceInfo.function.match(rule.functionPattern);
|
|
709
|
+
if (match) {
|
|
710
|
+
matchGroups.set("function", match.slice(1));
|
|
711
|
+
} else {
|
|
712
|
+
allMatched = false;
|
|
713
|
+
}
|
|
714
|
+
} else {
|
|
715
|
+
allMatched = false;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (rule.modulePattern && allMatched) {
|
|
719
|
+
const moduleName = sourceInfo?.file ? extractModuleName(sourceInfo.file) : "";
|
|
720
|
+
if (moduleName) {
|
|
721
|
+
const match = moduleName.match(rule.modulePattern);
|
|
722
|
+
if (match) {
|
|
723
|
+
matchGroups.set("module", match.slice(1));
|
|
724
|
+
} else {
|
|
725
|
+
allMatched = false;
|
|
726
|
+
}
|
|
727
|
+
} else {
|
|
728
|
+
allMatched = false;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
if (allMatched) {
|
|
732
|
+
return { rule, matchGroups };
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return void 0;
|
|
736
|
+
}
|
|
737
|
+
function inferSpanName(fiberId, sourceInfo, config) {
|
|
738
|
+
const variables = {
|
|
739
|
+
fiber_id: String(fiberId),
|
|
740
|
+
function: sourceInfo?.function || "anonymous",
|
|
741
|
+
module: sourceInfo?.file ? extractModuleName(sourceInfo.file) : "unknown",
|
|
742
|
+
file: sourceInfo?.file || "unknown",
|
|
743
|
+
line: sourceInfo?.line ? String(sourceInfo.line) : "0",
|
|
744
|
+
operator: "gen"
|
|
745
|
+
// Default operator, could be enhanced with more context
|
|
746
|
+
};
|
|
747
|
+
const match = findMatchingRule(sourceInfo, config);
|
|
748
|
+
if (match) {
|
|
749
|
+
return applyTemplate(match.rule.original.name, variables, match.matchGroups);
|
|
750
|
+
}
|
|
751
|
+
const defaultTemplate = config.span_naming?.default || "effect.fiber.{fiber_id}";
|
|
752
|
+
return applyTemplate(defaultTemplate, variables);
|
|
753
|
+
}
|
|
754
|
+
function sanitizeSpanName(name) {
|
|
755
|
+
if (!name) return "effect.fiber.unknown";
|
|
756
|
+
let sanitized = name.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
757
|
+
sanitized = sanitized.replace(/_+/g, "_");
|
|
758
|
+
sanitized = sanitized.replace(/^_+|_+$/g, "");
|
|
759
|
+
if (!sanitized) return "effect.fiber.unknown";
|
|
760
|
+
if (sanitized.length > 256) {
|
|
761
|
+
sanitized = sanitized.substring(0, 256);
|
|
762
|
+
}
|
|
763
|
+
return sanitized;
|
|
764
|
+
}
|
|
765
|
+
|
|
704
766
|
// src/integrations/effect/auto/supervisor.ts
|
|
705
767
|
var AutoTracingEnabled = FiberRef.unsafeMake(true);
|
|
706
768
|
var AutoTracingSpanName = FiberRef.unsafeMake(Option.none());
|
|
@@ -1069,6 +1131,6 @@ var createFullAutoTracingLayer = () => {
|
|
|
1069
1131
|
};
|
|
1070
1132
|
var FullAutoTracingLive = createFullAutoTracingLayer();
|
|
1071
1133
|
|
|
1072
|
-
export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, FullAutoTracingLive, createAutoTracingLayer, createAutoTracingSupervisor, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
|
|
1134
|
+
export { AutoTracingConfig, AutoTracingConfigLayer, AutoTracingConfigLive, AutoTracingEnabled, AutoTracingLive, AutoTracingSpanName, AutoTracingSupervisor, EffectTracingLive, FullAutoTracingLive, createAutoTracingLayer, createAutoTracingSupervisor, createEffectTracingLayer, createFullAutoTracingLayer, defaultAutoTracingConfig, inferSpanName, loadAutoTracingConfig, loadAutoTracingConfigSync, sanitizeSpanName, setSpanName, withAutoTracing, withoutAutoTracing };
|
|
1073
1135
|
//# sourceMappingURL=index.js.map
|
|
1074
1136
|
//# sourceMappingURL=index.js.map
|