@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.
- package/lib/cjs/config/otel.d.ts +20 -0
- package/lib/cjs/config/otel.d.ts.map +1 -0
- package/lib/cjs/config/otel.js +22 -0
- package/lib/cjs/config/otel.js.map +1 -0
- package/lib/cjs/index.d.ts +3 -0
- package/lib/cjs/index.d.ts.map +1 -0
- package/lib/cjs/index.js +19 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/cjs/longSpanRegistry.d.ts +42 -0
- package/lib/cjs/longSpanRegistry.d.ts.map +1 -0
- package/lib/cjs/longSpanRegistry.js +176 -0
- package/lib/cjs/longSpanRegistry.js.map +1 -0
- package/lib/cjs/package.json +1 -0
- package/lib/cjs/tracing.d.ts +36 -0
- package/lib/cjs/tracing.d.ts.map +1 -0
- package/lib/cjs/tracing.js +108 -0
- package/lib/cjs/tracing.js.map +1 -0
- package/lib/mjs/config/otel.d.ts +20 -0
- package/lib/mjs/config/otel.d.ts.map +1 -0
- package/lib/mjs/config/otel.js +20 -0
- package/lib/mjs/config/otel.js.map +1 -0
- package/lib/mjs/index.d.ts +3 -0
- package/lib/mjs/index.d.ts.map +1 -0
- package/lib/mjs/index.js +3 -0
- package/lib/mjs/index.js.map +1 -0
- package/lib/mjs/longSpanRegistry.d.ts +42 -0
- package/lib/mjs/longSpanRegistry.d.ts.map +1 -0
- package/lib/mjs/longSpanRegistry.js +173 -0
- package/lib/mjs/longSpanRegistry.js.map +1 -0
- package/lib/mjs/package.json +1 -0
- package/lib/mjs/tracing.d.ts +36 -0
- package/lib/mjs/tracing.d.ts.map +1 -0
- package/lib/mjs/tracing.js +105 -0
- package/lib/mjs/tracing.js.map +1 -0
- package/lib/tsconfig.cjs.tsbuildinfo +1 -0
- package/lib/tsconfig.mjs.tsbuildinfo +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
declare const config: {
|
|
2
|
+
otel: {
|
|
3
|
+
/** Master switch — when false nothing is created and tracers are no-ops. */
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
/** OTLP/HTTP traces endpoint (highlight.io default). */
|
|
6
|
+
endpoint: string;
|
|
7
|
+
/** Reported as the OTel `service.name` resource attribute. */
|
|
8
|
+
serviceName: string;
|
|
9
|
+
/** Extra resource attributes, e.g. { 'highlight.project_id': '...' }. */
|
|
10
|
+
resourceAttributes: Record<string, string>;
|
|
11
|
+
longSpan: {
|
|
12
|
+
/** Spans open longer than this are force-closed as orphaned. */
|
|
13
|
+
maxAgeMs: number;
|
|
14
|
+
/** Orphan sweep cadence. */
|
|
15
|
+
sweepIntervalMs: number;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export default config;
|
|
20
|
+
//# sourceMappingURL=otel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../../../src/config/otel.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,MAAM;IACV,IAAI;QACF,4EAA4E;QAC5E,OAAO;QAEP,wDAAwD;QACxD,QAAQ;QAER,8DAA8D;QAC9D,WAAW;QAEX,yEAAyE;QACzE,kBAAkB,EAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;QAEhD,QAAQ;YACN,gEAAgE;YAChE,QAAQ;YAER,4BAA4B;YAC5B,eAAe;;;CAGpB,CAAC;eAEa,MAAM"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const config = {
|
|
4
|
+
otel: {
|
|
5
|
+
/** Master switch — when false nothing is created and tracers are no-ops. */
|
|
6
|
+
enabled: false,
|
|
7
|
+
/** OTLP/HTTP traces endpoint (highlight.io default). */
|
|
8
|
+
endpoint: 'https://otel.highlight.io:4318/v1/traces',
|
|
9
|
+
/** Reported as the OTel `service.name` resource attribute. */
|
|
10
|
+
serviceName: 'spinajs-app',
|
|
11
|
+
/** Extra resource attributes, e.g. { 'highlight.project_id': '...' }. */
|
|
12
|
+
resourceAttributes: {},
|
|
13
|
+
longSpan: {
|
|
14
|
+
/** Spans open longer than this are force-closed as orphaned. */
|
|
15
|
+
maxAgeMs: 30 * 60_000,
|
|
16
|
+
/** Orphan sweep cadence. */
|
|
17
|
+
sweepIntervalMs: 60_000,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
exports.default = config;
|
|
22
|
+
//# sourceMappingURL=otel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel.js","sourceRoot":"","sources":["../../../src/config/otel.ts"],"names":[],"mappings":";;AAAA,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,4EAA4E;QAC5E,OAAO,EAAE,KAAK;QAEd,wDAAwD;QACxD,QAAQ,EAAE,0CAA0C;QAEpD,8DAA8D;QAC9D,WAAW,EAAE,aAAa;QAE1B,yEAAyE;QACzE,kBAAkB,EAAE,EAA4B;QAEhD,QAAQ,EAAE;YACR,gEAAgE;YAChE,QAAQ,EAAE,EAAE,GAAG,MAAM;YAErB,4BAA4B;YAC5B,eAAe,EAAE,MAAM;SACxB;KACF;CACF,CAAC;kBAEa,MAAM"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC"}
|
package/lib/cjs/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./tracing.js"), exports);
|
|
18
|
+
__exportStar(require("./longSpanRegistry.js"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,wDAAsC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AsyncService } from '@spinajs/di';
|
|
2
|
+
import { Log } from '@spinajs/log';
|
|
3
|
+
import { Attributes } from '@opentelemetry/api';
|
|
4
|
+
import { OtelTracing } from './tracing.js';
|
|
5
|
+
/**
|
|
6
|
+
* Keyed registry for long-lived spans (minutes) that cannot be scoped to one
|
|
7
|
+
* async call — e.g. one root span per payment transaction, opened when the
|
|
8
|
+
* transaction starts and closed by whichever handler sees the terminal state.
|
|
9
|
+
*
|
|
10
|
+
* Every method is a guarded no-op when tracing is disabled, the key is unknown
|
|
11
|
+
* or the underlying OTel call throws: observability must never break the
|
|
12
|
+
* business flow. An orphan sweep force-closes spans that outlive
|
|
13
|
+
* `otel.longSpan.maxAgeMs` (crashed flows, lost terminal messages).
|
|
14
|
+
*/
|
|
15
|
+
export declare class LongSpanRegistry extends AsyncService {
|
|
16
|
+
protected log: Log;
|
|
17
|
+
protected tracing: OtelTracing;
|
|
18
|
+
protected maxAgeMs: number;
|
|
19
|
+
protected sweepIntervalMs: number;
|
|
20
|
+
private readonly spans;
|
|
21
|
+
private timer?;
|
|
22
|
+
/** Open a span under `key`; a stale span on the same key is closed as replaced. */
|
|
23
|
+
open(key: string, name: string, attrs?: Attributes): void;
|
|
24
|
+
/** Add a span event; no-op when key is undefined/unknown. */
|
|
25
|
+
event(key: string | undefined, name: string, attrs?: Attributes): void;
|
|
26
|
+
setAttributes(key: string, attrs: Attributes): void;
|
|
27
|
+
has(key: string): boolean;
|
|
28
|
+
/** Close and export the span; no-op for unknown keys. */
|
|
29
|
+
close(key: string, status: 'ok' | 'error', attrs?: Attributes): void;
|
|
30
|
+
/**
|
|
31
|
+
* Run `fn` inside a short span, parented into the open long span for `key`
|
|
32
|
+
* when there is one (giving kiosk round-trips a place in the transaction
|
|
33
|
+
* waterfall), standalone otherwise. Errors are recorded and re-thrown.
|
|
34
|
+
*/
|
|
35
|
+
childSpan<T>(key: string | undefined, name: string, attrs: Attributes, fn: () => Promise<T>): Promise<T>;
|
|
36
|
+
/** Force-close spans that outlived `maxAgeMs` (public for tests). */
|
|
37
|
+
sweep(): void;
|
|
38
|
+
private ensureSweepTimer;
|
|
39
|
+
private stopSweepTimer;
|
|
40
|
+
dispose(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=longSpanRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"longSpanRegistry.d.ts","sourceRoot":"","sources":["../../src/longSpanRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,YAAY,EAAc,MAAM,aAAa,CAAC;AAE9E,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAwB,UAAU,EAAgC,MAAM,oBAAoB,CAAC;AACpG,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAO3C;;;;;;;;;GASG;AACH,qBAEa,gBAAiB,SAAQ,YAAY;IAEhD,SAAS,CAAC,GAAG,EAAG,GAAG,CAAC;IAGpB,SAAS,CAAC,OAAO,EAAG,WAAW,CAAC;IAGhC,SAAS,CAAC,QAAQ,EAAG,MAAM,CAAC;IAG5B,SAAS,CAAC,eAAe,EAAG,MAAM,CAAC;IAEnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,OAAO,CAAC,KAAK,CAAC,CAAiB;IAE/B,mFAAmF;IAC5E,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAe/D;IAED,6DAA6D;IACtD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAO5E;IAEM,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAMzD;IAEM,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/B;IAED,yDAAyD;IAClD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,OAAO,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAY1E;IAED;;;;OAIG;IACU,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAoBpH;IAED,qEAAqE;IAC9D,KAAK,IAAI,IAAI,CAYnB;IAED,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,cAAc;IAMT,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAMpC;CACF"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.LongSpanRegistry = void 0;
|
|
13
|
+
const di_1 = require("@spinajs/di");
|
|
14
|
+
const configuration_1 = require("@spinajs/configuration");
|
|
15
|
+
const log_1 = require("@spinajs/log");
|
|
16
|
+
const api_1 = require("@opentelemetry/api");
|
|
17
|
+
const tracing_js_1 = require("./tracing.js");
|
|
18
|
+
/**
|
|
19
|
+
* Keyed registry for long-lived spans (minutes) that cannot be scoped to one
|
|
20
|
+
* async call — e.g. one root span per payment transaction, opened when the
|
|
21
|
+
* transaction starts and closed by whichever handler sees the terminal state.
|
|
22
|
+
*
|
|
23
|
+
* Every method is a guarded no-op when tracing is disabled, the key is unknown
|
|
24
|
+
* or the underlying OTel call throws: observability must never break the
|
|
25
|
+
* business flow. An orphan sweep force-closes spans that outlive
|
|
26
|
+
* `otel.longSpan.maxAgeMs` (crashed flows, lost terminal messages).
|
|
27
|
+
*/
|
|
28
|
+
let LongSpanRegistry = class LongSpanRegistry extends di_1.AsyncService {
|
|
29
|
+
constructor() {
|
|
30
|
+
super(...arguments);
|
|
31
|
+
this.spans = new Map();
|
|
32
|
+
}
|
|
33
|
+
/** Open a span under `key`; a stale span on the same key is closed as replaced. */
|
|
34
|
+
open(key, name, attrs) {
|
|
35
|
+
try {
|
|
36
|
+
const stale = this.spans.get(key);
|
|
37
|
+
if (stale) {
|
|
38
|
+
stale.span.setAttribute('replaced', true);
|
|
39
|
+
stale.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: 'replaced by a new span on the same key' });
|
|
40
|
+
stale.span.end();
|
|
41
|
+
this.spans.delete(key);
|
|
42
|
+
}
|
|
43
|
+
const span = this.tracing.tracer('paystation').startSpan(name, { attributes: attrs });
|
|
44
|
+
this.spans.set(key, { span, openedAt: Date.now() });
|
|
45
|
+
this.ensureSweepTimer();
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
this.log.warn(`long-span open('${key}') failed: ${err.message}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Add a span event; no-op when key is undefined/unknown. */
|
|
52
|
+
event(key, name, attrs) {
|
|
53
|
+
try {
|
|
54
|
+
if (!key)
|
|
55
|
+
return;
|
|
56
|
+
this.spans.get(key)?.span.addEvent(name, attrs);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
this.log.warn(`long-span event('${key ?? ''}') failed: ${err.message}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
setAttributes(key, attrs) {
|
|
63
|
+
try {
|
|
64
|
+
this.spans.get(key)?.span.setAttributes(attrs);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
this.log.warn(`long-span setAttributes('${key}') failed: ${err.message}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
has(key) {
|
|
71
|
+
return this.spans.has(key);
|
|
72
|
+
}
|
|
73
|
+
/** Close and export the span; no-op for unknown keys. */
|
|
74
|
+
close(key, status, attrs) {
|
|
75
|
+
try {
|
|
76
|
+
const entry = this.spans.get(key);
|
|
77
|
+
if (!entry)
|
|
78
|
+
return;
|
|
79
|
+
if (attrs)
|
|
80
|
+
entry.span.setAttributes(attrs);
|
|
81
|
+
entry.span.setStatus({ code: status === 'ok' ? api_1.SpanStatusCode.OK : api_1.SpanStatusCode.ERROR });
|
|
82
|
+
entry.span.end();
|
|
83
|
+
this.spans.delete(key);
|
|
84
|
+
if (this.spans.size === 0)
|
|
85
|
+
this.stopSweepTimer();
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
this.log.warn(`long-span close('${key}') failed: ${err.message}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Run `fn` inside a short span, parented into the open long span for `key`
|
|
93
|
+
* when there is one (giving kiosk round-trips a place in the transaction
|
|
94
|
+
* waterfall), standalone otherwise. Errors are recorded and re-thrown.
|
|
95
|
+
*/
|
|
96
|
+
async childSpan(key, name, attrs, fn) {
|
|
97
|
+
let span;
|
|
98
|
+
try {
|
|
99
|
+
const parent = key ? this.spans.get(key)?.span : undefined;
|
|
100
|
+
const ctx = parent ? api_1.trace.setSpan(api_1.ROOT_CONTEXT, parent) : api_1.context.active();
|
|
101
|
+
span = this.tracing.tracer('paystation').startSpan(name, { attributes: attrs }, ctx);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
this.log.warn(`long-span childSpan('${name}') failed to start: ${err.message}`);
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const result = await fn();
|
|
108
|
+
span?.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
span?.recordException(err);
|
|
113
|
+
span?.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err.message });
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
span?.end();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Force-close spans that outlived `maxAgeMs` (public for tests). */
|
|
121
|
+
sweep() {
|
|
122
|
+
const cutoff = Date.now() - this.maxAgeMs;
|
|
123
|
+
for (const [key, entry] of this.spans) {
|
|
124
|
+
if (entry.openedAt <= cutoff) {
|
|
125
|
+
this.log.warn(`long-span '${key}' exceeded maxAgeMs; closing as orphaned`);
|
|
126
|
+
entry.span.setAttribute('orphaned', true);
|
|
127
|
+
entry.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: 'span outlived otel.longSpan.maxAgeMs' });
|
|
128
|
+
entry.span.end();
|
|
129
|
+
this.spans.delete(key);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (this.spans.size === 0)
|
|
133
|
+
this.stopSweepTimer();
|
|
134
|
+
}
|
|
135
|
+
ensureSweepTimer() {
|
|
136
|
+
if (this.timer)
|
|
137
|
+
return;
|
|
138
|
+
this.timer = setInterval(() => this.sweep(), this.sweepIntervalMs);
|
|
139
|
+
this.timer.unref?.();
|
|
140
|
+
}
|
|
141
|
+
stopSweepTimer() {
|
|
142
|
+
if (!this.timer)
|
|
143
|
+
return;
|
|
144
|
+
clearInterval(this.timer);
|
|
145
|
+
this.timer = undefined;
|
|
146
|
+
}
|
|
147
|
+
async dispose() {
|
|
148
|
+
for (const key of [...this.spans.keys()]) {
|
|
149
|
+
this.close(key, 'error', { shutdown: true });
|
|
150
|
+
}
|
|
151
|
+
this.stopSweepTimer();
|
|
152
|
+
await super.dispose();
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
exports.LongSpanRegistry = LongSpanRegistry;
|
|
156
|
+
__decorate([
|
|
157
|
+
(0, log_1.Logger)('otel'),
|
|
158
|
+
__metadata("design:type", log_1.Log)
|
|
159
|
+
], LongSpanRegistry.prototype, "log", void 0);
|
|
160
|
+
__decorate([
|
|
161
|
+
(0, di_1.Autoinject)(tracing_js_1.OtelTracing),
|
|
162
|
+
__metadata("design:type", tracing_js_1.OtelTracing)
|
|
163
|
+
], LongSpanRegistry.prototype, "tracing", void 0);
|
|
164
|
+
__decorate([
|
|
165
|
+
(0, configuration_1.Config)('otel.longSpan.maxAgeMs', { defaultValue: 30 * 60_000 }),
|
|
166
|
+
__metadata("design:type", Number)
|
|
167
|
+
], LongSpanRegistry.prototype, "maxAgeMs", void 0);
|
|
168
|
+
__decorate([
|
|
169
|
+
(0, configuration_1.Config)('otel.longSpan.sweepIntervalMs', { defaultValue: 60_000 }),
|
|
170
|
+
__metadata("design:type", Number)
|
|
171
|
+
], LongSpanRegistry.prototype, "sweepIntervalMs", void 0);
|
|
172
|
+
exports.LongSpanRegistry = LongSpanRegistry = __decorate([
|
|
173
|
+
(0, di_1.Singleton)(),
|
|
174
|
+
(0, di_1.Injectable)()
|
|
175
|
+
], LongSpanRegistry);
|
|
176
|
+
//# 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":"commonjs"}
|
|
@@ -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,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.OtelTracing = void 0;
|
|
13
|
+
const di_1 = require("@spinajs/di");
|
|
14
|
+
const configuration_1 = require("@spinajs/configuration");
|
|
15
|
+
const log_1 = require("@spinajs/log");
|
|
16
|
+
const api_1 = require("@opentelemetry/api");
|
|
17
|
+
const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
|
|
18
|
+
const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
|
|
19
|
+
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
|
|
20
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
21
|
+
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
22
|
+
/**
|
|
23
|
+
* Boots a private OTel NodeTracerProvider with an OTLP/HTTP trace exporter.
|
|
24
|
+
*
|
|
25
|
+
* Config-driven and disabled by default: with `otel.enabled=false` no provider
|
|
26
|
+
* is created and `tracer()` hands out the OTel API no-op tracer, so call sites
|
|
27
|
+
* cost nothing. The provider is intentionally NOT registered as the OTel
|
|
28
|
+
* global — consumers get tracers through this service.
|
|
29
|
+
*
|
|
30
|
+
* `start( processor )` accepts a processor override so tests can plug an
|
|
31
|
+
* InMemorySpanExporter without any network.
|
|
32
|
+
*/
|
|
33
|
+
let OtelTracing = class OtelTracing extends di_1.AsyncService {
|
|
34
|
+
/**
|
|
35
|
+
* Create the provider (idempotent, no-op when disabled). Call after the
|
|
36
|
+
* Configuration service is resolved so the @Config fields are populated.
|
|
37
|
+
*/
|
|
38
|
+
start(processorOverride) {
|
|
39
|
+
if (!this.enabled || this.provider) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const resource = (0, resources_1.resourceFromAttributes)({
|
|
43
|
+
[semantic_conventions_1.ATTR_SERVICE_NAME]: this.serviceName,
|
|
44
|
+
...this.resourceAttributes,
|
|
45
|
+
});
|
|
46
|
+
const processor = processorOverride ?? new sdk_trace_base_1.BatchSpanProcessor(new exporter_trace_otlp_http_1.OTLPTraceExporter({ url: this.endpoint }));
|
|
47
|
+
this.provider = new sdk_trace_node_1.NodeTracerProvider({ resource, spanProcessors: [processor] });
|
|
48
|
+
this.log.info(`otel tracing started (service=${this.serviceName}, endpoint=${this.endpoint})`);
|
|
49
|
+
}
|
|
50
|
+
get active() {
|
|
51
|
+
return this.provider !== undefined;
|
|
52
|
+
}
|
|
53
|
+
/** A tracer from the private provider, or the API no-op tracer when off. */
|
|
54
|
+
tracer(name) {
|
|
55
|
+
return this.provider ? this.provider.getTracer(name) : api_1.trace.getTracer(name);
|
|
56
|
+
}
|
|
57
|
+
/** Run `fn` inside a span; records exceptions and sets ERROR status on throw. */
|
|
58
|
+
async withSpan(name, attrs, fn) {
|
|
59
|
+
const span = this.tracer('spinajs').startSpan(name, { attributes: attrs });
|
|
60
|
+
try {
|
|
61
|
+
const result = await fn(span);
|
|
62
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
span.recordException(err);
|
|
67
|
+
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err.message });
|
|
68
|
+
throw err;
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
span.end();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async flush() {
|
|
75
|
+
await this.provider?.forceFlush();
|
|
76
|
+
}
|
|
77
|
+
async dispose() {
|
|
78
|
+
await this.provider?.shutdown();
|
|
79
|
+
this.provider = undefined;
|
|
80
|
+
await super.dispose();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
exports.OtelTracing = OtelTracing;
|
|
84
|
+
__decorate([
|
|
85
|
+
(0, log_1.Logger)('otel'),
|
|
86
|
+
__metadata("design:type", log_1.Log)
|
|
87
|
+
], OtelTracing.prototype, "log", void 0);
|
|
88
|
+
__decorate([
|
|
89
|
+
(0, configuration_1.Config)('otel.enabled', { defaultValue: false }),
|
|
90
|
+
__metadata("design:type", Boolean)
|
|
91
|
+
], OtelTracing.prototype, "enabled", void 0);
|
|
92
|
+
__decorate([
|
|
93
|
+
(0, configuration_1.Config)('otel.endpoint', { defaultValue: 'https://otel.highlight.io:4318/v1/traces' }),
|
|
94
|
+
__metadata("design:type", String)
|
|
95
|
+
], OtelTracing.prototype, "endpoint", void 0);
|
|
96
|
+
__decorate([
|
|
97
|
+
(0, configuration_1.Config)('otel.serviceName', { defaultValue: 'spinajs-app' }),
|
|
98
|
+
__metadata("design:type", String)
|
|
99
|
+
], OtelTracing.prototype, "serviceName", void 0);
|
|
100
|
+
__decorate([
|
|
101
|
+
(0, configuration_1.Config)('otel.resourceAttributes', { defaultValue: {} }),
|
|
102
|
+
__metadata("design:type", Object)
|
|
103
|
+
], OtelTracing.prototype, "resourceAttributes", void 0);
|
|
104
|
+
exports.OtelTracing = OtelTracing = __decorate([
|
|
105
|
+
(0, di_1.Singleton)(),
|
|
106
|
+
(0, di_1.Injectable)()
|
|
107
|
+
], OtelTracing);
|
|
108
|
+
//# sourceMappingURL=tracing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracing.js","sourceRoot":"","sources":["../../src/tracing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
declare const config: {
|
|
2
|
+
otel: {
|
|
3
|
+
/** Master switch — when false nothing is created and tracers are no-ops. */
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
/** OTLP/HTTP traces endpoint (highlight.io default). */
|
|
6
|
+
endpoint: string;
|
|
7
|
+
/** Reported as the OTel `service.name` resource attribute. */
|
|
8
|
+
serviceName: string;
|
|
9
|
+
/** Extra resource attributes, e.g. { 'highlight.project_id': '...' }. */
|
|
10
|
+
resourceAttributes: Record<string, string>;
|
|
11
|
+
longSpan: {
|
|
12
|
+
/** Spans open longer than this are force-closed as orphaned. */
|
|
13
|
+
maxAgeMs: number;
|
|
14
|
+
/** Orphan sweep cadence. */
|
|
15
|
+
sweepIntervalMs: number;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export default config;
|
|
20
|
+
//# sourceMappingURL=otel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../../../src/config/otel.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,MAAM;IACV,IAAI;QACF,4EAA4E;QAC5E,OAAO;QAEP,wDAAwD;QACxD,QAAQ;QAER,8DAA8D;QAC9D,WAAW;QAEX,yEAAyE;QACzE,kBAAkB,EAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;QAEhD,QAAQ;YACN,gEAAgE;YAChE,QAAQ;YAER,4BAA4B;YAC5B,eAAe;;;CAGpB,CAAC;eAEa,MAAM"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const config = {
|
|
2
|
+
otel: {
|
|
3
|
+
/** Master switch — when false nothing is created and tracers are no-ops. */
|
|
4
|
+
enabled: false,
|
|
5
|
+
/** OTLP/HTTP traces endpoint (highlight.io default). */
|
|
6
|
+
endpoint: 'https://otel.highlight.io:4318/v1/traces',
|
|
7
|
+
/** Reported as the OTel `service.name` resource attribute. */
|
|
8
|
+
serviceName: 'spinajs-app',
|
|
9
|
+
/** Extra resource attributes, e.g. { 'highlight.project_id': '...' }. */
|
|
10
|
+
resourceAttributes: {},
|
|
11
|
+
longSpan: {
|
|
12
|
+
/** Spans open longer than this are force-closed as orphaned. */
|
|
13
|
+
maxAgeMs: 30 * 60_000,
|
|
14
|
+
/** Orphan sweep cadence. */
|
|
15
|
+
sweepIntervalMs: 60_000,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
export default config;
|
|
20
|
+
//# sourceMappingURL=otel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel.js","sourceRoot":"","sources":["../../../src/config/otel.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,4EAA4E;QAC5E,OAAO,EAAE,KAAK;QAEd,wDAAwD;QACxD,QAAQ,EAAE,0CAA0C;QAEpD,8DAA8D;QAC9D,WAAW,EAAE,aAAa;QAE1B,yEAAyE;QACzE,kBAAkB,EAAE,EAA4B;QAEhD,QAAQ,EAAE;YACR,gEAAgE;YAChE,QAAQ,EAAE,EAAE,GAAG,MAAM;YAErB,4BAA4B;YAC5B,eAAe,EAAE,MAAM;SACxB;KACF;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC"}
|
package/lib/mjs/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AsyncService } from '@spinajs/di';
|
|
2
|
+
import { Log } from '@spinajs/log';
|
|
3
|
+
import { Attributes } from '@opentelemetry/api';
|
|
4
|
+
import { OtelTracing } from './tracing.js';
|
|
5
|
+
/**
|
|
6
|
+
* Keyed registry for long-lived spans (minutes) that cannot be scoped to one
|
|
7
|
+
* async call — e.g. one root span per payment transaction, opened when the
|
|
8
|
+
* transaction starts and closed by whichever handler sees the terminal state.
|
|
9
|
+
*
|
|
10
|
+
* Every method is a guarded no-op when tracing is disabled, the key is unknown
|
|
11
|
+
* or the underlying OTel call throws: observability must never break the
|
|
12
|
+
* business flow. An orphan sweep force-closes spans that outlive
|
|
13
|
+
* `otel.longSpan.maxAgeMs` (crashed flows, lost terminal messages).
|
|
14
|
+
*/
|
|
15
|
+
export declare class LongSpanRegistry extends AsyncService {
|
|
16
|
+
protected log: Log;
|
|
17
|
+
protected tracing: OtelTracing;
|
|
18
|
+
protected maxAgeMs: number;
|
|
19
|
+
protected sweepIntervalMs: number;
|
|
20
|
+
private readonly spans;
|
|
21
|
+
private timer?;
|
|
22
|
+
/** Open a span under `key`; a stale span on the same key is closed as replaced. */
|
|
23
|
+
open(key: string, name: string, attrs?: Attributes): void;
|
|
24
|
+
/** Add a span event; no-op when key is undefined/unknown. */
|
|
25
|
+
event(key: string | undefined, name: string, attrs?: Attributes): void;
|
|
26
|
+
setAttributes(key: string, attrs: Attributes): void;
|
|
27
|
+
has(key: string): boolean;
|
|
28
|
+
/** Close and export the span; no-op for unknown keys. */
|
|
29
|
+
close(key: string, status: 'ok' | 'error', attrs?: Attributes): void;
|
|
30
|
+
/**
|
|
31
|
+
* Run `fn` inside a short span, parented into the open long span for `key`
|
|
32
|
+
* when there is one (giving kiosk round-trips a place in the transaction
|
|
33
|
+
* waterfall), standalone otherwise. Errors are recorded and re-thrown.
|
|
34
|
+
*/
|
|
35
|
+
childSpan<T>(key: string | undefined, name: string, attrs: Attributes, fn: () => Promise<T>): Promise<T>;
|
|
36
|
+
/** Force-close spans that outlived `maxAgeMs` (public for tests). */
|
|
37
|
+
sweep(): void;
|
|
38
|
+
private ensureSweepTimer;
|
|
39
|
+
private stopSweepTimer;
|
|
40
|
+
dispose(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=longSpanRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"longSpanRegistry.d.ts","sourceRoot":"","sources":["../../src/longSpanRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,YAAY,EAAc,MAAM,aAAa,CAAC;AAE9E,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAwB,UAAU,EAAgC,MAAM,oBAAoB,CAAC;AACpG,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAO3C;;;;;;;;;GASG;AACH,qBAEa,gBAAiB,SAAQ,YAAY;IAEhD,SAAS,CAAC,GAAG,EAAG,GAAG,CAAC;IAGpB,SAAS,CAAC,OAAO,EAAG,WAAW,CAAC;IAGhC,SAAS,CAAC,QAAQ,EAAG,MAAM,CAAC;IAG5B,SAAS,CAAC,eAAe,EAAG,MAAM,CAAC;IAEnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,OAAO,CAAC,KAAK,CAAC,CAAiB;IAE/B,mFAAmF;IAC5E,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAe/D;IAED,6DAA6D;IACtD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAO5E;IAEM,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAMzD;IAEM,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/B;IAED,yDAAyD;IAClD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,OAAO,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAY1E;IAED;;;;OAIG;IACU,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAoBpH;IAED,qEAAqE;IAC9D,KAAK,IAAI,IAAI,CAYnB;IAED,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,cAAc;IAMT,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAMpC;CACF"}
|