tracebeam-sdk 0.1.0 → 0.2.0
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/dist/index.d.mts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +735 -377
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +722 -376
- package/dist/index.mjs.map +1 -1
- package/dist/integrations/express.d.mts +26 -2
- package/dist/integrations/express.d.ts +26 -2
- package/dist/integrations/express.js +30 -0
- package/dist/integrations/express.js.map +1 -1
- package/dist/integrations/express.mjs +29 -0
- package/dist/integrations/express.mjs.map +1 -1
- package/dist/integrations/fastify.d.mts +1 -1
- package/dist/integrations/fastify.d.ts +1 -1
- package/dist/integrations/fastify.js.map +1 -1
- package/dist/integrations/fastify.mjs.map +1 -1
- package/dist/{client-CaHega3m.d.mts → sdk-bh44OWR9.d.mts} +11 -80
- package/dist/{client-CaHega3m.d.ts → sdk-bh44OWR9.d.ts} +11 -80
- package/package.json +16 -7
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,613 @@
|
|
|
1
|
+
// src/sdk.ts
|
|
2
|
+
import * as api from "@opentelemetry/api";
|
|
3
|
+
|
|
4
|
+
// node_modules/@opentelemetry/core/build/esm/trace/suppress-tracing.js
|
|
5
|
+
import { createContextKey } from "@opentelemetry/api";
|
|
6
|
+
var SUPPRESS_TRACING_KEY = createContextKey("OpenTelemetry SDK Context Key SUPPRESS_TRACING");
|
|
7
|
+
function suppressTracing(context3) {
|
|
8
|
+
return context3.setValue(SUPPRESS_TRACING_KEY, true);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// node_modules/@opentelemetry/core/build/esm/common/logging-error-handler.js
|
|
12
|
+
import { diag } from "@opentelemetry/api";
|
|
13
|
+
function loggingErrorHandler() {
|
|
14
|
+
return (ex) => {
|
|
15
|
+
diag.error(stringifyException(ex));
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function stringifyException(ex) {
|
|
19
|
+
if (typeof ex === "string") {
|
|
20
|
+
return ex;
|
|
21
|
+
} else {
|
|
22
|
+
return JSON.stringify(flattenException(ex));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function flattenException(ex) {
|
|
26
|
+
const result = {};
|
|
27
|
+
let current = ex;
|
|
28
|
+
while (current !== null) {
|
|
29
|
+
Object.getOwnPropertyNames(current).forEach((propertyName) => {
|
|
30
|
+
if (result[propertyName])
|
|
31
|
+
return;
|
|
32
|
+
const value = current[propertyName];
|
|
33
|
+
if (value) {
|
|
34
|
+
result[propertyName] = String(value);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
current = Object.getPrototypeOf(current);
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// node_modules/@opentelemetry/core/build/esm/common/global-error-handler.js
|
|
43
|
+
var delegateHandler = loggingErrorHandler();
|
|
44
|
+
function globalErrorHandler(ex) {
|
|
45
|
+
try {
|
|
46
|
+
delegateHandler(ex);
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// node_modules/@opentelemetry/core/build/esm/platform/node/environment.js
|
|
52
|
+
import { diag as diag2 } from "@opentelemetry/api";
|
|
53
|
+
import { inspect } from "util";
|
|
54
|
+
function getNumberFromEnv(key) {
|
|
55
|
+
const raw = process.env[key];
|
|
56
|
+
if (raw == null || raw.trim() === "") {
|
|
57
|
+
return void 0;
|
|
58
|
+
}
|
|
59
|
+
const value = Number(raw);
|
|
60
|
+
if (isNaN(value)) {
|
|
61
|
+
diag2.warn(`Unknown value ${inspect(raw)} for ${key}, expected a number, using defaults`);
|
|
62
|
+
return void 0;
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// node_modules/@opentelemetry/core/build/esm/common/time.js
|
|
68
|
+
var NANOSECOND_DIGITS = 9;
|
|
69
|
+
var NANOSECOND_DIGITS_IN_MILLIS = 6;
|
|
70
|
+
var MILLISECONDS_TO_NANOSECONDS = Math.pow(10, NANOSECOND_DIGITS_IN_MILLIS);
|
|
71
|
+
var SECOND_TO_NANOSECONDS = Math.pow(10, NANOSECOND_DIGITS);
|
|
72
|
+
function hrTimeToMicroseconds(time) {
|
|
73
|
+
return time[0] * 1e6 + time[1] / 1e3;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// node_modules/@opentelemetry/core/build/esm/ExportResult.js
|
|
77
|
+
var ExportResultCode;
|
|
78
|
+
(function(ExportResultCode2) {
|
|
79
|
+
ExportResultCode2[ExportResultCode2["SUCCESS"] = 0] = "SUCCESS";
|
|
80
|
+
ExportResultCode2[ExportResultCode2["FAILED"] = 1] = "FAILED";
|
|
81
|
+
})(ExportResultCode || (ExportResultCode = {}));
|
|
82
|
+
|
|
83
|
+
// node_modules/@opentelemetry/core/build/esm/utils/promise.js
|
|
84
|
+
var Deferred = class {
|
|
85
|
+
_promise;
|
|
86
|
+
_resolve;
|
|
87
|
+
_reject;
|
|
88
|
+
constructor() {
|
|
89
|
+
this._promise = new Promise((resolve, reject) => {
|
|
90
|
+
this._resolve = resolve;
|
|
91
|
+
this._reject = reject;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
get promise() {
|
|
95
|
+
return this._promise;
|
|
96
|
+
}
|
|
97
|
+
resolve(val) {
|
|
98
|
+
this._resolve(val);
|
|
99
|
+
}
|
|
100
|
+
reject(err) {
|
|
101
|
+
this._reject(err);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// node_modules/@opentelemetry/core/build/esm/utils/callback.js
|
|
106
|
+
var BindOnceFuture = class {
|
|
107
|
+
_isCalled = false;
|
|
108
|
+
_deferred = new Deferred();
|
|
109
|
+
_callback;
|
|
110
|
+
_that;
|
|
111
|
+
constructor(callback, that) {
|
|
112
|
+
this._callback = callback;
|
|
113
|
+
this._that = that;
|
|
114
|
+
}
|
|
115
|
+
get isCalled() {
|
|
116
|
+
return this._isCalled;
|
|
117
|
+
}
|
|
118
|
+
get promise() {
|
|
119
|
+
return this._deferred.promise;
|
|
120
|
+
}
|
|
121
|
+
call(...args) {
|
|
122
|
+
if (!this._isCalled) {
|
|
123
|
+
this._isCalled = true;
|
|
124
|
+
try {
|
|
125
|
+
Promise.resolve(this._callback.call(this._that, ...args)).then((val) => this._deferred.resolve(val), (err) => this._deferred.reject(err));
|
|
126
|
+
} catch (err) {
|
|
127
|
+
this._deferred.reject(err);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return this._deferred.promise;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// node_modules/@opentelemetry/core/build/esm/internal/exporter.js
|
|
135
|
+
import { context } from "@opentelemetry/api";
|
|
136
|
+
function _export(exporter, arg) {
|
|
137
|
+
return new Promise((resolve) => {
|
|
138
|
+
context.with(suppressTracing(context.active()), () => {
|
|
139
|
+
exporter.export(arg, (result) => {
|
|
140
|
+
resolve(result);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// node_modules/@opentelemetry/core/build/esm/index.js
|
|
147
|
+
var internal = {
|
|
148
|
+
_export
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// node_modules/@opentelemetry/sdk-trace-base/build/esm/export/BatchSpanProcessorBase.js
|
|
152
|
+
import { context as context2, diag as diag3, TraceFlags } from "@opentelemetry/api";
|
|
153
|
+
var BatchSpanProcessorBase = class {
|
|
154
|
+
_maxExportBatchSize;
|
|
155
|
+
_maxQueueSize;
|
|
156
|
+
_scheduledDelayMillis;
|
|
157
|
+
_exportTimeoutMillis;
|
|
158
|
+
_exporter;
|
|
159
|
+
_isExporting = false;
|
|
160
|
+
_finishedSpans = [];
|
|
161
|
+
_timer;
|
|
162
|
+
_shutdownOnce;
|
|
163
|
+
_droppedSpansCount = 0;
|
|
164
|
+
constructor(exporter, config) {
|
|
165
|
+
this._exporter = exporter;
|
|
166
|
+
this._maxExportBatchSize = typeof config?.maxExportBatchSize === "number" ? config.maxExportBatchSize : getNumberFromEnv("OTEL_BSP_MAX_EXPORT_BATCH_SIZE") ?? 512;
|
|
167
|
+
this._maxQueueSize = typeof config?.maxQueueSize === "number" ? config.maxQueueSize : getNumberFromEnv("OTEL_BSP_MAX_QUEUE_SIZE") ?? 2048;
|
|
168
|
+
this._scheduledDelayMillis = typeof config?.scheduledDelayMillis === "number" ? config.scheduledDelayMillis : getNumberFromEnv("OTEL_BSP_SCHEDULE_DELAY") ?? 5e3;
|
|
169
|
+
this._exportTimeoutMillis = typeof config?.exportTimeoutMillis === "number" ? config.exportTimeoutMillis : getNumberFromEnv("OTEL_BSP_EXPORT_TIMEOUT") ?? 3e4;
|
|
170
|
+
this._shutdownOnce = new BindOnceFuture(this._shutdown, this);
|
|
171
|
+
if (this._maxExportBatchSize > this._maxQueueSize) {
|
|
172
|
+
diag3.warn("BatchSpanProcessor: maxExportBatchSize must be smaller or equal to maxQueueSize, setting maxExportBatchSize to match maxQueueSize");
|
|
173
|
+
this._maxExportBatchSize = this._maxQueueSize;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
forceFlush() {
|
|
177
|
+
if (this._shutdownOnce.isCalled) {
|
|
178
|
+
return this._shutdownOnce.promise;
|
|
179
|
+
}
|
|
180
|
+
return this._flushAll();
|
|
181
|
+
}
|
|
182
|
+
// does nothing.
|
|
183
|
+
onStart(_span, _parentContext) {
|
|
184
|
+
}
|
|
185
|
+
onEnd(span) {
|
|
186
|
+
if (this._shutdownOnce.isCalled) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if ((span.spanContext().traceFlags & TraceFlags.SAMPLED) === 0) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
this._addToBuffer(span);
|
|
193
|
+
}
|
|
194
|
+
shutdown() {
|
|
195
|
+
return this._shutdownOnce.call();
|
|
196
|
+
}
|
|
197
|
+
_shutdown() {
|
|
198
|
+
return Promise.resolve().then(() => {
|
|
199
|
+
return this.onShutdown();
|
|
200
|
+
}).then(() => {
|
|
201
|
+
return this._flushAll();
|
|
202
|
+
}).then(() => {
|
|
203
|
+
return this._exporter.shutdown();
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/** Add a span in the buffer. */
|
|
207
|
+
_addToBuffer(span) {
|
|
208
|
+
if (this._finishedSpans.length >= this._maxQueueSize) {
|
|
209
|
+
if (this._droppedSpansCount === 0) {
|
|
210
|
+
diag3.debug("maxQueueSize reached, dropping spans");
|
|
211
|
+
}
|
|
212
|
+
this._droppedSpansCount++;
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (this._droppedSpansCount > 0) {
|
|
216
|
+
diag3.warn(`Dropped ${this._droppedSpansCount} spans because maxQueueSize reached`);
|
|
217
|
+
this._droppedSpansCount = 0;
|
|
218
|
+
}
|
|
219
|
+
this._finishedSpans.push(span);
|
|
220
|
+
this._maybeStartTimer();
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Send all spans to the exporter respecting the batch size limit
|
|
224
|
+
* This function is used only on forceFlush or shutdown,
|
|
225
|
+
* for all other cases _flush should be used
|
|
226
|
+
* */
|
|
227
|
+
_flushAll() {
|
|
228
|
+
return new Promise((resolve, reject) => {
|
|
229
|
+
const promises = [];
|
|
230
|
+
const count = Math.ceil(this._finishedSpans.length / this._maxExportBatchSize);
|
|
231
|
+
for (let i = 0, j = count; i < j; i++) {
|
|
232
|
+
promises.push(this._flushOneBatch());
|
|
233
|
+
}
|
|
234
|
+
Promise.all(promises).then(() => {
|
|
235
|
+
resolve();
|
|
236
|
+
}).catch(reject);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
_flushOneBatch() {
|
|
240
|
+
this._clearTimer();
|
|
241
|
+
if (this._finishedSpans.length === 0) {
|
|
242
|
+
return Promise.resolve();
|
|
243
|
+
}
|
|
244
|
+
return new Promise((resolve, reject) => {
|
|
245
|
+
const timer = setTimeout(() => {
|
|
246
|
+
reject(new Error("Timeout"));
|
|
247
|
+
}, this._exportTimeoutMillis);
|
|
248
|
+
context2.with(suppressTracing(context2.active()), () => {
|
|
249
|
+
let spans;
|
|
250
|
+
if (this._finishedSpans.length <= this._maxExportBatchSize) {
|
|
251
|
+
spans = this._finishedSpans;
|
|
252
|
+
this._finishedSpans = [];
|
|
253
|
+
} else {
|
|
254
|
+
spans = this._finishedSpans.splice(0, this._maxExportBatchSize);
|
|
255
|
+
}
|
|
256
|
+
const doExport = () => this._exporter.export(spans, (result) => {
|
|
257
|
+
clearTimeout(timer);
|
|
258
|
+
if (result.code === ExportResultCode.SUCCESS) {
|
|
259
|
+
resolve();
|
|
260
|
+
} else {
|
|
261
|
+
reject(result.error ?? new Error("BatchSpanProcessor: span export failed"));
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
let pendingResources = null;
|
|
265
|
+
for (let i = 0, len = spans.length; i < len; i++) {
|
|
266
|
+
const span = spans[i];
|
|
267
|
+
if (span.resource.asyncAttributesPending && span.resource.waitForAsyncAttributes) {
|
|
268
|
+
pendingResources ??= [];
|
|
269
|
+
pendingResources.push(span.resource.waitForAsyncAttributes());
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (pendingResources === null) {
|
|
273
|
+
doExport();
|
|
274
|
+
} else {
|
|
275
|
+
Promise.all(pendingResources).then(doExport, (err) => {
|
|
276
|
+
globalErrorHandler(err);
|
|
277
|
+
reject(err);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
_maybeStartTimer() {
|
|
284
|
+
if (this._isExporting)
|
|
285
|
+
return;
|
|
286
|
+
const flush = () => {
|
|
287
|
+
this._isExporting = true;
|
|
288
|
+
this._flushOneBatch().finally(() => {
|
|
289
|
+
this._isExporting = false;
|
|
290
|
+
if (this._finishedSpans.length > 0) {
|
|
291
|
+
this._clearTimer();
|
|
292
|
+
this._maybeStartTimer();
|
|
293
|
+
}
|
|
294
|
+
}).catch((e) => {
|
|
295
|
+
this._isExporting = false;
|
|
296
|
+
globalErrorHandler(e);
|
|
297
|
+
});
|
|
298
|
+
};
|
|
299
|
+
if (this._finishedSpans.length >= this._maxExportBatchSize) {
|
|
300
|
+
return flush();
|
|
301
|
+
}
|
|
302
|
+
if (this._timer !== void 0)
|
|
303
|
+
return;
|
|
304
|
+
this._timer = setTimeout(() => flush(), this._scheduledDelayMillis);
|
|
305
|
+
if (typeof this._timer !== "number") {
|
|
306
|
+
this._timer.unref();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
_clearTimer() {
|
|
310
|
+
if (this._timer !== void 0) {
|
|
311
|
+
clearTimeout(this._timer);
|
|
312
|
+
this._timer = void 0;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// node_modules/@opentelemetry/sdk-trace-base/build/esm/platform/node/export/BatchSpanProcessor.js
|
|
318
|
+
var BatchSpanProcessor = class extends BatchSpanProcessorBase {
|
|
319
|
+
onShutdown() {
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// node_modules/@opentelemetry/sdk-trace-base/build/esm/export/ConsoleSpanExporter.js
|
|
324
|
+
var ConsoleSpanExporter = class {
|
|
325
|
+
/**
|
|
326
|
+
* Export spans.
|
|
327
|
+
* @param spans
|
|
328
|
+
* @param resultCallback
|
|
329
|
+
*/
|
|
330
|
+
export(spans, resultCallback) {
|
|
331
|
+
return this._sendSpans(spans, resultCallback);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Shutdown the exporter.
|
|
335
|
+
*/
|
|
336
|
+
shutdown() {
|
|
337
|
+
this._sendSpans([]);
|
|
338
|
+
return this.forceFlush();
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Exports any pending spans in exporter
|
|
342
|
+
*/
|
|
343
|
+
forceFlush() {
|
|
344
|
+
return Promise.resolve();
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* converts span info into more readable format
|
|
348
|
+
* @param span
|
|
349
|
+
*/
|
|
350
|
+
_exportInfo(span) {
|
|
351
|
+
return {
|
|
352
|
+
resource: {
|
|
353
|
+
attributes: span.resource.attributes
|
|
354
|
+
},
|
|
355
|
+
instrumentationScope: span.instrumentationScope,
|
|
356
|
+
traceId: span.spanContext().traceId,
|
|
357
|
+
parentSpanContext: span.parentSpanContext,
|
|
358
|
+
traceState: span.spanContext().traceState?.serialize(),
|
|
359
|
+
name: span.name,
|
|
360
|
+
id: span.spanContext().spanId,
|
|
361
|
+
kind: span.kind,
|
|
362
|
+
timestamp: hrTimeToMicroseconds(span.startTime),
|
|
363
|
+
duration: hrTimeToMicroseconds(span.duration),
|
|
364
|
+
attributes: span.attributes,
|
|
365
|
+
status: span.status,
|
|
366
|
+
events: span.events,
|
|
367
|
+
links: span.links
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Showing spans in console
|
|
372
|
+
* @param spans
|
|
373
|
+
* @param done
|
|
374
|
+
*/
|
|
375
|
+
_sendSpans(spans, done) {
|
|
376
|
+
for (const span of spans) {
|
|
377
|
+
console.dir(this._exportInfo(span), { depth: 3 });
|
|
378
|
+
}
|
|
379
|
+
if (done) {
|
|
380
|
+
return done({ code: ExportResultCode.SUCCESS });
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
// node_modules/@opentelemetry/sdk-trace-base/build/esm/export/SimpleSpanProcessor.js
|
|
386
|
+
import { TraceFlags as TraceFlags2 } from "@opentelemetry/api";
|
|
387
|
+
var SimpleSpanProcessor = class {
|
|
388
|
+
_exporter;
|
|
389
|
+
_shutdownOnce;
|
|
390
|
+
_pendingExports;
|
|
391
|
+
constructor(exporter) {
|
|
392
|
+
this._exporter = exporter;
|
|
393
|
+
this._shutdownOnce = new BindOnceFuture(this._shutdown, this);
|
|
394
|
+
this._pendingExports = /* @__PURE__ */ new Set();
|
|
395
|
+
}
|
|
396
|
+
async forceFlush() {
|
|
397
|
+
await Promise.all(Array.from(this._pendingExports));
|
|
398
|
+
if (this._exporter.forceFlush) {
|
|
399
|
+
await this._exporter.forceFlush();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
onStart(_span, _parentContext) {
|
|
403
|
+
}
|
|
404
|
+
onEnd(span) {
|
|
405
|
+
if (this._shutdownOnce.isCalled) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if ((span.spanContext().traceFlags & TraceFlags2.SAMPLED) === 0) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
const pendingExport = this._doExport(span).catch((err) => globalErrorHandler(err));
|
|
412
|
+
this._pendingExports.add(pendingExport);
|
|
413
|
+
void pendingExport.finally(() => this._pendingExports.delete(pendingExport));
|
|
414
|
+
}
|
|
415
|
+
async _doExport(span) {
|
|
416
|
+
if (span.resource.asyncAttributesPending) {
|
|
417
|
+
await span.resource.waitForAsyncAttributes?.();
|
|
418
|
+
}
|
|
419
|
+
const result = await internal._export(this._exporter, [span]);
|
|
420
|
+
if (result.code !== ExportResultCode.SUCCESS) {
|
|
421
|
+
throw result.error ?? new Error(`SimpleSpanProcessor: span export failed (status ${result})`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
shutdown() {
|
|
425
|
+
return this._shutdownOnce.call();
|
|
426
|
+
}
|
|
427
|
+
_shutdown() {
|
|
428
|
+
return this._exporter.shutdown();
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// src/sdk.ts
|
|
433
|
+
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
434
|
+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
435
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
436
|
+
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
|
|
437
|
+
|
|
438
|
+
// node_modules/@opentelemetry/instrumentation/build/esm/autoLoader.js
|
|
439
|
+
import { trace, metrics } from "@opentelemetry/api";
|
|
440
|
+
|
|
441
|
+
// node_modules/@opentelemetry/api-logs/build/esm/NoopLogger.js
|
|
442
|
+
var NoopLogger = class {
|
|
443
|
+
emit(_logRecord) {
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
var NOOP_LOGGER = new NoopLogger();
|
|
447
|
+
|
|
448
|
+
// node_modules/@opentelemetry/api-logs/build/esm/NoopLoggerProvider.js
|
|
449
|
+
var NoopLoggerProvider = class {
|
|
450
|
+
getLogger(_name, _version, _options) {
|
|
451
|
+
return new NoopLogger();
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
var NOOP_LOGGER_PROVIDER = new NoopLoggerProvider();
|
|
455
|
+
|
|
456
|
+
// node_modules/@opentelemetry/api-logs/build/esm/ProxyLogger.js
|
|
457
|
+
var ProxyLogger = class {
|
|
458
|
+
constructor(provider, name, version, options) {
|
|
459
|
+
this._provider = provider;
|
|
460
|
+
this.name = name;
|
|
461
|
+
this.version = version;
|
|
462
|
+
this.options = options;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Emit a log record. This method should only be used by log appenders.
|
|
466
|
+
*
|
|
467
|
+
* @param logRecord
|
|
468
|
+
*/
|
|
469
|
+
emit(logRecord) {
|
|
470
|
+
this._getLogger().emit(logRecord);
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Try to get a logger from the proxy logger provider.
|
|
474
|
+
* If the proxy logger provider has no delegate, return a noop logger.
|
|
475
|
+
*/
|
|
476
|
+
_getLogger() {
|
|
477
|
+
if (this._delegate) {
|
|
478
|
+
return this._delegate;
|
|
479
|
+
}
|
|
480
|
+
const logger = this._provider._getDelegateLogger(this.name, this.version, this.options);
|
|
481
|
+
if (!logger) {
|
|
482
|
+
return NOOP_LOGGER;
|
|
483
|
+
}
|
|
484
|
+
this._delegate = logger;
|
|
485
|
+
return this._delegate;
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
// node_modules/@opentelemetry/api-logs/build/esm/ProxyLoggerProvider.js
|
|
490
|
+
var ProxyLoggerProvider = class {
|
|
491
|
+
getLogger(name, version, options) {
|
|
492
|
+
var _a;
|
|
493
|
+
return (_a = this._getDelegateLogger(name, version, options)) !== null && _a !== void 0 ? _a : new ProxyLogger(this, name, version, options);
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Get the delegate logger provider.
|
|
497
|
+
* Used by tests only.
|
|
498
|
+
* @internal
|
|
499
|
+
*/
|
|
500
|
+
_getDelegate() {
|
|
501
|
+
var _a;
|
|
502
|
+
return (_a = this._delegate) !== null && _a !== void 0 ? _a : NOOP_LOGGER_PROVIDER;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Set the delegate logger provider
|
|
506
|
+
* @internal
|
|
507
|
+
*/
|
|
508
|
+
_setDelegate(delegate) {
|
|
509
|
+
this._delegate = delegate;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* @internal
|
|
513
|
+
*/
|
|
514
|
+
_getDelegateLogger(name, version, options) {
|
|
515
|
+
var _a;
|
|
516
|
+
return (_a = this._delegate) === null || _a === void 0 ? void 0 : _a.getLogger(name, version, options);
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
// node_modules/@opentelemetry/api-logs/build/esm/internal/global-utils.js
|
|
521
|
+
var GLOBAL_LOGS_API_KEY = /* @__PURE__ */ Symbol.for("io.opentelemetry.js.api.logs");
|
|
522
|
+
var _global = globalThis;
|
|
523
|
+
function makeGetter(requiredVersion, instance, fallback) {
|
|
524
|
+
return (version) => version === requiredVersion ? instance : fallback;
|
|
525
|
+
}
|
|
526
|
+
var API_BACKWARDS_COMPATIBILITY_VERSION = 1;
|
|
527
|
+
|
|
528
|
+
// node_modules/@opentelemetry/api-logs/build/esm/api/logs.js
|
|
529
|
+
var LogsAPI = class _LogsAPI {
|
|
530
|
+
constructor() {
|
|
531
|
+
this._proxyLoggerProvider = new ProxyLoggerProvider();
|
|
532
|
+
}
|
|
533
|
+
static getInstance() {
|
|
534
|
+
if (!this._instance) {
|
|
535
|
+
this._instance = new _LogsAPI();
|
|
536
|
+
}
|
|
537
|
+
return this._instance;
|
|
538
|
+
}
|
|
539
|
+
setGlobalLoggerProvider(provider) {
|
|
540
|
+
if (_global[GLOBAL_LOGS_API_KEY]) {
|
|
541
|
+
return this.getLoggerProvider();
|
|
542
|
+
}
|
|
543
|
+
_global[GLOBAL_LOGS_API_KEY] = makeGetter(API_BACKWARDS_COMPATIBILITY_VERSION, provider, NOOP_LOGGER_PROVIDER);
|
|
544
|
+
this._proxyLoggerProvider._setDelegate(provider);
|
|
545
|
+
return provider;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Returns the global logger provider.
|
|
549
|
+
*
|
|
550
|
+
* @returns LoggerProvider
|
|
551
|
+
*/
|
|
552
|
+
getLoggerProvider() {
|
|
553
|
+
var _a, _b;
|
|
554
|
+
return (_b = (_a = _global[GLOBAL_LOGS_API_KEY]) === null || _a === void 0 ? void 0 : _a.call(_global, API_BACKWARDS_COMPATIBILITY_VERSION)) !== null && _b !== void 0 ? _b : this._proxyLoggerProvider;
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Returns a logger from the global logger provider.
|
|
558
|
+
*
|
|
559
|
+
* @returns Logger
|
|
560
|
+
*/
|
|
561
|
+
getLogger(name, version, options) {
|
|
562
|
+
return this.getLoggerProvider().getLogger(name, version, options);
|
|
563
|
+
}
|
|
564
|
+
/** Remove the global logger provider */
|
|
565
|
+
disable() {
|
|
566
|
+
delete _global[GLOBAL_LOGS_API_KEY];
|
|
567
|
+
this._proxyLoggerProvider = new ProxyLoggerProvider();
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
// node_modules/@opentelemetry/api-logs/build/esm/index.js
|
|
572
|
+
var logs = LogsAPI.getInstance();
|
|
573
|
+
|
|
574
|
+
// node_modules/@opentelemetry/instrumentation/build/esm/autoLoaderUtils.js
|
|
575
|
+
function enableInstrumentations(instrumentations, tracerProvider, meterProvider, loggerProvider) {
|
|
576
|
+
for (let i = 0, j = instrumentations.length; i < j; i++) {
|
|
577
|
+
const instrumentation = instrumentations[i];
|
|
578
|
+
if (tracerProvider) {
|
|
579
|
+
instrumentation.setTracerProvider(tracerProvider);
|
|
580
|
+
}
|
|
581
|
+
if (meterProvider) {
|
|
582
|
+
instrumentation.setMeterProvider(meterProvider);
|
|
583
|
+
}
|
|
584
|
+
if (loggerProvider && instrumentation.setLoggerProvider) {
|
|
585
|
+
instrumentation.setLoggerProvider(loggerProvider);
|
|
586
|
+
}
|
|
587
|
+
if (!instrumentation.getConfig().enabled) {
|
|
588
|
+
instrumentation.enable();
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
function disableInstrumentations(instrumentations) {
|
|
593
|
+
instrumentations.forEach((instrumentation) => instrumentation.disable());
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// node_modules/@opentelemetry/instrumentation/build/esm/autoLoader.js
|
|
597
|
+
function registerInstrumentations(options) {
|
|
598
|
+
const tracerProvider = options.tracerProvider || trace.getTracerProvider();
|
|
599
|
+
const meterProvider = options.meterProvider || metrics.getMeterProvider();
|
|
600
|
+
const loggerProvider = options.loggerProvider || logs.getLoggerProvider();
|
|
601
|
+
const instrumentations = options.instrumentations?.flat() ?? [];
|
|
602
|
+
enableInstrumentations(instrumentations, tracerProvider, meterProvider, loggerProvider);
|
|
603
|
+
return () => {
|
|
604
|
+
disableInstrumentations(instrumentations);
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// src/sdk.ts
|
|
609
|
+
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
|
|
610
|
+
|
|
1
611
|
// src/config.ts
|
|
2
612
|
var DEFAULT_CONFIG = {
|
|
3
613
|
environment: "development",
|
|
@@ -98,357 +708,143 @@ function parseBoolEnv(name, defaultValue) {
|
|
|
98
708
|
return value.toLowerCase() === "true" || value === "1";
|
|
99
709
|
}
|
|
100
710
|
|
|
101
|
-
// src/
|
|
102
|
-
var defaultLogger = {
|
|
103
|
-
debug: (msg, ...args) => console.debug(`[tracebeam] ${msg}`, ...args),
|
|
104
|
-
warn: (msg, ...args) => console.warn(`[tracebeam] ${msg}`, ...args),
|
|
105
|
-
error: (msg, ...args) => console.error(`[tracebeam] ${msg}`, ...args)
|
|
106
|
-
};
|
|
107
|
-
var Transport = class {
|
|
108
|
-
endpoint;
|
|
109
|
-
apiKey;
|
|
110
|
-
timeout;
|
|
111
|
-
logger;
|
|
112
|
-
debug;
|
|
113
|
-
state = "active";
|
|
114
|
-
constructor(options) {
|
|
115
|
-
this.endpoint = options.endpoint.replace(/\/$/, "");
|
|
116
|
-
this.apiKey = options.apiKey;
|
|
117
|
-
this.timeout = options.timeout;
|
|
118
|
-
this.debug = options.debug;
|
|
119
|
-
this.logger = options.logger ?? defaultLogger;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Get current transport state
|
|
123
|
-
*/
|
|
124
|
-
getState() {
|
|
125
|
-
return this.state;
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Check if transport is active
|
|
129
|
-
*/
|
|
130
|
-
isActive() {
|
|
131
|
-
return this.state === "active";
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Send a batch of events to the Ingest API
|
|
135
|
-
* Implements retry with exponential backoff
|
|
136
|
-
*/
|
|
137
|
-
async send(events) {
|
|
138
|
-
if (!this.isActive()) {
|
|
139
|
-
return {
|
|
140
|
-
success: false,
|
|
141
|
-
error: "Transport disabled",
|
|
142
|
-
message: `Transport is ${this.state}`,
|
|
143
|
-
code: 0
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
const batch = { events };
|
|
147
|
-
const url = `${this.endpoint}/api/v1/events`;
|
|
148
|
-
let lastError = null;
|
|
149
|
-
const maxRetries = 3;
|
|
150
|
-
const baseDelay = 1e3;
|
|
151
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
152
|
-
try {
|
|
153
|
-
const response = await this.executeRequest(url, batch);
|
|
154
|
-
if (response.success) {
|
|
155
|
-
if (this.debug) {
|
|
156
|
-
this.logger.debug(`Sent ${events.length} events successfully`);
|
|
157
|
-
}
|
|
158
|
-
return response;
|
|
159
|
-
}
|
|
160
|
-
const errorResponse = response;
|
|
161
|
-
lastError = errorResponse;
|
|
162
|
-
switch (errorResponse.code) {
|
|
163
|
-
case 401:
|
|
164
|
-
this.state = "disabled";
|
|
165
|
-
this.logger.error("Invalid API key. SDK disabled.");
|
|
166
|
-
return errorResponse;
|
|
167
|
-
case 402:
|
|
168
|
-
this.state = "quota_exceeded";
|
|
169
|
-
this.logger.warn("Event quota exceeded. SDK paused.");
|
|
170
|
-
return errorResponse;
|
|
171
|
-
case 429:
|
|
172
|
-
const retryAfter = errorResponse.retry_after ?? 1;
|
|
173
|
-
if (attempt < maxRetries) {
|
|
174
|
-
await this.sleep(retryAfter * 1e3);
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
return errorResponse;
|
|
178
|
-
case 400:
|
|
179
|
-
this.logger.warn("Bad request:", errorResponse.message);
|
|
180
|
-
return errorResponse;
|
|
181
|
-
default:
|
|
182
|
-
if (errorResponse.code >= 500 && attempt < maxRetries) {
|
|
183
|
-
const delay = this.calculateBackoff(attempt, baseDelay);
|
|
184
|
-
if (this.debug) {
|
|
185
|
-
this.logger.debug(`Retry ${attempt + 1}/${maxRetries} after ${delay}ms`);
|
|
186
|
-
}
|
|
187
|
-
await this.sleep(delay);
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
return errorResponse;
|
|
191
|
-
}
|
|
192
|
-
} catch (error) {
|
|
193
|
-
if (attempt < maxRetries) {
|
|
194
|
-
const delay = this.calculateBackoff(attempt, baseDelay);
|
|
195
|
-
if (this.debug) {
|
|
196
|
-
this.logger.debug(`Network error, retry ${attempt + 1}/${maxRetries} after ${delay}ms`);
|
|
197
|
-
}
|
|
198
|
-
await this.sleep(delay);
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
const networkError = {
|
|
202
|
-
success: false,
|
|
203
|
-
error: "Network Error",
|
|
204
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
205
|
-
code: 0
|
|
206
|
-
};
|
|
207
|
-
return networkError;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
return lastError ?? {
|
|
211
|
-
success: false,
|
|
212
|
-
error: "Max retries exceeded",
|
|
213
|
-
message: "Failed after maximum retry attempts",
|
|
214
|
-
code: 0
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Execute HTTP request
|
|
219
|
-
*/
|
|
220
|
-
async executeRequest(url, batch) {
|
|
221
|
-
const controller = new AbortController();
|
|
222
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
223
|
-
try {
|
|
224
|
-
const response = await fetch(url, {
|
|
225
|
-
method: "POST",
|
|
226
|
-
headers: {
|
|
227
|
-
"Content-Type": "application/json",
|
|
228
|
-
"Authorization": `Bearer ${this.apiKey}`
|
|
229
|
-
},
|
|
230
|
-
body: JSON.stringify(batch),
|
|
231
|
-
signal: controller.signal
|
|
232
|
-
});
|
|
233
|
-
const data = await response.json();
|
|
234
|
-
return data;
|
|
235
|
-
} finally {
|
|
236
|
-
clearTimeout(timeoutId);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Calculate backoff delay with jitter
|
|
241
|
-
*/
|
|
242
|
-
calculateBackoff(attempt, baseDelay) {
|
|
243
|
-
const exponentialDelay = baseDelay * Math.pow(2, attempt);
|
|
244
|
-
const jitter = exponentialDelay * 0.1 * (Math.random() * 2 - 1);
|
|
245
|
-
return Math.round(exponentialDelay + jitter);
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Sleep for specified milliseconds
|
|
249
|
-
*/
|
|
250
|
-
sleep(ms) {
|
|
251
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
// src/queue.ts
|
|
256
|
-
var EventQueue = class {
|
|
257
|
-
queue = [];
|
|
258
|
-
options;
|
|
259
|
-
onFlush;
|
|
260
|
-
flushTimer = null;
|
|
261
|
-
isFlushing = false;
|
|
262
|
-
constructor(options, onFlush) {
|
|
263
|
-
this.options = options;
|
|
264
|
-
this.onFlush = onFlush;
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Start the background flush timer
|
|
268
|
-
*/
|
|
269
|
-
start() {
|
|
270
|
-
if (this.flushTimer) return;
|
|
271
|
-
this.flushTimer = setInterval(() => {
|
|
272
|
-
this.flush().catch(() => {
|
|
273
|
-
});
|
|
274
|
-
}, this.options.flushInterval);
|
|
275
|
-
if (this.flushTimer.unref) {
|
|
276
|
-
this.flushTimer.unref();
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Stop the background flush timer
|
|
281
|
-
*/
|
|
282
|
-
stop() {
|
|
283
|
-
if (this.flushTimer) {
|
|
284
|
-
clearInterval(this.flushTimer);
|
|
285
|
-
this.flushTimer = null;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Add an event to the queue
|
|
290
|
-
* Returns immediately (non-blocking)
|
|
291
|
-
*/
|
|
292
|
-
add(event) {
|
|
293
|
-
if (this.queue.length >= this.options.maxQueueSize) {
|
|
294
|
-
this.queue.shift();
|
|
295
|
-
if (this.options.debug) {
|
|
296
|
-
console.warn("[tracebeam] Queue full, dropping oldest event");
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
this.queue.push(event);
|
|
300
|
-
if (this.queue.length >= this.options.batchSize) {
|
|
301
|
-
this.flush().catch(() => {
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
/**
|
|
306
|
-
* Flush all queued events
|
|
307
|
-
*/
|
|
308
|
-
async flush() {
|
|
309
|
-
if (this.isFlushing || this.queue.length === 0) {
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
this.isFlushing = true;
|
|
313
|
-
try {
|
|
314
|
-
const events = this.queue.splice(0, this.queue.length);
|
|
315
|
-
await this.onFlush(events);
|
|
316
|
-
} finally {
|
|
317
|
-
this.isFlushing = false;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Get current queue size
|
|
322
|
-
*/
|
|
323
|
-
size() {
|
|
324
|
-
return this.queue.length;
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* Check if queue is empty
|
|
328
|
-
*/
|
|
329
|
-
isEmpty() {
|
|
330
|
-
return this.queue.length === 0;
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
function createEvent(projectId, environment, error, options = {}, globalTags = {}, globalExtra = {}) {
|
|
334
|
-
if (!projectId || projectId.trim() === "") {
|
|
335
|
-
throw new ConfigError('createEvent: "projectId" must be a non-empty string.');
|
|
336
|
-
}
|
|
337
|
-
if (!environment || environment.trim() === "") {
|
|
338
|
-
throw new ConfigError('createEvent: "environment" must be a non-empty string.');
|
|
339
|
-
}
|
|
340
|
-
const level = options.level ?? "error";
|
|
341
|
-
const timestamp = options.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
342
|
-
const tags = {
|
|
343
|
-
...globalTags,
|
|
344
|
-
...options.tags
|
|
345
|
-
};
|
|
346
|
-
const extra = {
|
|
347
|
-
...globalExtra,
|
|
348
|
-
...options.extra
|
|
349
|
-
};
|
|
350
|
-
const truncatedError = error.length > 1e4 ? error.slice(0, 1e4) : error;
|
|
351
|
-
return {
|
|
352
|
-
project_id: projectId,
|
|
353
|
-
error: truncatedError,
|
|
354
|
-
level,
|
|
355
|
-
environment,
|
|
356
|
-
timestamp,
|
|
357
|
-
tags,
|
|
358
|
-
extra
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// src/client.ts
|
|
711
|
+
// src/sdk.ts
|
|
363
712
|
var TraceBeamSDK = class _TraceBeamSDK {
|
|
364
713
|
config;
|
|
365
|
-
|
|
366
|
-
|
|
714
|
+
provider;
|
|
715
|
+
tracer;
|
|
716
|
+
isInitialized = true;
|
|
367
717
|
globalTags = {};
|
|
368
718
|
globalExtra = {};
|
|
369
719
|
userId = null;
|
|
370
|
-
isInitialized = true;
|
|
371
720
|
/**
|
|
372
721
|
* Create SDK instance from configuration
|
|
373
722
|
*/
|
|
374
723
|
constructor(config) {
|
|
375
724
|
validateConfig(config);
|
|
376
725
|
this.config = mergeConfig(config);
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
726
|
+
const baseUrl = this.config.endpoint.replace(/\/$/, "");
|
|
727
|
+
const exporterUrl = `${baseUrl}/v1/traces`;
|
|
728
|
+
const exporter = new OTLPTraceExporter({
|
|
729
|
+
url: exporterUrl,
|
|
730
|
+
headers: {
|
|
731
|
+
"Authorization": `Bearer ${this.config.apiKey}`
|
|
732
|
+
}
|
|
382
733
|
});
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
debug: this.config.debug
|
|
389
|
-
},
|
|
390
|
-
this.handleFlush.bind(this)
|
|
391
|
-
);
|
|
392
|
-
this.queue.start();
|
|
734
|
+
const spanProcessors = [];
|
|
735
|
+
spanProcessors.push(new BatchSpanProcessor(exporter, {
|
|
736
|
+
maxExportBatchSize: this.config.batchSize,
|
|
737
|
+
scheduledDelayMillis: this.config.flushInterval
|
|
738
|
+
}));
|
|
393
739
|
if (this.config.debug) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
740
|
+
spanProcessors.push(new SimpleSpanProcessor(new ConsoleSpanExporter()));
|
|
741
|
+
console.debug("[tracebeam] Initialized OTLP", {
|
|
742
|
+
url: exporterUrl,
|
|
743
|
+
projectId: this.config.projectId
|
|
398
744
|
});
|
|
399
745
|
}
|
|
746
|
+
this.provider = new NodeTracerProvider({
|
|
747
|
+
resource: resourceFromAttributes({
|
|
748
|
+
[SemanticResourceAttributes.SERVICE_NAME]: this.config.projectId,
|
|
749
|
+
[SemanticResourceAttributes.SERVICE_VERSION]: this.config.environment,
|
|
750
|
+
[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: this.config.environment,
|
|
751
|
+
"telemetry.sdk.language": "nodejs",
|
|
752
|
+
"telemetry.sdk.name": "tracebeam-sdk",
|
|
753
|
+
"telemetry.sdk.version": "0.2.0"
|
|
754
|
+
}),
|
|
755
|
+
spanProcessors
|
|
756
|
+
});
|
|
757
|
+
this.provider.register();
|
|
758
|
+
registerInstrumentations({
|
|
759
|
+
tracerProvider: this.provider,
|
|
760
|
+
instrumentations: [
|
|
761
|
+
getNodeAutoInstrumentations({
|
|
762
|
+
// Disable some noisy instrumentations
|
|
763
|
+
"@opentelemetry/instrumentation-fs": { enabled: false },
|
|
764
|
+
"@opentelemetry/instrumentation-dns": { enabled: false }
|
|
765
|
+
})
|
|
766
|
+
]
|
|
767
|
+
});
|
|
768
|
+
this.tracer = api.trace.getTracer("tracebeam-sdk");
|
|
400
769
|
}
|
|
401
|
-
/**
|
|
402
|
-
* Create SDK instance from environment variables
|
|
403
|
-
*
|
|
404
|
-
* Required env vars:
|
|
405
|
-
* - TRACEBEAM_API_KEY
|
|
406
|
-
* - TRACEBEAM_PROJECT_ID
|
|
407
|
-
*
|
|
408
|
-
* Optional env vars:
|
|
409
|
-
* - TRACEBEAM_ENVIRONMENT (default: 'development')
|
|
410
|
-
* - TRACEBEAM_ENDPOINT (default: 'https://ingest.tracebeam.io')
|
|
411
|
-
* - TRACEBEAM_BATCH_SIZE (default: 100)
|
|
412
|
-
* - TRACEBEAM_FLUSH_INTERVAL (default: 5000)
|
|
413
|
-
* - TRACEBEAM_HTTP_TIMEOUT (default: 10000)
|
|
414
|
-
* - TRACEBEAM_MAX_QUEUE_SIZE (default: 10000)
|
|
415
|
-
* - TRACEBEAM_SAMPLE_RATE (default: 1.0)
|
|
416
|
-
* - TRACEBEAM_DEBUG (default: false)
|
|
417
|
-
*/
|
|
418
770
|
static fromEnv() {
|
|
419
771
|
const config = loadConfigFromEnv();
|
|
420
772
|
return new _TraceBeamSDK(config);
|
|
421
773
|
}
|
|
422
774
|
/**
|
|
423
775
|
* Capture an exception/error
|
|
424
|
-
* Returns immediately (non-blocking)
|
|
425
776
|
*/
|
|
426
777
|
captureException(error, options = {}) {
|
|
427
778
|
if (!this.canCapture()) return;
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
779
|
+
const timestamp = options.timestamp ? new Date(options.timestamp).getTime() : Date.now();
|
|
780
|
+
let startTime = timestamp;
|
|
781
|
+
if (options.latency) {
|
|
782
|
+
startTime = timestamp - options.latency;
|
|
783
|
+
}
|
|
784
|
+
let spanName = "exception";
|
|
785
|
+
let spanStatus = api.SpanStatusCode.ERROR;
|
|
786
|
+
let errorMessage = "";
|
|
787
|
+
if (error instanceof Error) {
|
|
788
|
+
spanName = error.name || "Error";
|
|
789
|
+
errorMessage = error.message;
|
|
790
|
+
} else if (typeof error === "string") {
|
|
791
|
+
if (error === "") {
|
|
792
|
+
spanName = options.tags?.["endpoint"] || "request";
|
|
793
|
+
spanStatus = api.SpanStatusCode.OK;
|
|
794
|
+
} else {
|
|
795
|
+
spanName = "Error";
|
|
796
|
+
errorMessage = error;
|
|
797
|
+
}
|
|
798
|
+
} else {
|
|
799
|
+
spanName = "Error";
|
|
800
|
+
errorMessage = String(error);
|
|
801
|
+
}
|
|
802
|
+
const span = this.tracer.startSpan(spanName, {
|
|
803
|
+
startTime,
|
|
804
|
+
kind: api.SpanKind.CLIENT
|
|
433
805
|
});
|
|
434
|
-
|
|
806
|
+
const attributes = {};
|
|
807
|
+
Object.entries(this.globalTags).forEach(([k, v]) => attributes[k] = v);
|
|
808
|
+
if (options.tags) {
|
|
809
|
+
Object.entries(options.tags).forEach(([k, v]) => attributes[k] = v);
|
|
810
|
+
}
|
|
811
|
+
Object.entries(this.globalExtra).forEach(([k, v]) => {
|
|
812
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
813
|
+
attributes[k] = v;
|
|
814
|
+
} else {
|
|
815
|
+
attributes[k] = JSON.stringify(v);
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
if (options.extra) {
|
|
819
|
+
Object.entries(options.extra).forEach(([k, v]) => {
|
|
820
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
821
|
+
attributes[k] = v;
|
|
822
|
+
} else {
|
|
823
|
+
attributes[k] = JSON.stringify(v);
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
if (options.latency) {
|
|
828
|
+
attributes["latency_ms"] = options.latency;
|
|
829
|
+
attributes["latency"] = options.latency;
|
|
830
|
+
}
|
|
831
|
+
span.setAttributes(attributes);
|
|
832
|
+
span.setStatus({ code: spanStatus });
|
|
833
|
+
if (error && error !== "") {
|
|
834
|
+
if (error instanceof Error) {
|
|
835
|
+
span.recordException(error);
|
|
836
|
+
} else {
|
|
837
|
+
span.recordException(new Error(String(error)));
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
span.end(timestamp);
|
|
435
841
|
}
|
|
436
842
|
/**
|
|
437
|
-
* Capture a message
|
|
438
|
-
* Returns immediately (non-blocking)
|
|
843
|
+
* Capture a message
|
|
439
844
|
*/
|
|
440
845
|
captureMessage(message, options = {}) {
|
|
441
|
-
|
|
442
|
-
const event = this.createEventWithContext(message, {
|
|
443
|
-
level: "info",
|
|
444
|
-
...options
|
|
445
|
-
});
|
|
446
|
-
this.queue.add(event);
|
|
846
|
+
this.captureException(message, { ...options, level: options.level || "info" });
|
|
447
847
|
}
|
|
448
|
-
/**
|
|
449
|
-
* Set the current user ID
|
|
450
|
-
* Will be included in all subsequent events
|
|
451
|
-
*/
|
|
452
848
|
setUser(userId) {
|
|
453
849
|
this.userId = userId;
|
|
454
850
|
if (userId) {
|
|
@@ -457,62 +853,30 @@ ${error.stack ?? ""}` : String(error);
|
|
|
457
853
|
delete this.globalExtra["user_id"];
|
|
458
854
|
}
|
|
459
855
|
}
|
|
460
|
-
/**
|
|
461
|
-
* Set a global tag
|
|
462
|
-
* Will be included in all subsequent events
|
|
463
|
-
*/
|
|
464
856
|
setTag(key, value) {
|
|
465
857
|
this.globalTags[key] = value;
|
|
466
858
|
}
|
|
467
|
-
/**
|
|
468
|
-
* Set multiple global tags
|
|
469
|
-
* Will be included in all subsequent events
|
|
470
|
-
*/
|
|
471
859
|
setTags(tags) {
|
|
472
860
|
Object.assign(this.globalTags, tags);
|
|
473
861
|
}
|
|
474
|
-
/**
|
|
475
|
-
* Set global extra context
|
|
476
|
-
* Will be included in all subsequent events
|
|
477
|
-
*/
|
|
478
862
|
setExtra(key, value) {
|
|
479
863
|
this.globalExtra[key] = value;
|
|
480
864
|
}
|
|
481
|
-
/**
|
|
482
|
-
* Set multiple global extra context values
|
|
483
|
-
*/
|
|
484
865
|
setExtras(extras) {
|
|
485
866
|
Object.assign(this.globalExtra, extras);
|
|
486
867
|
}
|
|
487
|
-
/**
|
|
488
|
-
* Manually flush queued events
|
|
489
|
-
* Call this to ensure events are sent before process exit
|
|
490
|
-
*/
|
|
491
868
|
async flush() {
|
|
492
|
-
await this.
|
|
869
|
+
await this.provider.forceFlush();
|
|
493
870
|
}
|
|
494
|
-
/**
|
|
495
|
-
* Graceful shutdown
|
|
496
|
-
* Flushes remaining events and stops background workers
|
|
497
|
-
*/
|
|
498
871
|
async close() {
|
|
499
872
|
this.isInitialized = false;
|
|
500
|
-
this.
|
|
501
|
-
await this.flush();
|
|
502
|
-
if (this.config.debug) {
|
|
503
|
-
console.debug("[tracebeam] Closed");
|
|
504
|
-
}
|
|
873
|
+
await this.provider.shutdown();
|
|
505
874
|
}
|
|
506
|
-
/**
|
|
507
|
-
* Check if SDK is active and can capture events
|
|
508
|
-
*/
|
|
509
875
|
isActive() {
|
|
510
|
-
return this.isInitialized
|
|
876
|
+
return this.isInitialized;
|
|
511
877
|
}
|
|
512
|
-
// Private methods
|
|
513
878
|
canCapture() {
|
|
514
879
|
if (!this.isInitialized) return false;
|
|
515
|
-
if (!this.transport.isActive()) return false;
|
|
516
880
|
if (this.config.sampleRate < 1) {
|
|
517
881
|
if (Math.random() > this.config.sampleRate) {
|
|
518
882
|
return false;
|
|
@@ -520,31 +884,13 @@ ${error.stack ?? ""}` : String(error);
|
|
|
520
884
|
}
|
|
521
885
|
return true;
|
|
522
886
|
}
|
|
523
|
-
createEventWithContext(error, options) {
|
|
524
|
-
return createEvent(
|
|
525
|
-
this.config.projectId,
|
|
526
|
-
this.config.environment,
|
|
527
|
-
error,
|
|
528
|
-
options,
|
|
529
|
-
this.globalTags,
|
|
530
|
-
this.globalExtra
|
|
531
|
-
);
|
|
532
|
-
}
|
|
533
|
-
async handleFlush(events) {
|
|
534
|
-
if (events.length === 0) return;
|
|
535
|
-
try {
|
|
536
|
-
await this.transport.send(events);
|
|
537
|
-
} catch (error) {
|
|
538
|
-
if (this.config.debug) {
|
|
539
|
-
console.error("[tracebeam] Failed to flush events:", error);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
887
|
};
|
|
544
888
|
export {
|
|
545
889
|
ConfigError,
|
|
546
890
|
DEFAULT_CONFIG,
|
|
547
891
|
TraceBeamSDK,
|
|
548
|
-
loadConfigFromEnv
|
|
892
|
+
loadConfigFromEnv,
|
|
893
|
+
mergeConfig,
|
|
894
|
+
validateConfig
|
|
549
895
|
};
|
|
550
896
|
//# sourceMappingURL=index.mjs.map
|