@superblocksteam/telemetry 2.0.83-next.1
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/LICENSE.txt +87 -0
- package/README.md +155 -0
- package/dist/browser/index.d.ts +8 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +19 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/init.d.ts +75 -0
- package/dist/browser/init.d.ts.map +1 -0
- package/dist/browser/init.js +169 -0
- package/dist/browser/init.js.map +1 -0
- package/dist/browser/resilient-exporter.d.ts +43 -0
- package/dist/browser/resilient-exporter.d.ts.map +1 -0
- package/dist/browser/resilient-exporter.js +88 -0
- package/dist/browser/resilient-exporter.js.map +1 -0
- package/dist/common/contracts/tier2-traces.d.ts +75 -0
- package/dist/common/contracts/tier2-traces.d.ts.map +1 -0
- package/dist/common/contracts/tier2-traces.js +186 -0
- package/dist/common/contracts/tier2-traces.js.map +1 -0
- package/dist/common/deployment-type.d.ts +18 -0
- package/dist/common/deployment-type.d.ts.map +1 -0
- package/dist/common/deployment-type.js +30 -0
- package/dist/common/deployment-type.js.map +1 -0
- package/dist/common/guardrails.d.ts +116 -0
- package/dist/common/guardrails.d.ts.map +1 -0
- package/dist/common/guardrails.js +189 -0
- package/dist/common/guardrails.js.map +1 -0
- package/dist/common/index.d.ts +16 -0
- package/dist/common/index.d.ts.map +1 -0
- package/dist/common/index.js +32 -0
- package/dist/common/index.js.map +1 -0
- package/dist/common/log-sanitizer.d.ts +78 -0
- package/dist/common/log-sanitizer.d.ts.map +1 -0
- package/dist/common/log-sanitizer.js +340 -0
- package/dist/common/log-sanitizer.js.map +1 -0
- package/dist/common/policy-evaluator.d.ts +103 -0
- package/dist/common/policy-evaluator.d.ts.map +1 -0
- package/dist/common/policy-evaluator.js +200 -0
- package/dist/common/policy-evaluator.js.map +1 -0
- package/dist/common/resource.d.ts +62 -0
- package/dist/common/resource.d.ts.map +1 -0
- package/dist/common/resource.js +106 -0
- package/dist/common/resource.js.map +1 -0
- package/dist/common/tier-hints.d.ts +182 -0
- package/dist/common/tier-hints.d.ts.map +1 -0
- package/dist/common/tier-hints.js +209 -0
- package/dist/common/tier-hints.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/lint/forbidden-attributes.d.ts +149 -0
- package/dist/lint/forbidden-attributes.d.ts.map +1 -0
- package/dist/lint/forbidden-attributes.js +214 -0
- package/dist/lint/forbidden-attributes.js.map +1 -0
- package/dist/lint/index.d.ts +9 -0
- package/dist/lint/index.d.ts.map +1 -0
- package/dist/lint/index.js +16 -0
- package/dist/lint/index.js.map +1 -0
- package/dist/llmobs/index.d.ts +22 -0
- package/dist/llmobs/index.d.ts.map +1 -0
- package/dist/llmobs/index.js +29 -0
- package/dist/llmobs/index.js.map +1 -0
- package/dist/llmobs/tier1-exporter.d.ts +146 -0
- package/dist/llmobs/tier1-exporter.d.ts.map +1 -0
- package/dist/llmobs/tier1-exporter.js +196 -0
- package/dist/llmobs/tier1-exporter.js.map +1 -0
- package/dist/llmobs/tier2-summarizer.d.ts +268 -0
- package/dist/llmobs/tier2-summarizer.d.ts.map +1 -0
- package/dist/llmobs/tier2-summarizer.js +650 -0
- package/dist/llmobs/tier2-summarizer.js.map +1 -0
- package/dist/node/exporters/resilient-exporter.d.ts +77 -0
- package/dist/node/exporters/resilient-exporter.d.ts.map +1 -0
- package/dist/node/exporters/resilient-exporter.js +129 -0
- package/dist/node/exporters/resilient-exporter.js.map +1 -0
- package/dist/node/index.d.ts +11 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +24 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/init.d.ts +75 -0
- package/dist/node/init.d.ts.map +1 -0
- package/dist/node/init.js +245 -0
- package/dist/node/init.js.map +1 -0
- package/dist/node/log-processor.d.ts +83 -0
- package/dist/node/log-processor.d.ts.map +1 -0
- package/dist/node/log-processor.js +266 -0
- package/dist/node/log-processor.js.map +1 -0
- package/dist/node/metrics-client.d.ts +66 -0
- package/dist/node/metrics-client.d.ts.map +1 -0
- package/dist/node/metrics-client.js +193 -0
- package/dist/node/metrics-client.js.map +1 -0
- package/dist/node/traced-socket.d.ts +76 -0
- package/dist/node/traced-socket.d.ts.map +1 -0
- package/dist/node/traced-socket.js +261 -0
- package/dist/node/traced-socket.js.map +1 -0
- package/dist/testing/in-memory-exporter.d.ts +179 -0
- package/dist/testing/in-memory-exporter.d.ts.map +1 -0
- package/dist/testing/in-memory-exporter.js +254 -0
- package/dist/testing/in-memory-exporter.js.map +1 -0
- package/dist/testing/index.d.ts +8 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +19 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/test-init.d.ts +80 -0
- package/dist/testing/test-init.d.ts.map +1 -0
- package/dist/testing/test-init.js +144 -0
- package/dist/testing/test-init.js.map +1 -0
- package/dist/types/index.d.ts +40 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +23 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/policy.d.ts +92 -0
- package/dist/types/policy.d.ts.map +1 -0
- package/dist/types/policy.js +125 -0
- package/dist/types/policy.js.map +1 -0
- package/dist-esm/browser/index.d.ts +8 -0
- package/dist-esm/browser/index.d.ts.map +1 -0
- package/dist-esm/browser/index.js +9 -0
- package/dist-esm/browser/index.js.map +1 -0
- package/dist-esm/browser/init.d.ts +75 -0
- package/dist-esm/browser/init.d.ts.map +1 -0
- package/dist-esm/browser/init.js +162 -0
- package/dist-esm/browser/init.js.map +1 -0
- package/dist-esm/browser/resilient-exporter.d.ts +43 -0
- package/dist-esm/browser/resilient-exporter.d.ts.map +1 -0
- package/dist-esm/browser/resilient-exporter.js +84 -0
- package/dist-esm/browser/resilient-exporter.js.map +1 -0
- package/dist-esm/common/contracts/tier2-traces.d.ts +75 -0
- package/dist-esm/common/contracts/tier2-traces.d.ts.map +1 -0
- package/dist-esm/common/contracts/tier2-traces.js +178 -0
- package/dist-esm/common/contracts/tier2-traces.js.map +1 -0
- package/dist-esm/common/deployment-type.d.ts +18 -0
- package/dist-esm/common/deployment-type.d.ts.map +1 -0
- package/dist-esm/common/deployment-type.js +27 -0
- package/dist-esm/common/deployment-type.js.map +1 -0
- package/dist-esm/common/guardrails.d.ts +116 -0
- package/dist-esm/common/guardrails.d.ts.map +1 -0
- package/dist-esm/common/guardrails.js +179 -0
- package/dist-esm/common/guardrails.js.map +1 -0
- package/dist-esm/common/index.d.ts +16 -0
- package/dist-esm/common/index.d.ts.map +1 -0
- package/dist-esm/common/index.js +16 -0
- package/dist-esm/common/index.js.map +1 -0
- package/dist-esm/common/log-sanitizer.d.ts +78 -0
- package/dist-esm/common/log-sanitizer.d.ts.map +1 -0
- package/dist-esm/common/log-sanitizer.js +331 -0
- package/dist-esm/common/log-sanitizer.js.map +1 -0
- package/dist-esm/common/policy-evaluator.d.ts +103 -0
- package/dist-esm/common/policy-evaluator.d.ts.map +1 -0
- package/dist-esm/common/policy-evaluator.js +196 -0
- package/dist-esm/common/policy-evaluator.js.map +1 -0
- package/dist-esm/common/resource.d.ts +62 -0
- package/dist-esm/common/resource.d.ts.map +1 -0
- package/dist-esm/common/resource.js +100 -0
- package/dist-esm/common/resource.js.map +1 -0
- package/dist-esm/common/tier-hints.d.ts +182 -0
- package/dist-esm/common/tier-hints.d.ts.map +1 -0
- package/dist-esm/common/tier-hints.js +199 -0
- package/dist-esm/common/tier-hints.js.map +1 -0
- package/dist-esm/index.d.ts +43 -0
- package/dist-esm/index.d.ts.map +1 -0
- package/dist-esm/index.js +53 -0
- package/dist-esm/index.js.map +1 -0
- package/dist-esm/lint/forbidden-attributes.d.ts +149 -0
- package/dist-esm/lint/forbidden-attributes.d.ts.map +1 -0
- package/dist-esm/lint/forbidden-attributes.js +209 -0
- package/dist-esm/lint/forbidden-attributes.js.map +1 -0
- package/dist-esm/lint/index.d.ts +9 -0
- package/dist-esm/lint/index.d.ts.map +1 -0
- package/dist-esm/lint/index.js +9 -0
- package/dist-esm/lint/index.js.map +1 -0
- package/dist-esm/llmobs/index.d.ts +22 -0
- package/dist-esm/llmobs/index.d.ts.map +1 -0
- package/dist-esm/llmobs/index.js +22 -0
- package/dist-esm/llmobs/index.js.map +1 -0
- package/dist-esm/llmobs/tier1-exporter.d.ts +146 -0
- package/dist-esm/llmobs/tier1-exporter.d.ts.map +1 -0
- package/dist-esm/llmobs/tier1-exporter.js +190 -0
- package/dist-esm/llmobs/tier1-exporter.js.map +1 -0
- package/dist-esm/llmobs/tier2-summarizer.d.ts +268 -0
- package/dist-esm/llmobs/tier2-summarizer.d.ts.map +1 -0
- package/dist-esm/llmobs/tier2-summarizer.js +646 -0
- package/dist-esm/llmobs/tier2-summarizer.js.map +1 -0
- package/dist-esm/node/exporters/resilient-exporter.d.ts +77 -0
- package/dist-esm/node/exporters/resilient-exporter.d.ts.map +1 -0
- package/dist-esm/node/exporters/resilient-exporter.js +125 -0
- package/dist-esm/node/exporters/resilient-exporter.js.map +1 -0
- package/dist-esm/node/index.d.ts +11 -0
- package/dist-esm/node/index.d.ts.map +1 -0
- package/dist-esm/node/index.js +11 -0
- package/dist-esm/node/index.js.map +1 -0
- package/dist-esm/node/init.d.ts +75 -0
- package/dist-esm/node/init.d.ts.map +1 -0
- package/dist-esm/node/init.js +239 -0
- package/dist-esm/node/init.js.map +1 -0
- package/dist-esm/node/log-processor.d.ts +83 -0
- package/dist-esm/node/log-processor.d.ts.map +1 -0
- package/dist-esm/node/log-processor.js +261 -0
- package/dist-esm/node/log-processor.js.map +1 -0
- package/dist-esm/node/metrics-client.d.ts +66 -0
- package/dist-esm/node/metrics-client.d.ts.map +1 -0
- package/dist-esm/node/metrics-client.js +189 -0
- package/dist-esm/node/metrics-client.js.map +1 -0
- package/dist-esm/node/traced-socket.d.ts +76 -0
- package/dist-esm/node/traced-socket.d.ts.map +1 -0
- package/dist-esm/node/traced-socket.js +257 -0
- package/dist-esm/node/traced-socket.js.map +1 -0
- package/dist-esm/testing/in-memory-exporter.d.ts +179 -0
- package/dist-esm/testing/in-memory-exporter.d.ts.map +1 -0
- package/dist-esm/testing/in-memory-exporter.js +248 -0
- package/dist-esm/testing/in-memory-exporter.js.map +1 -0
- package/dist-esm/testing/index.d.ts +8 -0
- package/dist-esm/testing/index.d.ts.map +1 -0
- package/dist-esm/testing/index.js +8 -0
- package/dist-esm/testing/index.js.map +1 -0
- package/dist-esm/testing/test-init.d.ts +80 -0
- package/dist-esm/testing/test-init.d.ts.map +1 -0
- package/dist-esm/testing/test-init.js +137 -0
- package/dist-esm/testing/test-init.js.map +1 -0
- package/dist-esm/types/index.d.ts +40 -0
- package/dist-esm/types/index.d.ts.map +1 -0
- package/dist-esm/types/index.js +7 -0
- package/dist-esm/types/index.js.map +1 -0
- package/dist-esm/types/policy.d.ts +92 -0
- package/dist-esm/types/policy.d.ts.map +1 -0
- package/dist-esm/types/policy.js +122 -0
- package/dist-esm/types/policy.js.map +1 -0
- package/package.json +101 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resilient Exporter
|
|
3
|
+
*
|
|
4
|
+
* Wrapper that ensures Tier 2/3 export failures never block core request paths.
|
|
5
|
+
* Export failures are observable via metrics, not via blocking or exceptions.
|
|
6
|
+
*/
|
|
7
|
+
import type { SpanExporter, ReadableSpan } from "@opentelemetry/sdk-trace-base";
|
|
8
|
+
import { ExportResult } from "@opentelemetry/core";
|
|
9
|
+
/**
|
|
10
|
+
* Configuration for the resilient exporter.
|
|
11
|
+
*/
|
|
12
|
+
export interface ResilientExporterConfig {
|
|
13
|
+
/** Underlying exporter to wrap */
|
|
14
|
+
delegate: SpanExporter;
|
|
15
|
+
/** Max items to buffer before dropping (default: 2048) */
|
|
16
|
+
maxQueueSize?: number;
|
|
17
|
+
/** Export timeout in ms (default: 30000) */
|
|
18
|
+
exportTimeoutMs?: number;
|
|
19
|
+
/** Callback when items are dropped due to backpressure */
|
|
20
|
+
onDrop?: (count: number, reason: "queue_full" | "export_failed" | "timeout") => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Metrics exposed by the resilient exporter.
|
|
24
|
+
*/
|
|
25
|
+
export interface ResilientExporterMetrics {
|
|
26
|
+
/** Total spans dropped due to backpressure or failure */
|
|
27
|
+
dropped: number;
|
|
28
|
+
/** Current queue size */
|
|
29
|
+
queued: number;
|
|
30
|
+
/** Total export failures */
|
|
31
|
+
failures: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resilient exporter wrapper that:
|
|
35
|
+
* - Drops spans when queue is full (never blocks)
|
|
36
|
+
* - Catches export failures and emits metrics
|
|
37
|
+
* - Times out stalled exports
|
|
38
|
+
*
|
|
39
|
+
* CRITICAL: Telemetry export must be fire-and-forget from the application's perspective.
|
|
40
|
+
* Export failures should be observable via metrics, not via blocking or exceptions.
|
|
41
|
+
*/
|
|
42
|
+
export declare class ResilientExporter implements SpanExporter {
|
|
43
|
+
private readonly delegate;
|
|
44
|
+
private readonly maxQueueSize;
|
|
45
|
+
private readonly exportTimeoutMs;
|
|
46
|
+
private readonly onDrop;
|
|
47
|
+
private queuedCount;
|
|
48
|
+
private droppedCount;
|
|
49
|
+
private exportFailures;
|
|
50
|
+
private shuttingDown;
|
|
51
|
+
constructor(config: ResilientExporterConfig);
|
|
52
|
+
/**
|
|
53
|
+
* Export spans with resilient error handling.
|
|
54
|
+
*
|
|
55
|
+
* IMPORTANT: Always returns SUCCESS to caller - export failures are
|
|
56
|
+
* observable via metrics, not via the result callback.
|
|
57
|
+
*/
|
|
58
|
+
export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void;
|
|
59
|
+
/**
|
|
60
|
+
* Shutdown the underlying exporter.
|
|
61
|
+
* Marks exporter as shutting down to reject new exports.
|
|
62
|
+
*/
|
|
63
|
+
shutdown(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Force flush the underlying exporter.
|
|
66
|
+
*/
|
|
67
|
+
forceFlush(): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Get current metrics for observability.
|
|
70
|
+
*/
|
|
71
|
+
getMetrics(): ResilientExporterMetrics;
|
|
72
|
+
/**
|
|
73
|
+
* Reset metrics (for testing).
|
|
74
|
+
*/
|
|
75
|
+
resetMetrics(): void;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=resilient-exporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilient-exporter.d.ts","sourceRoot":"","sources":["../../../src/node/exporters/resilient-exporter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,YAAY,EAAoB,MAAM,qBAAqB,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,kCAAkC;IAClC,QAAQ,EAAE,YAAY,CAAC;IACvB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,CACP,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,YAAY,GAAG,eAAe,GAAG,SAAS,KAC/C,IAAI,CAAC;CACX;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGb;IAEV,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,YAAY,CAAS;gBAEjB,MAAM,EAAE,uBAAuB;IAO3C;;;;;OAKG;IACH,MAAM,CACJ,KAAK,EAAE,YAAY,EAAE,EACrB,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAC7C,IAAI;IA0DP;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAK/B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACH,UAAU,IAAI,wBAAwB;IAQtC;;OAEG;IACH,YAAY,IAAI,IAAI;CAIrB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resilient Exporter
|
|
3
|
+
*
|
|
4
|
+
* Wrapper that ensures Tier 2/3 export failures never block core request paths.
|
|
5
|
+
* Export failures are observable via metrics, not via blocking or exceptions.
|
|
6
|
+
*/
|
|
7
|
+
import { ExportResultCode } from "@opentelemetry/core";
|
|
8
|
+
/**
|
|
9
|
+
* Resilient exporter wrapper that:
|
|
10
|
+
* - Drops spans when queue is full (never blocks)
|
|
11
|
+
* - Catches export failures and emits metrics
|
|
12
|
+
* - Times out stalled exports
|
|
13
|
+
*
|
|
14
|
+
* CRITICAL: Telemetry export must be fire-and-forget from the application's perspective.
|
|
15
|
+
* Export failures should be observable via metrics, not via blocking or exceptions.
|
|
16
|
+
*/
|
|
17
|
+
export class ResilientExporter {
|
|
18
|
+
delegate;
|
|
19
|
+
maxQueueSize;
|
|
20
|
+
exportTimeoutMs;
|
|
21
|
+
onDrop;
|
|
22
|
+
queuedCount = 0;
|
|
23
|
+
droppedCount = 0;
|
|
24
|
+
exportFailures = 0;
|
|
25
|
+
shuttingDown = false;
|
|
26
|
+
constructor(config) {
|
|
27
|
+
this.delegate = config.delegate;
|
|
28
|
+
this.maxQueueSize = config.maxQueueSize ?? 2048;
|
|
29
|
+
this.exportTimeoutMs = config.exportTimeoutMs ?? 30000;
|
|
30
|
+
this.onDrop = config.onDrop ?? (() => { });
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Export spans with resilient error handling.
|
|
34
|
+
*
|
|
35
|
+
* IMPORTANT: Always returns SUCCESS to caller - export failures are
|
|
36
|
+
* observable via metrics, not via the result callback.
|
|
37
|
+
*/
|
|
38
|
+
export(spans, resultCallback) {
|
|
39
|
+
// Don't accept new exports during shutdown
|
|
40
|
+
if (this.shuttingDown) {
|
|
41
|
+
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Check backpressure - drop if queue is full
|
|
45
|
+
if (this.queuedCount + spans.length > this.maxQueueSize) {
|
|
46
|
+
this.droppedCount += spans.length;
|
|
47
|
+
this.onDrop(spans.length, "queue_full");
|
|
48
|
+
// Still return success - don't block the caller
|
|
49
|
+
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.queuedCount += spans.length;
|
|
53
|
+
let completed = false;
|
|
54
|
+
// Wrap with timeout
|
|
55
|
+
const timeoutId = setTimeout(() => {
|
|
56
|
+
if (completed)
|
|
57
|
+
return;
|
|
58
|
+
completed = true;
|
|
59
|
+
this.queuedCount -= spans.length;
|
|
60
|
+
this.droppedCount += spans.length;
|
|
61
|
+
this.onDrop(spans.length, "timeout");
|
|
62
|
+
resultCallback({ code: ExportResultCode.SUCCESS }); // Don't propagate failure
|
|
63
|
+
}, this.exportTimeoutMs);
|
|
64
|
+
try {
|
|
65
|
+
this.delegate.export(spans, (result) => {
|
|
66
|
+
if (completed)
|
|
67
|
+
return;
|
|
68
|
+
completed = true;
|
|
69
|
+
clearTimeout(timeoutId);
|
|
70
|
+
this.queuedCount -= spans.length;
|
|
71
|
+
if (result.code !== ExportResultCode.SUCCESS) {
|
|
72
|
+
this.exportFailures++;
|
|
73
|
+
this.droppedCount += spans.length;
|
|
74
|
+
this.onDrop(spans.length, "export_failed");
|
|
75
|
+
}
|
|
76
|
+
// Always return success to caller - export failures are observable via metrics
|
|
77
|
+
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (completed)
|
|
82
|
+
return;
|
|
83
|
+
completed = true;
|
|
84
|
+
clearTimeout(timeoutId);
|
|
85
|
+
this.queuedCount -= spans.length;
|
|
86
|
+
this.exportFailures++;
|
|
87
|
+
this.droppedCount += spans.length;
|
|
88
|
+
this.onDrop(spans.length, "export_failed");
|
|
89
|
+
console.warn("[Telemetry] Span export threw:", error);
|
|
90
|
+
resultCallback({ code: ExportResultCode.SUCCESS }); // Don't propagate failure
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Shutdown the underlying exporter.
|
|
95
|
+
* Marks exporter as shutting down to reject new exports.
|
|
96
|
+
*/
|
|
97
|
+
async shutdown() {
|
|
98
|
+
this.shuttingDown = true;
|
|
99
|
+
return this.delegate.shutdown();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Force flush the underlying exporter.
|
|
103
|
+
*/
|
|
104
|
+
async forceFlush() {
|
|
105
|
+
return this.delegate.forceFlush?.() ?? Promise.resolve();
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get current metrics for observability.
|
|
109
|
+
*/
|
|
110
|
+
getMetrics() {
|
|
111
|
+
return {
|
|
112
|
+
dropped: this.droppedCount,
|
|
113
|
+
queued: this.queuedCount,
|
|
114
|
+
failures: this.exportFailures,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Reset metrics (for testing).
|
|
119
|
+
*/
|
|
120
|
+
resetMetrics() {
|
|
121
|
+
this.droppedCount = 0;
|
|
122
|
+
this.exportFailures = 0;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=resilient-exporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilient-exporter.js","sourceRoot":"","sources":["../../../src/node/exporters/resilient-exporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js Telemetry Bootstrap
|
|
3
|
+
*
|
|
4
|
+
* This is the ONLY approved way to initialize telemetry in Node.js services.
|
|
5
|
+
*/
|
|
6
|
+
export { initNodeTelemetry, getTelemetryInstance, isTelemetryInitialized, resetTelemetry, type NodeTelemetryInstance, } from "./init.js";
|
|
7
|
+
export { MetricsClient, type Labels, type CounterHandle, type GaugeHandle, type HistogramHandle, } from "./metrics-client.js";
|
|
8
|
+
export { TracedSocket, type TracedSocketConfig, type TracedSocketOptions, } from "./traced-socket.js";
|
|
9
|
+
export { ResilientExporter, type ResilientExporterConfig, type ResilientExporterMetrics, } from "./exporters/resilient-exporter.js";
|
|
10
|
+
export { PolicyAwareLogProcessor, LogExportMode, getLoggingPolicy, type LoggingPolicyConfig, } from "./log-processor.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,KAAK,qBAAqB,GAC3B,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,aAAa,EACb,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,YAAY,EACZ,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,GAC9B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EACL,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js Telemetry Bootstrap
|
|
3
|
+
*
|
|
4
|
+
* This is the ONLY approved way to initialize telemetry in Node.js services.
|
|
5
|
+
*/
|
|
6
|
+
export { initNodeTelemetry, getTelemetryInstance, isTelemetryInitialized, resetTelemetry, } from "./init.js";
|
|
7
|
+
export { MetricsClient, } from "./metrics-client.js";
|
|
8
|
+
export { TracedSocket, } from "./traced-socket.js";
|
|
9
|
+
export { ResilientExporter, } from "./exporters/resilient-exporter.js";
|
|
10
|
+
export { PolicyAwareLogProcessor, LogExportMode, getLoggingPolicy, } from "./log-processor.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,GAEf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,aAAa,GAKd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,YAAY,GAGb,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,iBAAiB,GAGlB,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EACL,uBAAuB,EACvB,aAAa,EACb,gBAAgB,GAEjB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js Telemetry Bootstrap
|
|
3
|
+
*
|
|
4
|
+
* This is the ONLY approved way to initialize telemetry in Node.js services.
|
|
5
|
+
* Direct NodeSDK usage outside this package is prohibited.
|
|
6
|
+
*/
|
|
7
|
+
import { Tracer, Meter } from "@opentelemetry/api";
|
|
8
|
+
import { Logger } from "@opentelemetry/api-logs";
|
|
9
|
+
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
10
|
+
import { TelemetryPolicyEvaluator } from "../common/policy-evaluator.js";
|
|
11
|
+
import type { NodeTelemetryConfig } from "../types/index.js";
|
|
12
|
+
import { TelemetryPolicy } from "../types/policy.js";
|
|
13
|
+
import { MetricsClient } from "./metrics-client.js";
|
|
14
|
+
/**
|
|
15
|
+
* Telemetry instance returned by initNodeTelemetry.
|
|
16
|
+
*/
|
|
17
|
+
export interface NodeTelemetryInstance {
|
|
18
|
+
/** The underlying NodeSDK instance (undefined in CI/no-op mode) */
|
|
19
|
+
sdk?: NodeSDK;
|
|
20
|
+
/** Policy evaluator for runtime decisions */
|
|
21
|
+
policyEvaluator: TelemetryPolicyEvaluator;
|
|
22
|
+
/** Get a tracer for the service */
|
|
23
|
+
getTracer: (name?: string) => Tracer;
|
|
24
|
+
/** Get a meter for the service */
|
|
25
|
+
getMeter: (name?: string) => Meter;
|
|
26
|
+
/** Get a logger for the service */
|
|
27
|
+
getLogger: (name?: string) => Logger;
|
|
28
|
+
/** Metrics client for recording counters, gauges, and histograms */
|
|
29
|
+
metricsClient: MetricsClient;
|
|
30
|
+
/** Graceful shutdown */
|
|
31
|
+
shutdown: () => Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Initialize Node.js telemetry with policy enforcement.
|
|
35
|
+
*
|
|
36
|
+
* This is the ONLY approved way to initialize telemetry in Node.js services.
|
|
37
|
+
* Direct NodeSDK usage outside this package is prohibited.
|
|
38
|
+
*
|
|
39
|
+
* @param config - Service configuration
|
|
40
|
+
* @param policy - Telemetry policy (REQUIRED)
|
|
41
|
+
* @returns Telemetry instance with SDK and utilities
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* import { initNodeTelemetry } from '@superblocksteam/telemetry/node';
|
|
46
|
+
* import { getDefaultPolicy, DeploymentType } from '@superblocksteam/shared';
|
|
47
|
+
*
|
|
48
|
+
* const policy = getDefaultPolicy(DeploymentType.CLOUD_PREM);
|
|
49
|
+
* const telemetry = initNodeTelemetry({
|
|
50
|
+
* serviceName: 'my-service',
|
|
51
|
+
* serviceVersion: '1.0.0',
|
|
52
|
+
* environment: 'production',
|
|
53
|
+
* otlpUrl: 'http://localhost:4318',
|
|
54
|
+
* }, policy);
|
|
55
|
+
*
|
|
56
|
+
* const tracer = telemetry.getTracer();
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function initNodeTelemetry(config: NodeTelemetryConfig, policy: TelemetryPolicy): NodeTelemetryInstance;
|
|
60
|
+
/**
|
|
61
|
+
* Get the current telemetry instance.
|
|
62
|
+
*
|
|
63
|
+
* @throws Error if not initialized
|
|
64
|
+
*/
|
|
65
|
+
export declare function getTelemetryInstance(): NodeTelemetryInstance;
|
|
66
|
+
/**
|
|
67
|
+
* Check if telemetry is initialized.
|
|
68
|
+
*/
|
|
69
|
+
export declare function isTelemetryInitialized(): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Reset telemetry (for testing only).
|
|
72
|
+
* @internal
|
|
73
|
+
*/
|
|
74
|
+
export declare function resetTelemetry(): void;
|
|
75
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/node/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAS,MAAM,EAAW,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAQ,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAWvD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAIlD,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAiB,MAAM,oBAAoB,CAAC;AAOpE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,mEAAmE;IACnE,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,6CAA6C;IAC7C,eAAe,EAAE,wBAAwB,CAAC;IAC1C,mCAAmC;IACnC,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,kCAAkC;IAClC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,KAAK,CAAC;IACnC,mCAAmC;IACnC,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,oEAAoE;IACpE,aAAa,EAAE,aAAa,CAAC;IAC7B,wBAAwB;IACxB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AA0ED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,eAAe,GACtB,qBAAqB,CAkJvB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,qBAAqB,CAO5D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAErC"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js Telemetry Bootstrap
|
|
3
|
+
*
|
|
4
|
+
* This is the ONLY approved way to initialize telemetry in Node.js services.
|
|
5
|
+
* Direct NodeSDK usage outside this package is prohibited.
|
|
6
|
+
*/
|
|
7
|
+
import { trace, metrics } from "@opentelemetry/api";
|
|
8
|
+
import { logs } from "@opentelemetry/api-logs";
|
|
9
|
+
import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
|
|
10
|
+
import { W3CTraceContextPropagator } from "@opentelemetry/core";
|
|
11
|
+
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
|
|
12
|
+
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
|
|
13
|
+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
14
|
+
import { BatchLogRecordProcessor } from "@opentelemetry/sdk-logs";
|
|
15
|
+
import { AggregationTemporality, PeriodicExportingMetricReader, } from "@opentelemetry/sdk-metrics";
|
|
16
|
+
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
17
|
+
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
18
|
+
import { buildResource, validateResource } from "../common/resource.js";
|
|
19
|
+
import { TelemetryPolicyEvaluator } from "../common/policy-evaluator.js";
|
|
20
|
+
import { TelemetryTier } from "../types/policy.js";
|
|
21
|
+
import { ResilientExporter } from "./exporters/resilient-exporter.js";
|
|
22
|
+
import { PolicyAwareLogProcessor, getLoggingPolicy, LogExportMode, } from "./log-processor.js";
|
|
23
|
+
import { MetricsClient } from "./metrics-client.js";
|
|
24
|
+
// Singleton instance
|
|
25
|
+
let instance;
|
|
26
|
+
/**
|
|
27
|
+
* Create a no-op telemetry instance for CI environments.
|
|
28
|
+
*
|
|
29
|
+
* IMPORTANT: We intentionally do NOT use NodeSDK here. NodeSDK.start()
|
|
30
|
+
* auto-configures OTLP exporters for traces, metrics, and logs from
|
|
31
|
+
* environment defaults (localhost:4318). During shutdown, these exporters
|
|
32
|
+
* try to flush to the non-existent collector, causing ECONNREFUSED errors
|
|
33
|
+
* that fail test suites even when all tests pass.
|
|
34
|
+
*
|
|
35
|
+
* Instead, we return a lightweight instance that uses the global OTel API
|
|
36
|
+
* (which returns no-op tracers/meters/loggers when no provider is registered).
|
|
37
|
+
*/
|
|
38
|
+
function createNoOpInstance(config, policy) {
|
|
39
|
+
const policyEvaluator = new TelemetryPolicyEvaluator(policy);
|
|
40
|
+
// Use a no-op meter for the metrics client
|
|
41
|
+
const defaultMeter = metrics.getMeter(config.serviceName, config.serviceVersion);
|
|
42
|
+
return {
|
|
43
|
+
sdk: undefined,
|
|
44
|
+
policyEvaluator,
|
|
45
|
+
getTracer: (name) => trace.getTracer(name ?? config.serviceName, config.serviceVersion),
|
|
46
|
+
getMeter: (name) => metrics.getMeter(name ?? config.serviceName, config.serviceVersion),
|
|
47
|
+
getLogger: (name) => logs.getLogger(name ?? config.serviceName, config.serviceVersion),
|
|
48
|
+
metricsClient: new MetricsClient(defaultMeter),
|
|
49
|
+
shutdown: async () => {
|
|
50
|
+
// No-op: nothing to flush or shut down
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Validate telemetry configuration.
|
|
56
|
+
*
|
|
57
|
+
* @param config - Configuration to validate
|
|
58
|
+
* @throws Error if configuration is invalid
|
|
59
|
+
*/
|
|
60
|
+
function validateNodeTelemetryConfig(config) {
|
|
61
|
+
if (!config.serviceName?.trim()) {
|
|
62
|
+
throw new Error("[Telemetry] serviceName is required and cannot be empty");
|
|
63
|
+
}
|
|
64
|
+
if (!config.serviceVersion?.trim()) {
|
|
65
|
+
throw new Error("[Telemetry] serviceVersion is required and cannot be empty");
|
|
66
|
+
}
|
|
67
|
+
if (!config.environment?.trim()) {
|
|
68
|
+
throw new Error("[Telemetry] environment is required and cannot be empty");
|
|
69
|
+
}
|
|
70
|
+
if (config.otlpUrl) {
|
|
71
|
+
try {
|
|
72
|
+
new URL(config.otlpUrl);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
throw new Error(`[Telemetry] Invalid otlpUrl: ${config.otlpUrl} (${error.message})`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Initialize Node.js telemetry with policy enforcement.
|
|
81
|
+
*
|
|
82
|
+
* This is the ONLY approved way to initialize telemetry in Node.js services.
|
|
83
|
+
* Direct NodeSDK usage outside this package is prohibited.
|
|
84
|
+
*
|
|
85
|
+
* @param config - Service configuration
|
|
86
|
+
* @param policy - Telemetry policy (REQUIRED)
|
|
87
|
+
* @returns Telemetry instance with SDK and utilities
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* import { initNodeTelemetry } from '@superblocksteam/telemetry/node';
|
|
92
|
+
* import { getDefaultPolicy, DeploymentType } from '@superblocksteam/shared';
|
|
93
|
+
*
|
|
94
|
+
* const policy = getDefaultPolicy(DeploymentType.CLOUD_PREM);
|
|
95
|
+
* const telemetry = initNodeTelemetry({
|
|
96
|
+
* serviceName: 'my-service',
|
|
97
|
+
* serviceVersion: '1.0.0',
|
|
98
|
+
* environment: 'production',
|
|
99
|
+
* otlpUrl: 'http://localhost:4318',
|
|
100
|
+
* }, policy);
|
|
101
|
+
*
|
|
102
|
+
* const tracer = telemetry.getTracer();
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export function initNodeTelemetry(config, policy) {
|
|
106
|
+
// Policy is required
|
|
107
|
+
if (!policy) {
|
|
108
|
+
throw new Error("[Telemetry] Policy is required. Cannot initialize telemetry without a policy.");
|
|
109
|
+
}
|
|
110
|
+
// Validate config
|
|
111
|
+
validateNodeTelemetryConfig(config);
|
|
112
|
+
// Return existing instance if already initialized
|
|
113
|
+
if (instance) {
|
|
114
|
+
// Warn if config differs from existing
|
|
115
|
+
const existingPolicy = instance.policyEvaluator.getPolicy();
|
|
116
|
+
if (existingPolicy.deploymentType !== policy.deploymentType) {
|
|
117
|
+
console.warn(`[Telemetry] Already initialized with different deployment type ` +
|
|
118
|
+
`(existing: ${existingPolicy.deploymentType}, requested: ${policy.deploymentType}). ` +
|
|
119
|
+
`Returning existing instance.`);
|
|
120
|
+
}
|
|
121
|
+
return instance;
|
|
122
|
+
}
|
|
123
|
+
// CI environment detection - use no-op telemetry
|
|
124
|
+
if (process.env.CI === "true") {
|
|
125
|
+
console.debug("[Telemetry] CI environment detected, using no-op telemetry");
|
|
126
|
+
instance = createNoOpInstance(config, policy);
|
|
127
|
+
return instance;
|
|
128
|
+
}
|
|
129
|
+
const policyEvaluator = new TelemetryPolicyEvaluator(policy);
|
|
130
|
+
const resource = buildResource(config);
|
|
131
|
+
// Validate resource has required attributes
|
|
132
|
+
validateResource(resource);
|
|
133
|
+
// Track dropped spans for observability
|
|
134
|
+
let droppedSpans = 0;
|
|
135
|
+
const onDrop = (count, reason) => {
|
|
136
|
+
droppedSpans += count;
|
|
137
|
+
console.warn(`[Telemetry] Dropped ${count} spans (${reason}). Total dropped: ${droppedSpans}`);
|
|
138
|
+
};
|
|
139
|
+
// Create trace exporter if URL provided and Tier 2 export is enabled
|
|
140
|
+
// Use isExportEnabled (not canExport) - sampling applies at runtime, not initialization
|
|
141
|
+
let traceExporter;
|
|
142
|
+
if (config.otlpUrl &&
|
|
143
|
+
policyEvaluator.isExportEnabled(TelemetryTier.TIER_2_OPERATIONAL)) {
|
|
144
|
+
traceExporter = new ResilientExporter({
|
|
145
|
+
delegate: new OTLPTraceExporter({ url: `${config.otlpUrl}/v1/traces` }),
|
|
146
|
+
onDrop,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// Create metric exporter if enabled
|
|
150
|
+
// Use isExportEnabled (not canExport) - sampling applies at runtime, not initialization
|
|
151
|
+
let metricReader;
|
|
152
|
+
if (config.otlpUrl &&
|
|
153
|
+
config.metricsEnabled !== false &&
|
|
154
|
+
policyEvaluator.isExportEnabled(TelemetryTier.TIER_2_OPERATIONAL)) {
|
|
155
|
+
metricReader = new PeriodicExportingMetricReader({
|
|
156
|
+
exporter: new OTLPMetricExporter({
|
|
157
|
+
url: `${config.otlpUrl}/v1/metrics`,
|
|
158
|
+
temporalityPreference: AggregationTemporality.DELTA,
|
|
159
|
+
}),
|
|
160
|
+
exportIntervalMillis: 10000, // every 10 seconds
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
// Create log processor with policy-aware filtering and sanitization
|
|
164
|
+
// The PolicyAwareLogProcessor wraps the batch processor to:
|
|
165
|
+
// 1. Filter logs by severity level based on export mode (LOCAL_ONLY, ERRORS_ONLY, INFO_AND_ABOVE)
|
|
166
|
+
// 2. Sanitize log bodies and attributes to remove PII, file paths, stack traces
|
|
167
|
+
// 3. Remove forbidden fields that should never be exported
|
|
168
|
+
let logProcessor;
|
|
169
|
+
const loggingPolicy = getLoggingPolicy(policy);
|
|
170
|
+
if (config.otlpUrl &&
|
|
171
|
+
config.logsEnabled !== false &&
|
|
172
|
+
policyEvaluator.isExportEnabled(TelemetryTier.TIER_2_OPERATIONAL) &&
|
|
173
|
+
loggingPolicy.exportMode !== LogExportMode.LOCAL_ONLY) {
|
|
174
|
+
const batchProcessor = new BatchLogRecordProcessor(new OTLPLogExporter({ url: `${config.otlpUrl}/v1/logs` }));
|
|
175
|
+
logProcessor = new PolicyAwareLogProcessor(loggingPolicy, batchProcessor);
|
|
176
|
+
}
|
|
177
|
+
// Create the SDK
|
|
178
|
+
// Note: instrumentations typed as unknown[] for flexibility with various OTEL instrumentation packages
|
|
179
|
+
const sdk = new NodeSDK({
|
|
180
|
+
resource,
|
|
181
|
+
spanProcessor: traceExporter
|
|
182
|
+
? new BatchSpanProcessor(traceExporter)
|
|
183
|
+
: undefined,
|
|
184
|
+
metricReader,
|
|
185
|
+
logRecordProcessor: logProcessor,
|
|
186
|
+
contextManager: new AsyncLocalStorageContextManager(),
|
|
187
|
+
textMapPropagator: new W3CTraceContextPropagator(),
|
|
188
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- OTEL instrumentation types vary
|
|
189
|
+
instrumentations: (config.instrumentations ?? []),
|
|
190
|
+
});
|
|
191
|
+
sdk.start();
|
|
192
|
+
console.info(`[Telemetry] Initialized for ${config.serviceName} (${policy.deploymentType})` +
|
|
193
|
+
` | Traces: ${traceExporter ? "enabled" : "disabled"}` +
|
|
194
|
+
` | Metrics: ${metricReader ? "enabled" : "disabled"}` +
|
|
195
|
+
` | Logs: ${logProcessor ? "enabled" : "disabled"}`);
|
|
196
|
+
const defaultMeter = metrics.getMeter(config.serviceName, config.serviceVersion);
|
|
197
|
+
instance = {
|
|
198
|
+
sdk,
|
|
199
|
+
policyEvaluator,
|
|
200
|
+
getTracer: (name) => trace.getTracer(name ?? config.serviceName, config.serviceVersion),
|
|
201
|
+
getMeter: (name) => metrics.getMeter(name ?? config.serviceName, config.serviceVersion),
|
|
202
|
+
getLogger: (name) => logs.getLogger(name ?? config.serviceName, config.serviceVersion),
|
|
203
|
+
metricsClient: new MetricsClient(defaultMeter),
|
|
204
|
+
shutdown: async () => {
|
|
205
|
+
try {
|
|
206
|
+
await sdk.shutdown();
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
instance = undefined;
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
return instance;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Get the current telemetry instance.
|
|
217
|
+
*
|
|
218
|
+
* @throws Error if not initialized
|
|
219
|
+
*/
|
|
220
|
+
export function getTelemetryInstance() {
|
|
221
|
+
if (!instance) {
|
|
222
|
+
throw new Error("[Telemetry] Not initialized. Call initNodeTelemetry() first.");
|
|
223
|
+
}
|
|
224
|
+
return instance;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Check if telemetry is initialized.
|
|
228
|
+
*/
|
|
229
|
+
export function isTelemetryInitialized() {
|
|
230
|
+
return instance !== undefined;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Reset telemetry (for testing only).
|
|
234
|
+
* @internal
|
|
235
|
+
*/
|
|
236
|
+
export function resetTelemetry() {
|
|
237
|
+
instance = undefined;
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/node/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy-Aware Log Processor
|
|
3
|
+
*
|
|
4
|
+
* Wraps a delegate LogRecordProcessor to provide:
|
|
5
|
+
* 1. Export mode filtering (LOCAL_ONLY, ERRORS_ONLY, INFO_AND_ABOVE)
|
|
6
|
+
* 2. Severity level filtering
|
|
7
|
+
* 3. Log body and attribute sanitization
|
|
8
|
+
*
|
|
9
|
+
* @see https://github.com/superblocksteam/engineering/blob/main/projects/o11y-refactor/epics/epic-c4-logging-strategy.md
|
|
10
|
+
*/
|
|
11
|
+
import type { LogRecordProcessor, ReadableLogRecord } from "@opentelemetry/sdk-logs";
|
|
12
|
+
import type { Context } from "@opentelemetry/api";
|
|
13
|
+
import { TelemetryPolicy } from "../types/policy.js";
|
|
14
|
+
/**
|
|
15
|
+
* Controls what logs are exported via OTEL.
|
|
16
|
+
*/
|
|
17
|
+
export declare enum LogExportMode {
|
|
18
|
+
/** No log export - local stdout/stderr only */
|
|
19
|
+
LOCAL_ONLY = "local_only",
|
|
20
|
+
/** Export WARN/ERROR/FATAL only (default for cloud-prem) */
|
|
21
|
+
ERRORS_ONLY = "errors_only",
|
|
22
|
+
/** Export INFO and above (not recommended for cloud-prem) */
|
|
23
|
+
INFO_AND_ABOVE = "info_and_above"
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Logging-specific policy configuration.
|
|
27
|
+
*/
|
|
28
|
+
export interface LoggingPolicyConfig {
|
|
29
|
+
/** What logs to export */
|
|
30
|
+
exportMode: LogExportMode;
|
|
31
|
+
/** Maximum log level for local retention */
|
|
32
|
+
localMaxLevel: "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
33
|
+
/** Regex patterns to redact from log content */
|
|
34
|
+
redactPatterns: RegExp[];
|
|
35
|
+
/** Fields to never include in exported logs */
|
|
36
|
+
forbiddenFields: Set<string>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get logging policy based on telemetry policy.
|
|
40
|
+
*
|
|
41
|
+
* @param policy - Telemetry policy
|
|
42
|
+
* @returns Logging policy configuration
|
|
43
|
+
*/
|
|
44
|
+
export declare function getLoggingPolicy(policy: TelemetryPolicy): LoggingPolicyConfig;
|
|
45
|
+
/**
|
|
46
|
+
* Log processor that filters and sanitizes logs based on policy.
|
|
47
|
+
*
|
|
48
|
+
* This processor:
|
|
49
|
+
* 1. Blocks all logs if exportMode is LOCAL_ONLY
|
|
50
|
+
* 2. Filters by severity level based on exportMode
|
|
51
|
+
* 3. Sanitizes log body and attributes before forwarding
|
|
52
|
+
*/
|
|
53
|
+
export declare class PolicyAwareLogProcessor implements LogRecordProcessor {
|
|
54
|
+
private readonly policy;
|
|
55
|
+
private readonly delegate;
|
|
56
|
+
constructor(policy: LoggingPolicyConfig, delegate: LogRecordProcessor);
|
|
57
|
+
/**
|
|
58
|
+
* Called when a log record is emitted.
|
|
59
|
+
*/
|
|
60
|
+
onEmit(logRecord: ReadableLogRecord, context?: Context): void;
|
|
61
|
+
/**
|
|
62
|
+
* Sanitize a log record for export.
|
|
63
|
+
* Mutates the log record in place to preserve OTEL SDK internal state.
|
|
64
|
+
*/
|
|
65
|
+
private sanitizeLogRecord;
|
|
66
|
+
/**
|
|
67
|
+
* Check if a string contains a stack trace.
|
|
68
|
+
*/
|
|
69
|
+
private containsStackTrace;
|
|
70
|
+
/**
|
|
71
|
+
* Sanitize log attributes.
|
|
72
|
+
*/
|
|
73
|
+
private sanitizeAttributes;
|
|
74
|
+
/**
|
|
75
|
+
* Shutdown the processor.
|
|
76
|
+
*/
|
|
77
|
+
shutdown(): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Force flush pending logs.
|
|
80
|
+
*/
|
|
81
|
+
forceFlush(): Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=log-processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-processor.d.ts","sourceRoot":"","sources":["../../src/node/log-processor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAiB,MAAM,oBAAoB,CAAC;AAepE;;GAEG;AACH,oBAAY,aAAa;IACvB,+CAA+C;IAC/C,UAAU,eAAe;IACzB,4DAA4D;IAC5D,WAAW,gBAAgB;IAC3B,6DAA6D;IAC7D,cAAc,mBAAmB;CAClC;AAMD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,0BAA0B;IAC1B,UAAU,EAAE,aAAa,CAAC;IAC1B,4CAA4C;IAC5C,aAAa,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IACvE,gDAAgD;IAChD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,+CAA+C;IAC/C,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC9B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,mBAAmB,CAyC7E;AAuDD;;;;;;;GAOG;AACH,qBAAa,uBAAwB,YAAW,kBAAkB;IAChE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;gBAElC,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,kBAAkB;IAKrE;;OAEG;IACH,MAAM,CAAC,SAAS,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;IAsB7D;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAuCzB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAyC1B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAGlC"}
|