@atrim/instrument-node 0.5.0 → 0.5.1-21bb978-20260105202350
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 +73 -274
- package/package.json +20 -19
- package/target/dist/index.cjs +155 -60
- 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 +154 -60
- package/target/dist/index.js.map +1 -1
- package/target/dist/integrations/effect/index.cjs +346 -130
- package/target/dist/integrations/effect/index.cjs.map +1 -1
- package/target/dist/integrations/effect/index.d.cts +335 -36
- package/target/dist/integrations/effect/index.d.ts +335 -36
- package/target/dist/integrations/effect/index.js +340 -134
- package/target/dist/integrations/effect/index.js.map +1 -1
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { Data, Context, Effect, Layer, FiberSet as FiberSet$1, Tracer } from 'effect';
|
|
1
|
+
import { Data, Context, Effect, Layer, FiberSet as FiberSet$1, Fiber, Option, FiberId, Tracer as Tracer$1 } from 'effect';
|
|
2
|
+
import * as Tracer from '@effect/opentelemetry/Tracer';
|
|
3
|
+
import * as Resource from '@effect/opentelemetry/Resource';
|
|
2
4
|
import * as Otlp from '@effect/opentelemetry/Otlp';
|
|
3
5
|
import { FetchHttpClient } from '@effect/platform';
|
|
4
|
-
import {
|
|
6
|
+
import { trace, context, TraceFlags } from '@opentelemetry/api';
|
|
7
|
+
import { TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS, ATTR_TELEMETRY_SDK_NAME, ATTR_TELEMETRY_SDK_LANGUAGE } from '@opentelemetry/semantic-conventions';
|
|
5
8
|
import { FileSystem } from '@effect/platform/FileSystem';
|
|
6
9
|
import * as HttpClient from '@effect/platform/HttpClient';
|
|
7
10
|
import * as HttpClientRequest from '@effect/platform/HttpClientRequest';
|
|
8
11
|
import { parse } from 'yaml';
|
|
9
12
|
import { z } from 'zod';
|
|
10
|
-
import { NodeContext } from '@effect/platform-node';
|
|
11
13
|
|
|
12
14
|
// src/integrations/effect/effect-tracer.ts
|
|
13
15
|
var __defProp = Object.defineProperty;
|
|
@@ -46,7 +48,20 @@ var HttpFilteringConfigSchema = z.object({
|
|
|
46
48
|
// Patterns to ignore for incoming HTTP requests (string patterns only in YAML)
|
|
47
49
|
ignore_incoming_paths: z.array(z.string()).optional(),
|
|
48
50
|
// Require parent span for outgoing requests (prevents root spans for HTTP calls)
|
|
49
|
-
require_parent_for_outgoing_spans: z.boolean().optional()
|
|
51
|
+
require_parent_for_outgoing_spans: z.boolean().optional(),
|
|
52
|
+
// Trace context propagation configuration
|
|
53
|
+
// Controls which cross-origin requests receive W3C Trace Context headers (traceparent, tracestate)
|
|
54
|
+
propagate_trace_context: z.object({
|
|
55
|
+
// Strategy for trace propagation
|
|
56
|
+
// - "all": Propagate to all cross-origin requests (may cause CORS errors)
|
|
57
|
+
// - "none": Never propagate trace headers
|
|
58
|
+
// - "same-origin": Only propagate to same-origin requests (default, safe)
|
|
59
|
+
// - "patterns": Propagate based on include_urls patterns
|
|
60
|
+
strategy: z.enum(["all", "none", "same-origin", "patterns"]).default("same-origin"),
|
|
61
|
+
// URL patterns to include when strategy is "patterns"
|
|
62
|
+
// Supports regex patterns (e.g., "^https://api\\.myapp\\.com")
|
|
63
|
+
include_urls: z.array(z.string()).optional()
|
|
64
|
+
}).optional()
|
|
50
65
|
});
|
|
51
66
|
var InstrumentationConfigSchema = z.object({
|
|
52
67
|
version: z.string(),
|
|
@@ -58,11 +73,56 @@ var InstrumentationConfigSchema = z.object({
|
|
|
58
73
|
ignore_patterns: z.array(PatternConfigSchema)
|
|
59
74
|
}),
|
|
60
75
|
effect: z.object({
|
|
76
|
+
// Enable/disable Effect tracing entirely
|
|
77
|
+
// When false, EffectInstrumentationLive returns Layer.empty
|
|
78
|
+
enabled: z.boolean().default(true),
|
|
79
|
+
// Exporter mode:
|
|
80
|
+
// - "unified": Use global TracerProvider from Node SDK (recommended, enables filtering)
|
|
81
|
+
// - "standalone": Use Effect's own OTLP exporter (bypasses Node SDK filtering)
|
|
82
|
+
exporter: z.enum(["unified", "standalone"]).default("unified"),
|
|
61
83
|
auto_extract_metadata: z.boolean(),
|
|
84
|
+
// Auto-bridge OpenTelemetry context to Effect spans
|
|
85
|
+
// When true, Effect spans automatically become children of the active OTel span
|
|
86
|
+
// (e.g., HTTP request span from auto-instrumentation)
|
|
87
|
+
// This is essential for proper trace hierarchy when using Effect with HTTP frameworks
|
|
88
|
+
auto_bridge_context: z.boolean().default(true),
|
|
62
89
|
auto_isolation: AutoIsolationConfigSchema.optional()
|
|
63
90
|
}).optional(),
|
|
64
91
|
http: HttpFilteringConfigSchema.optional()
|
|
65
92
|
});
|
|
93
|
+
var defaultConfig = {
|
|
94
|
+
version: "1.0",
|
|
95
|
+
instrumentation: {
|
|
96
|
+
enabled: true,
|
|
97
|
+
logging: "on",
|
|
98
|
+
description: "Default instrumentation configuration",
|
|
99
|
+
instrument_patterns: [
|
|
100
|
+
{ pattern: "^app\\.", enabled: true, description: "Application operations" },
|
|
101
|
+
{ pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
|
|
102
|
+
{ pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
|
|
103
|
+
],
|
|
104
|
+
ignore_patterns: [
|
|
105
|
+
{ pattern: "^test\\.", description: "Test utilities" },
|
|
106
|
+
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
107
|
+
{ pattern: "^health\\.", description: "Health checks" }
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
effect: {
|
|
111
|
+
enabled: true,
|
|
112
|
+
exporter: "unified",
|
|
113
|
+
auto_extract_metadata: true,
|
|
114
|
+
auto_bridge_context: true
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
function parseAndValidateConfig(content) {
|
|
118
|
+
let parsed;
|
|
119
|
+
if (typeof content === "string") {
|
|
120
|
+
parsed = parse(content);
|
|
121
|
+
} else {
|
|
122
|
+
parsed = content;
|
|
123
|
+
}
|
|
124
|
+
return InstrumentationConfigSchema.parse(parsed);
|
|
125
|
+
}
|
|
66
126
|
(class extends Data.TaggedError("ConfigError") {
|
|
67
127
|
get message() {
|
|
68
128
|
return this.reason;
|
|
@@ -240,7 +300,7 @@ var makeConfigLoader = Effect.gen(function* () {
|
|
|
240
300
|
})
|
|
241
301
|
});
|
|
242
302
|
});
|
|
243
|
-
|
|
303
|
+
Layer.effect(ConfigLoader, makeConfigLoader);
|
|
244
304
|
var PatternMatcher = class {
|
|
245
305
|
constructor(config) {
|
|
246
306
|
__publicField(this, "ignorePatterns", []);
|
|
@@ -388,83 +448,58 @@ var Logger = class {
|
|
|
388
448
|
}
|
|
389
449
|
};
|
|
390
450
|
var logger = new Logger();
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
);
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
}).pipe(Effect.provide(NodeConfigLoaderLive))
|
|
401
|
-
);
|
|
451
|
+
async function loadFromFile(filePath) {
|
|
452
|
+
const { readFile } = await import('fs/promises');
|
|
453
|
+
const content = await readFile(filePath, "utf-8");
|
|
454
|
+
return parseAndValidateConfig(content);
|
|
455
|
+
}
|
|
456
|
+
async function loadFromUrl(url) {
|
|
457
|
+
const response = await fetch(url);
|
|
458
|
+
if (!response.ok) {
|
|
459
|
+
throw new Error(`Failed to fetch config from ${url}: ${response.statusText}`);
|
|
402
460
|
}
|
|
403
|
-
|
|
461
|
+
const content = await response.text();
|
|
462
|
+
return parseAndValidateConfig(content);
|
|
404
463
|
}
|
|
405
|
-
async function loadConfig(uri,
|
|
406
|
-
if (
|
|
407
|
-
|
|
408
|
-
const loader2 = yield* ConfigLoader;
|
|
409
|
-
return yield* loader2.loadFromUri(uri);
|
|
410
|
-
});
|
|
411
|
-
return Effect.runPromise(program.pipe(Effect.provide(NodeConfigLoaderLive)));
|
|
464
|
+
async function loadConfig(uri, _options) {
|
|
465
|
+
if (uri.startsWith("http://") || uri.startsWith("https://")) {
|
|
466
|
+
return loadFromUrl(uri);
|
|
412
467
|
}
|
|
413
|
-
|
|
414
|
-
|
|
468
|
+
if (uri.startsWith("file://")) {
|
|
469
|
+
const filePath = uri.slice(7);
|
|
470
|
+
return loadFromFile(filePath);
|
|
471
|
+
}
|
|
472
|
+
return loadFromFile(uri);
|
|
415
473
|
}
|
|
416
474
|
async function loadConfigFromInline(content) {
|
|
417
|
-
|
|
418
|
-
return Effect.runPromise(loader.loadFromInline(content));
|
|
419
|
-
}
|
|
420
|
-
function getDefaultConfig() {
|
|
421
|
-
return {
|
|
422
|
-
version: "1.0",
|
|
423
|
-
instrumentation: {
|
|
424
|
-
enabled: true,
|
|
425
|
-
logging: "on",
|
|
426
|
-
description: "Default instrumentation configuration",
|
|
427
|
-
instrument_patterns: [
|
|
428
|
-
{ pattern: "^app\\.", enabled: true, description: "Application operations" },
|
|
429
|
-
{ pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
|
|
430
|
-
{ pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
|
|
431
|
-
],
|
|
432
|
-
ignore_patterns: [
|
|
433
|
-
{ pattern: "^test\\.", description: "Test utilities" },
|
|
434
|
-
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
435
|
-
{ pattern: "^health\\.", description: "Health checks" }
|
|
436
|
-
]
|
|
437
|
-
},
|
|
438
|
-
effect: {
|
|
439
|
-
auto_extract_metadata: true
|
|
440
|
-
}
|
|
441
|
-
};
|
|
475
|
+
return parseAndValidateConfig(content);
|
|
442
476
|
}
|
|
443
477
|
async function loadConfigWithOptions(options = {}) {
|
|
444
|
-
const loadOptions = options.cacheTimeout !== void 0 ? { cacheTimeout: options.cacheTimeout } : void 0;
|
|
445
478
|
if (options.config) {
|
|
446
479
|
return loadConfigFromInline(options.config);
|
|
447
480
|
}
|
|
448
481
|
const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
|
|
449
482
|
if (envConfigPath) {
|
|
450
|
-
return loadConfig(envConfigPath
|
|
483
|
+
return loadConfig(envConfigPath);
|
|
451
484
|
}
|
|
452
485
|
if (options.configUrl) {
|
|
453
|
-
return loadConfig(options.configUrl
|
|
486
|
+
return loadConfig(options.configUrl);
|
|
454
487
|
}
|
|
455
488
|
if (options.configPath) {
|
|
456
|
-
return loadConfig(options.configPath
|
|
489
|
+
return loadConfig(options.configPath);
|
|
457
490
|
}
|
|
458
491
|
const { existsSync } = await import('fs');
|
|
459
492
|
const { join } = await import('path');
|
|
460
493
|
const defaultPath = join(process.cwd(), "instrumentation.yaml");
|
|
461
494
|
if (existsSync(defaultPath)) {
|
|
462
|
-
return loadConfig(defaultPath
|
|
495
|
+
return loadConfig(defaultPath);
|
|
463
496
|
}
|
|
464
|
-
return
|
|
497
|
+
return defaultConfig;
|
|
465
498
|
}
|
|
466
499
|
|
|
467
500
|
// src/integrations/effect/effect-tracer.ts
|
|
501
|
+
var SDK_NAME = "@effect/opentelemetry";
|
|
502
|
+
var ATTR_TELEMETRY_EXPORTER_MODE = "telemetry.exporter.mode";
|
|
468
503
|
function createEffectInstrumentation(options = {}) {
|
|
469
504
|
return Layer.unwrapEffect(
|
|
470
505
|
Effect.gen(function* () {
|
|
@@ -475,106 +510,277 @@ function createEffectInstrumentation(options = {}) {
|
|
|
475
510
|
message: error instanceof Error ? error.message : String(error)
|
|
476
511
|
})
|
|
477
512
|
});
|
|
513
|
+
const effectEnabled = process.env.OTEL_EFFECT_ENABLED !== "false" && (config.effect?.enabled ?? true);
|
|
514
|
+
if (!effectEnabled) {
|
|
515
|
+
logger.log("@atrim/instrumentation/effect: Effect tracing disabled via config");
|
|
516
|
+
return Layer.empty;
|
|
517
|
+
}
|
|
478
518
|
yield* Effect.sync(() => {
|
|
479
519
|
const loggingLevel = config.instrumentation.logging || "on";
|
|
480
520
|
logger.setLevel(loggingLevel);
|
|
481
521
|
});
|
|
482
522
|
yield* Effect.sync(() => initializePatternMatcher(config));
|
|
483
|
-
const otlpEndpoint = options.otlpEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
|
|
484
523
|
const serviceName = options.serviceName || process.env.OTEL_SERVICE_NAME || "effect-service";
|
|
485
524
|
const serviceVersion = options.serviceVersion || process.env.npm_package_version || "1.0.0";
|
|
486
|
-
const
|
|
487
|
-
const
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
525
|
+
const exporterMode = options.exporterMode ?? config.effect?.exporter ?? "unified";
|
|
526
|
+
const resourceAttributes = {
|
|
527
|
+
"platform.component": "effect",
|
|
528
|
+
[ATTR_TELEMETRY_SDK_LANGUAGE]: TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
|
|
529
|
+
[ATTR_TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
530
|
+
[ATTR_TELEMETRY_EXPORTER_MODE]: exporterMode
|
|
531
|
+
};
|
|
532
|
+
if (exporterMode === "standalone") {
|
|
533
|
+
const otlpEndpoint = options.otlpEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
|
|
534
|
+
logger.log("Effect OpenTelemetry instrumentation (standalone)");
|
|
535
|
+
logger.log(` Service: ${serviceName}`);
|
|
536
|
+
logger.log(` Endpoint: ${otlpEndpoint}`);
|
|
537
|
+
logger.log(" WARNING: Standalone mode bypasses Node SDK filtering");
|
|
538
|
+
return Otlp.layer({
|
|
539
|
+
baseUrl: otlpEndpoint,
|
|
540
|
+
resource: {
|
|
541
|
+
serviceName,
|
|
542
|
+
serviceVersion,
|
|
543
|
+
attributes: resourceAttributes
|
|
544
|
+
},
|
|
545
|
+
// Bridge Effect context to OpenTelemetry global context
|
|
546
|
+
tracerContext: (f, span) => {
|
|
547
|
+
if (span._tag !== "Span") {
|
|
548
|
+
return f();
|
|
549
|
+
}
|
|
550
|
+
const spanContext = {
|
|
551
|
+
traceId: span.traceId,
|
|
552
|
+
spanId: span.spanId,
|
|
553
|
+
traceFlags: span.sampled ? TraceFlags.SAMPLED : TraceFlags.NONE
|
|
554
|
+
};
|
|
555
|
+
const otelSpan = trace.wrapSpanContext(spanContext);
|
|
556
|
+
return context.with(trace.setSpan(context.active(), otelSpan), f);
|
|
509
557
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
558
|
+
}).pipe(Layer.provide(FetchHttpClient.layer));
|
|
559
|
+
} else {
|
|
560
|
+
logger.log("Effect OpenTelemetry instrumentation (unified)");
|
|
561
|
+
logger.log(` Service: ${serviceName}`);
|
|
562
|
+
logger.log(" Using global TracerProvider for span export");
|
|
563
|
+
return Tracer.layerGlobal.pipe(
|
|
564
|
+
Layer.provide(
|
|
565
|
+
Resource.layer({
|
|
566
|
+
serviceName,
|
|
567
|
+
serviceVersion,
|
|
568
|
+
attributes: resourceAttributes
|
|
569
|
+
})
|
|
570
|
+
)
|
|
571
|
+
);
|
|
521
572
|
}
|
|
522
|
-
return otlpLayer;
|
|
523
573
|
})
|
|
524
574
|
).pipe(Layer.orDie);
|
|
525
575
|
}
|
|
526
576
|
var EffectInstrumentationLive = Effect.sync(() => {
|
|
527
|
-
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
|
|
528
577
|
const serviceName = process.env.OTEL_SERVICE_NAME || "effect-service";
|
|
529
578
|
const serviceVersion = process.env.npm_package_version || "1.0.0";
|
|
530
579
|
logger.minimal(`@atrim/instrumentation/effect: Effect tracing enabled (${serviceName})`);
|
|
531
|
-
logger.log("
|
|
532
|
-
logger.log(`
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
return f();
|
|
548
|
-
}
|
|
549
|
-
const spanContext = {
|
|
550
|
-
traceId: span.traceId,
|
|
551
|
-
spanId: span.spanId,
|
|
552
|
-
traceFlags: span.sampled ? TraceFlags.SAMPLED : TraceFlags.NONE
|
|
553
|
-
};
|
|
554
|
-
const otelSpan = trace.wrapSpanContext(spanContext);
|
|
555
|
-
return context.with(trace.setSpan(context.active(), otelSpan), f);
|
|
556
|
-
}
|
|
557
|
-
}).pipe(Layer.provide(FetchHttpClient.layer));
|
|
580
|
+
logger.log("Effect OpenTelemetry tracer (unified)");
|
|
581
|
+
logger.log(` Service: ${serviceName}`);
|
|
582
|
+
return Tracer.layerGlobal.pipe(
|
|
583
|
+
Layer.provide(
|
|
584
|
+
Resource.layer({
|
|
585
|
+
serviceName,
|
|
586
|
+
serviceVersion,
|
|
587
|
+
attributes: {
|
|
588
|
+
"platform.component": "effect",
|
|
589
|
+
[ATTR_TELEMETRY_SDK_LANGUAGE]: TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
|
|
590
|
+
[ATTR_TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
591
|
+
[ATTR_TELEMETRY_EXPORTER_MODE]: "unified"
|
|
592
|
+
}
|
|
593
|
+
})
|
|
594
|
+
)
|
|
595
|
+
);
|
|
558
596
|
}).pipe(Layer.unwrapEffect);
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
597
|
+
var withOtelParentSpan = (effect) => {
|
|
598
|
+
const currentSpan = trace.getSpan(context.active());
|
|
599
|
+
if (currentSpan) {
|
|
600
|
+
const spanContext = currentSpan.spanContext();
|
|
601
|
+
return Tracer.withSpanContext(spanContext)(effect);
|
|
602
|
+
}
|
|
603
|
+
return effect;
|
|
604
|
+
};
|
|
605
|
+
var getCurrentOtelSpanContext = Effect.sync(() => {
|
|
606
|
+
const currentSpan = trace.getSpan(context.active());
|
|
607
|
+
return currentSpan?.spanContext();
|
|
608
|
+
});
|
|
609
|
+
var getOtelParentSpan = Effect.sync(
|
|
610
|
+
() => {
|
|
611
|
+
const currentSpan = trace.getSpan(context.active());
|
|
612
|
+
if (!currentSpan) {
|
|
613
|
+
return void 0;
|
|
614
|
+
}
|
|
615
|
+
const spanContext = currentSpan.spanContext();
|
|
616
|
+
return Tracer.makeExternalSpan({
|
|
617
|
+
traceId: spanContext.traceId,
|
|
618
|
+
spanId: spanContext.spanId,
|
|
619
|
+
traceFlags: spanContext.traceFlags,
|
|
620
|
+
traceState: spanContext.traceState?.serialize()
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
);
|
|
624
|
+
var runWithOtelContext = (effect) => {
|
|
625
|
+
return Effect.flatMap(
|
|
626
|
+
Tracer.currentOtelSpan,
|
|
627
|
+
(otelSpan) => Effect.async((resume) => {
|
|
628
|
+
context.with(trace.setSpan(context.active(), otelSpan), () => {
|
|
629
|
+
Effect.runPromiseExit(effect).then((exit) => {
|
|
630
|
+
if (exit._tag === "Success") {
|
|
631
|
+
resume(Effect.succeed(exit.value));
|
|
632
|
+
} else {
|
|
633
|
+
resume(Effect.failCause(exit.cause));
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
})
|
|
638
|
+
).pipe(
|
|
639
|
+
// If no OTel span is available, just run the effect normally
|
|
640
|
+
Effect.catchAll(() => effect)
|
|
641
|
+
);
|
|
642
|
+
};
|
|
643
|
+
var withFullOtelBridging = (effect) => {
|
|
644
|
+
return withOtelParentSpan(effect);
|
|
645
|
+
};
|
|
646
|
+
function annotateUser(userId, email, username) {
|
|
647
|
+
const attributes = {
|
|
648
|
+
"user.id": userId
|
|
649
|
+
};
|
|
650
|
+
if (email) attributes["user.email"] = email;
|
|
651
|
+
if (username) attributes["user.name"] = username;
|
|
652
|
+
return Effect.annotateCurrentSpan(attributes);
|
|
562
653
|
}
|
|
563
|
-
function annotateDataSize(
|
|
654
|
+
function annotateDataSize(bytes, items, compressionRatio) {
|
|
655
|
+
const attributes = {
|
|
656
|
+
"data.size.bytes": bytes,
|
|
657
|
+
"data.size.items": items
|
|
658
|
+
};
|
|
659
|
+
if (compressionRatio !== void 0) {
|
|
660
|
+
attributes["data.compression.ratio"] = compressionRatio;
|
|
661
|
+
}
|
|
662
|
+
return Effect.annotateCurrentSpan(attributes);
|
|
564
663
|
}
|
|
565
|
-
function annotateBatch(
|
|
664
|
+
function annotateBatch(totalItems, batchSize, successCount, failureCount) {
|
|
665
|
+
const attributes = {
|
|
666
|
+
"batch.size": batchSize,
|
|
667
|
+
"batch.total_items": totalItems,
|
|
668
|
+
"batch.count": Math.ceil(totalItems / batchSize)
|
|
669
|
+
};
|
|
670
|
+
if (successCount !== void 0) {
|
|
671
|
+
attributes["batch.success_count"] = successCount;
|
|
672
|
+
}
|
|
673
|
+
if (failureCount !== void 0) {
|
|
674
|
+
attributes["batch.failure_count"] = failureCount;
|
|
675
|
+
}
|
|
676
|
+
return Effect.annotateCurrentSpan(attributes);
|
|
566
677
|
}
|
|
567
|
-
function annotateLLM(
|
|
678
|
+
function annotateLLM(model, provider, tokens) {
|
|
679
|
+
const attributes = {
|
|
680
|
+
"llm.model": model,
|
|
681
|
+
"llm.provider": provider
|
|
682
|
+
};
|
|
683
|
+
if (tokens) {
|
|
684
|
+
if (tokens.prompt !== void 0) attributes["llm.tokens.prompt"] = tokens.prompt;
|
|
685
|
+
if (tokens.completion !== void 0) attributes["llm.tokens.completion"] = tokens.completion;
|
|
686
|
+
if (tokens.total !== void 0) attributes["llm.tokens.total"] = tokens.total;
|
|
687
|
+
}
|
|
688
|
+
return Effect.annotateCurrentSpan(attributes);
|
|
568
689
|
}
|
|
569
|
-
function annotateQuery(
|
|
690
|
+
function annotateQuery(query, duration, rowCount, database) {
|
|
691
|
+
const attributes = {
|
|
692
|
+
"db.statement": query.length > 1e3 ? query.substring(0, 1e3) + "..." : query
|
|
693
|
+
};
|
|
694
|
+
if (duration !== void 0) attributes["db.duration.ms"] = duration;
|
|
695
|
+
if (rowCount !== void 0) attributes["db.row_count"] = rowCount;
|
|
696
|
+
if (database) attributes["db.name"] = database;
|
|
697
|
+
return Effect.annotateCurrentSpan(attributes);
|
|
570
698
|
}
|
|
571
|
-
function annotateHttpRequest(
|
|
699
|
+
function annotateHttpRequest(method, url, statusCode, contentLength) {
|
|
700
|
+
const attributes = {
|
|
701
|
+
"http.method": method,
|
|
702
|
+
"http.url": url
|
|
703
|
+
};
|
|
704
|
+
if (statusCode !== void 0) attributes["http.status_code"] = statusCode;
|
|
705
|
+
if (contentLength !== void 0) attributes["http.response.content_length"] = contentLength;
|
|
706
|
+
return Effect.annotateCurrentSpan(attributes);
|
|
572
707
|
}
|
|
573
|
-
function annotateError(
|
|
708
|
+
function annotateError(error, recoverable, errorType) {
|
|
709
|
+
const errorMessage = typeof error === "string" ? error : error.message;
|
|
710
|
+
const errorStack = typeof error === "string" ? void 0 : error.stack;
|
|
711
|
+
const attributes = {
|
|
712
|
+
"error.message": errorMessage,
|
|
713
|
+
"error.recoverable": recoverable
|
|
714
|
+
};
|
|
715
|
+
if (errorType) attributes["error.type"] = errorType;
|
|
716
|
+
if (errorStack) attributes["error.stack"] = errorStack;
|
|
717
|
+
return Effect.annotateCurrentSpan(attributes);
|
|
574
718
|
}
|
|
575
|
-
function annotatePriority(
|
|
719
|
+
function annotatePriority(priority, reason) {
|
|
720
|
+
const attributes = {
|
|
721
|
+
"operation.priority": priority
|
|
722
|
+
};
|
|
723
|
+
if (reason) attributes["operation.priority.reason"] = reason;
|
|
724
|
+
return Effect.annotateCurrentSpan(attributes);
|
|
576
725
|
}
|
|
577
|
-
function annotateCache(
|
|
726
|
+
function annotateCache(hit, key, ttl) {
|
|
727
|
+
const attributes = {
|
|
728
|
+
"cache.hit": hit,
|
|
729
|
+
"cache.key": key
|
|
730
|
+
};
|
|
731
|
+
if (ttl !== void 0) attributes["cache.ttl.seconds"] = ttl;
|
|
732
|
+
return Effect.annotateCurrentSpan(attributes);
|
|
733
|
+
}
|
|
734
|
+
function extractEffectMetadata() {
|
|
735
|
+
return Effect.gen(function* () {
|
|
736
|
+
const metadata = {};
|
|
737
|
+
const currentFiber = Fiber.getCurrentFiber();
|
|
738
|
+
if (Option.isSome(currentFiber)) {
|
|
739
|
+
const fiber = currentFiber.value;
|
|
740
|
+
const fiberId = fiber.id();
|
|
741
|
+
metadata["effect.fiber.id"] = FiberId.threadName(fiberId);
|
|
742
|
+
const status = yield* Fiber.status(fiber);
|
|
743
|
+
if (status._tag) {
|
|
744
|
+
metadata["effect.fiber.status"] = status._tag;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
const parentSpanResult = yield* Effect.currentSpan.pipe(
|
|
748
|
+
Effect.option
|
|
749
|
+
// Convert NoSuchElementException to Option
|
|
750
|
+
);
|
|
751
|
+
if (Option.isSome(parentSpanResult)) {
|
|
752
|
+
const parentSpan = parentSpanResult.value;
|
|
753
|
+
metadata["effect.operation.nested"] = true;
|
|
754
|
+
metadata["effect.operation.root"] = false;
|
|
755
|
+
if (parentSpan.spanId) {
|
|
756
|
+
metadata["effect.parent.span.id"] = parentSpan.spanId;
|
|
757
|
+
}
|
|
758
|
+
if (parentSpan.name) {
|
|
759
|
+
metadata["effect.parent.span.name"] = parentSpan.name;
|
|
760
|
+
}
|
|
761
|
+
if (parentSpan.traceId) {
|
|
762
|
+
metadata["effect.parent.trace.id"] = parentSpan.traceId;
|
|
763
|
+
}
|
|
764
|
+
} else {
|
|
765
|
+
metadata["effect.operation.nested"] = false;
|
|
766
|
+
metadata["effect.operation.root"] = true;
|
|
767
|
+
}
|
|
768
|
+
return metadata;
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
function autoEnrichSpan() {
|
|
772
|
+
return Effect.gen(function* () {
|
|
773
|
+
const metadata = yield* extractEffectMetadata();
|
|
774
|
+
yield* Effect.annotateCurrentSpan(metadata);
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
function withAutoEnrichedSpan(spanName, options) {
|
|
778
|
+
return (self) => {
|
|
779
|
+
return Effect.gen(function* () {
|
|
780
|
+
yield* autoEnrichSpan();
|
|
781
|
+
return yield* self;
|
|
782
|
+
}).pipe(Effect.withSpan(spanName, options));
|
|
783
|
+
};
|
|
578
784
|
}
|
|
579
785
|
var createLogicalParentLink = (parentSpan, useSpanLinks) => {
|
|
580
786
|
if (!useSpanLinks) {
|
|
@@ -624,7 +830,7 @@ var runIsolated = (set, effect, name, options) => {
|
|
|
624
830
|
return FiberSet$1.run(set, effect, { propagateInterruption });
|
|
625
831
|
}
|
|
626
832
|
return Effect.gen(function* () {
|
|
627
|
-
const maybeParent = yield* Effect.serviceOption(Tracer.ParentSpan);
|
|
833
|
+
const maybeParent = yield* Effect.serviceOption(Tracer$1.ParentSpan);
|
|
628
834
|
if (maybeParent._tag === "None" || !captureLogicalParent) {
|
|
629
835
|
const isolated2 = effect.pipe(
|
|
630
836
|
Effect.withSpan(name, {
|
|
@@ -701,6 +907,6 @@ var FiberSet = {
|
|
|
701
907
|
runWithSpan
|
|
702
908
|
};
|
|
703
909
|
|
|
704
|
-
export { EffectInstrumentationLive, FiberSet, annotateBatch, annotateCache, annotateDataSize, annotateError, annotateHttpRequest, annotateLLM, annotatePriority, annotateQuery, annotateSpawnedTasks, annotateUser, createEffectInstrumentation, runIsolated, runWithSpan };
|
|
910
|
+
export { EffectInstrumentationLive, FiberSet, annotateBatch, annotateCache, annotateDataSize, annotateError, annotateHttpRequest, annotateLLM, annotatePriority, annotateQuery, annotateSpawnedTasks, annotateUser, autoEnrichSpan, createEffectInstrumentation, extractEffectMetadata, getCurrentOtelSpanContext, getOtelParentSpan, runIsolated, runWithOtelContext, runWithSpan, withAutoEnrichedSpan, withFullOtelBridging, withOtelParentSpan };
|
|
705
911
|
//# sourceMappingURL=index.js.map
|
|
706
912
|
//# sourceMappingURL=index.js.map
|