@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,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":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAQ,cAAc,EAAc,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACpG,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAO3C;;;;;;;;;GASG;AAGI,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,YAAY;IAA3C;;QAaY,UAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAuHxD,CAAC;IApHC,mFAAmF;IAC5E,IAAI,CAAC,GAAW,EAAE,IAAY,EAAE,KAAkB;QACvD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,KAAK,EAAE,CAAC;gBACV,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;gBAC1C,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,wCAAwC,EAAE,CAAC,CAAC;gBACxG,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACjB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;YACtF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACpD,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,GAAG,cAAe,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;IAED,6DAA6D;IACtD,KAAK,CAAC,GAAuB,EAAE,IAAY,EAAE,KAAkB;QACpE,IAAI,CAAC;YACH,IAAI,CAAC,GAAG;gBAAE,OAAO;YACjB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,GAAG,IAAI,EAAE,cAAe,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IAEM,aAAa,CAAC,GAAW,EAAE,KAAiB;QACjD,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,4BAA4B,GAAG,cAAe,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAEM,GAAG,CAAC,GAAW;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,yDAAyD;IAClD,KAAK,CAAC,GAAW,EAAE,MAAsB,EAAE,KAAkB;QAClE,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,IAAI,KAAK;gBAAE,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC3C,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC;YAC3F,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACjB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;gBAAE,IAAI,CAAC,cAAc,EAAE,CAAC;QACnD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,GAAG,cAAe,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,SAAS,CAAI,GAAuB,EAAE,IAAY,EAAE,KAAiB,EAAE,EAAoB;QACtG,IAAI,IAAsB,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;YAC3D,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAC5E,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,GAAG,CAAC,CAAC;QACvF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,wBAAwB,IAAI,uBAAwB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7F,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;YAC1B,IAAI,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7C,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,EAAE,eAAe,CAAC,GAAY,CAAC,CAAC;YACpC,IAAI,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,OAAO,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YACjF,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,IAAI,EAAE,GAAG,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAED,qEAAqE;IAC9D,KAAK;QACV,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACtC,IAAI,KAAK,CAAC,QAAQ,IAAI,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,GAAG,0CAA0C,CAAC,CAAC;gBAC3E,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;gBAC1C,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,sCAAsC,EAAE,CAAC,CAAC;gBACtG,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACjB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,cAAc,EAAE,CAAC;IACnD,CAAC;IAEO,gBAAgB;QACtB,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;QACnE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IACvB,CAAC;IAEO,cAAc;QACpB,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO;QACxB,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;IACzB,CAAC;IAEM,KAAK,CAAC,OAAO;QAClB,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;CACF,CAAA;AAlIW;IADT,MAAM,CAAC,MAAM,CAAC;8BACC,GAAG;6CAAC;AAGV;IADT,UAAU,CAAC,WAAW,CAAC;8BACJ,WAAW;iDAAC;AAGtB;IADT,MAAM,CAAC,wBAAwB,EAAE,EAAE,YAAY,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC;;kDACpC;AAGlB;IADT,MAAM,CAAC,+BAA+B,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;;yDAC/B;AAXxB,gBAAgB;IAF5B,SAAS,EAAE;IACX,UAAU,EAAE;GACA,gBAAgB,CAoI5B"}
|
|
@@ -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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"}
|