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