@spinajs/telemetry-otel 2.0.507

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.
@@ -0,0 +1,173 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable, Singleton, AsyncService, Autoinject } from '@spinajs/di';
11
+ import { Config } from '@spinajs/configuration';
12
+ import { Log, Logger } from '@spinajs/log';
13
+ import { SpanStatusCode, trace, context, ROOT_CONTEXT } from '@opentelemetry/api';
14
+ import { OtelTracing } from './tracing.js';
15
+ /**
16
+ * Keyed registry for long-lived spans (minutes) that cannot be scoped to one
17
+ * async call — e.g. one root span per payment transaction, opened when the
18
+ * transaction starts and closed by whichever handler sees the terminal state.
19
+ *
20
+ * Every method is a guarded no-op when tracing is disabled, the key is unknown
21
+ * or the underlying OTel call throws: observability must never break the
22
+ * business flow. An orphan sweep force-closes spans that outlive
23
+ * `otel.longSpan.maxAgeMs` (crashed flows, lost terminal messages).
24
+ */
25
+ let LongSpanRegistry = class LongSpanRegistry extends AsyncService {
26
+ constructor() {
27
+ super(...arguments);
28
+ this.spans = new Map();
29
+ }
30
+ /** Open a span under `key`; a stale span on the same key is closed as replaced. */
31
+ open(key, name, attrs) {
32
+ try {
33
+ const stale = this.spans.get(key);
34
+ if (stale) {
35
+ stale.span.setAttribute('replaced', true);
36
+ stale.span.setStatus({ code: SpanStatusCode.ERROR, message: 'replaced by a new span on the same key' });
37
+ stale.span.end();
38
+ this.spans.delete(key);
39
+ }
40
+ const span = this.tracing.tracer('paystation').startSpan(name, { attributes: attrs });
41
+ this.spans.set(key, { span, openedAt: Date.now() });
42
+ this.ensureSweepTimer();
43
+ }
44
+ catch (err) {
45
+ this.log.warn(`long-span open('${key}') failed: ${err.message}`);
46
+ }
47
+ }
48
+ /** Add a span event; no-op when key is undefined/unknown. */
49
+ event(key, name, attrs) {
50
+ try {
51
+ if (!key)
52
+ return;
53
+ this.spans.get(key)?.span.addEvent(name, attrs);
54
+ }
55
+ catch (err) {
56
+ this.log.warn(`long-span event('${key ?? ''}') failed: ${err.message}`);
57
+ }
58
+ }
59
+ setAttributes(key, attrs) {
60
+ try {
61
+ this.spans.get(key)?.span.setAttributes(attrs);
62
+ }
63
+ catch (err) {
64
+ this.log.warn(`long-span setAttributes('${key}') failed: ${err.message}`);
65
+ }
66
+ }
67
+ has(key) {
68
+ return this.spans.has(key);
69
+ }
70
+ /** Close and export the span; no-op for unknown keys. */
71
+ close(key, status, attrs) {
72
+ try {
73
+ const entry = this.spans.get(key);
74
+ if (!entry)
75
+ return;
76
+ if (attrs)
77
+ entry.span.setAttributes(attrs);
78
+ entry.span.setStatus({ code: status === 'ok' ? SpanStatusCode.OK : SpanStatusCode.ERROR });
79
+ entry.span.end();
80
+ this.spans.delete(key);
81
+ if (this.spans.size === 0)
82
+ this.stopSweepTimer();
83
+ }
84
+ catch (err) {
85
+ this.log.warn(`long-span close('${key}') failed: ${err.message}`);
86
+ }
87
+ }
88
+ /**
89
+ * Run `fn` inside a short span, parented into the open long span for `key`
90
+ * when there is one (giving kiosk round-trips a place in the transaction
91
+ * waterfall), standalone otherwise. Errors are recorded and re-thrown.
92
+ */
93
+ async childSpan(key, name, attrs, fn) {
94
+ let span;
95
+ try {
96
+ const parent = key ? this.spans.get(key)?.span : undefined;
97
+ const ctx = parent ? trace.setSpan(ROOT_CONTEXT, parent) : context.active();
98
+ span = this.tracing.tracer('paystation').startSpan(name, { attributes: attrs }, ctx);
99
+ }
100
+ catch (err) {
101
+ this.log.warn(`long-span childSpan('${name}') failed to start: ${err.message}`);
102
+ }
103
+ try {
104
+ const result = await fn();
105
+ span?.setStatus({ code: SpanStatusCode.OK });
106
+ return result;
107
+ }
108
+ catch (err) {
109
+ span?.recordException(err);
110
+ span?.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
111
+ throw err;
112
+ }
113
+ finally {
114
+ span?.end();
115
+ }
116
+ }
117
+ /** Force-close spans that outlived `maxAgeMs` (public for tests). */
118
+ sweep() {
119
+ const cutoff = Date.now() - this.maxAgeMs;
120
+ for (const [key, entry] of this.spans) {
121
+ if (entry.openedAt <= cutoff) {
122
+ this.log.warn(`long-span '${key}' exceeded maxAgeMs; closing as orphaned`);
123
+ entry.span.setAttribute('orphaned', true);
124
+ entry.span.setStatus({ code: SpanStatusCode.ERROR, message: 'span outlived otel.longSpan.maxAgeMs' });
125
+ entry.span.end();
126
+ this.spans.delete(key);
127
+ }
128
+ }
129
+ if (this.spans.size === 0)
130
+ this.stopSweepTimer();
131
+ }
132
+ ensureSweepTimer() {
133
+ if (this.timer)
134
+ return;
135
+ this.timer = setInterval(() => this.sweep(), this.sweepIntervalMs);
136
+ this.timer.unref?.();
137
+ }
138
+ stopSweepTimer() {
139
+ if (!this.timer)
140
+ return;
141
+ clearInterval(this.timer);
142
+ this.timer = undefined;
143
+ }
144
+ async dispose() {
145
+ for (const key of [...this.spans.keys()]) {
146
+ this.close(key, 'error', { shutdown: true });
147
+ }
148
+ this.stopSweepTimer();
149
+ await super.dispose();
150
+ }
151
+ };
152
+ __decorate([
153
+ Logger('otel'),
154
+ __metadata("design:type", Log)
155
+ ], LongSpanRegistry.prototype, "log", void 0);
156
+ __decorate([
157
+ Autoinject(OtelTracing),
158
+ __metadata("design:type", OtelTracing)
159
+ ], LongSpanRegistry.prototype, "tracing", void 0);
160
+ __decorate([
161
+ Config('otel.longSpan.maxAgeMs', { defaultValue: 30 * 60_000 }),
162
+ __metadata("design:type", Number)
163
+ ], LongSpanRegistry.prototype, "maxAgeMs", void 0);
164
+ __decorate([
165
+ Config('otel.longSpan.sweepIntervalMs', { defaultValue: 60_000 }),
166
+ __metadata("design:type", Number)
167
+ ], LongSpanRegistry.prototype, "sweepIntervalMs", void 0);
168
+ LongSpanRegistry = __decorate([
169
+ Singleton(),
170
+ Injectable()
171
+ ], LongSpanRegistry);
172
+ export { LongSpanRegistry };
173
+ //# sourceMappingURL=longSpanRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"longSpanRegistry.js","sourceRoot":"","sources":["../../src/longSpanRegistry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,36 @@
1
+ import { AsyncService } from '@spinajs/di';
2
+ import { Log } from '@spinajs/log';
3
+ import { Tracer, Span, Attributes } from '@opentelemetry/api';
4
+ import { SpanProcessor } from '@opentelemetry/sdk-trace-base';
5
+ /**
6
+ * Boots a private OTel NodeTracerProvider with an OTLP/HTTP trace exporter.
7
+ *
8
+ * Config-driven and disabled by default: with `otel.enabled=false` no provider
9
+ * is created and `tracer()` hands out the OTel API no-op tracer, so call sites
10
+ * cost nothing. The provider is intentionally NOT registered as the OTel
11
+ * global — consumers get tracers through this service.
12
+ *
13
+ * `start( processor )` accepts a processor override so tests can plug an
14
+ * InMemorySpanExporter without any network.
15
+ */
16
+ export declare class OtelTracing extends AsyncService {
17
+ protected log: Log;
18
+ protected enabled: boolean;
19
+ protected endpoint: string;
20
+ protected serviceName: string;
21
+ protected resourceAttributes: Record<string, string>;
22
+ private provider?;
23
+ /**
24
+ * Create the provider (idempotent, no-op when disabled). Call after the
25
+ * Configuration service is resolved so the @Config fields are populated.
26
+ */
27
+ start(processorOverride?: SpanProcessor): void;
28
+ get active(): boolean;
29
+ /** A tracer from the private provider, or the API no-op tracer when off. */
30
+ tracer(name: string): Tracer;
31
+ /** Run `fn` inside a span; records exceptions and sets ERROR status on throw. */
32
+ withSpan<T>(name: string, attrs: Attributes, fn: (span: Span) => Promise<T>): Promise<T>;
33
+ flush(): Promise<void>;
34
+ dispose(): Promise<void>;
35
+ }
36
+ //# sourceMappingURL=tracing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../src/tracing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,YAAY,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAS,MAAM,EAAE,IAAI,EAAkB,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErF,OAAO,EAAsB,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAKlF;;;;;;;;;;GAUG;AACH,qBAEa,WAAY,SAAQ,YAAY;IAE3C,SAAS,CAAC,GAAG,EAAG,GAAG,CAAC;IAGpB,SAAS,CAAC,OAAO,EAAG,OAAO,CAAC;IAG5B,SAAS,CAAC,QAAQ,EAAG,MAAM,CAAC;IAG5B,SAAS,CAAC,WAAW,EAAG,MAAM,CAAC;IAG/B,SAAS,CAAC,kBAAkB,EAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEtD,OAAO,CAAC,QAAQ,CAAC,CAAqB;IAEtC;;;OAGG;IACI,KAAK,CAAC,iBAAiB,CAAC,EAAE,aAAa,GAAG,IAAI,CAWpD;IAED,IAAW,MAAM,IAAI,OAAO,CAE3B;IAED,4EAA4E;IACrE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElC;IAED,iFAAiF;IACpE,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAapG;IAEY,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAElC;IAEY,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAIpC;CACF"}
@@ -0,0 +1,105 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable, Singleton, AsyncService } from '@spinajs/di';
11
+ import { Config } from '@spinajs/configuration';
12
+ import { Log, Logger } from '@spinajs/log';
13
+ import { trace, SpanStatusCode } from '@opentelemetry/api';
14
+ import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
15
+ import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
16
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
17
+ import { resourceFromAttributes } from '@opentelemetry/resources';
18
+ import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
19
+ /**
20
+ * Boots a private OTel NodeTracerProvider with an OTLP/HTTP trace exporter.
21
+ *
22
+ * Config-driven and disabled by default: with `otel.enabled=false` no provider
23
+ * is created and `tracer()` hands out the OTel API no-op tracer, so call sites
24
+ * cost nothing. The provider is intentionally NOT registered as the OTel
25
+ * global — consumers get tracers through this service.
26
+ *
27
+ * `start( processor )` accepts a processor override so tests can plug an
28
+ * InMemorySpanExporter without any network.
29
+ */
30
+ let OtelTracing = class OtelTracing extends AsyncService {
31
+ /**
32
+ * Create the provider (idempotent, no-op when disabled). Call after the
33
+ * Configuration service is resolved so the @Config fields are populated.
34
+ */
35
+ start(processorOverride) {
36
+ if (!this.enabled || this.provider) {
37
+ return;
38
+ }
39
+ const resource = resourceFromAttributes({
40
+ [ATTR_SERVICE_NAME]: this.serviceName,
41
+ ...this.resourceAttributes,
42
+ });
43
+ const processor = processorOverride ?? new BatchSpanProcessor(new OTLPTraceExporter({ url: this.endpoint }));
44
+ this.provider = new NodeTracerProvider({ resource, spanProcessors: [processor] });
45
+ this.log.info(`otel tracing started (service=${this.serviceName}, endpoint=${this.endpoint})`);
46
+ }
47
+ get active() {
48
+ return this.provider !== undefined;
49
+ }
50
+ /** A tracer from the private provider, or the API no-op tracer when off. */
51
+ tracer(name) {
52
+ return this.provider ? this.provider.getTracer(name) : trace.getTracer(name);
53
+ }
54
+ /** Run `fn` inside a span; records exceptions and sets ERROR status on throw. */
55
+ async withSpan(name, attrs, fn) {
56
+ const span = this.tracer('spinajs').startSpan(name, { attributes: attrs });
57
+ try {
58
+ const result = await fn(span);
59
+ span.setStatus({ code: SpanStatusCode.OK });
60
+ return result;
61
+ }
62
+ catch (err) {
63
+ span.recordException(err);
64
+ span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
65
+ throw err;
66
+ }
67
+ finally {
68
+ span.end();
69
+ }
70
+ }
71
+ async flush() {
72
+ await this.provider?.forceFlush();
73
+ }
74
+ async dispose() {
75
+ await this.provider?.shutdown();
76
+ this.provider = undefined;
77
+ await super.dispose();
78
+ }
79
+ };
80
+ __decorate([
81
+ Logger('otel'),
82
+ __metadata("design:type", Log)
83
+ ], OtelTracing.prototype, "log", void 0);
84
+ __decorate([
85
+ Config('otel.enabled', { defaultValue: false }),
86
+ __metadata("design:type", Boolean)
87
+ ], OtelTracing.prototype, "enabled", void 0);
88
+ __decorate([
89
+ Config('otel.endpoint', { defaultValue: 'https://otel.highlight.io:4318/v1/traces' }),
90
+ __metadata("design:type", String)
91
+ ], OtelTracing.prototype, "endpoint", void 0);
92
+ __decorate([
93
+ Config('otel.serviceName', { defaultValue: 'spinajs-app' }),
94
+ __metadata("design:type", String)
95
+ ], OtelTracing.prototype, "serviceName", void 0);
96
+ __decorate([
97
+ Config('otel.resourceAttributes', { defaultValue: {} }),
98
+ __metadata("design:type", Object)
99
+ ], OtelTracing.prototype, "resourceAttributes", void 0);
100
+ OtelTracing = __decorate([
101
+ Singleton(),
102
+ Injectable()
103
+ ], OtelTracing);
104
+ export { OtelTracing };
105
+ //# sourceMappingURL=tracing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing.js","sourceRoot":"","sources":["../../src/tracing.ts"],"names":[],"mappings":"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"}