@nxgt/telemetry 0.1.0 → 0.2.1

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,6 +1,14 @@
1
1
  // src/attributes/attributes.ts
2
2
  var EMPTY_ATTRIBUTES = Object.freeze({});
3
+ var UNREADABLE = "[unreadable]";
3
4
  function coerceAttribute(value) {
5
+ try {
6
+ return coerce(value);
7
+ } catch {
8
+ return UNREADABLE;
9
+ }
10
+ }
11
+ function coerce(value) {
4
12
  if (value === null || value === undefined)
5
13
  return null;
6
14
  switch (typeof value) {
@@ -24,12 +32,25 @@ function coerceAttribute(value) {
24
32
  return render(value);
25
33
  }
26
34
  function attributesOf(input) {
27
- if (input === undefined)
35
+ if (input === undefined || input === null)
28
36
  return EMPTY_ATTRIBUTES;
37
+ let keys;
38
+ try {
39
+ keys = Object.keys(input);
40
+ } catch {
41
+ return EMPTY_ATTRIBUTES;
42
+ }
29
43
  const attributes = {};
30
44
  let any = false;
31
- for (const key of Object.keys(input)) {
32
- const value = input[key];
45
+ for (const key of keys) {
46
+ let value;
47
+ try {
48
+ value = input[key];
49
+ } catch {
50
+ attributes[key] = UNREADABLE;
51
+ any = true;
52
+ continue;
53
+ }
33
54
  if (value === undefined)
34
55
  continue;
35
56
  attributes[key] = coerceAttribute(value);
@@ -67,38 +88,97 @@ function render(value) {
67
88
  try {
68
89
  return String(value);
69
90
  } catch {
70
- return "[unrenderable]";
91
+ return UNREADABLE;
71
92
  }
72
93
  }
73
- // src/model/signal.ts
74
- var SEVERITY_NUMBER = Object.freeze({
75
- debug: 5,
76
- info: 9,
77
- warn: 13,
78
- error: 17
79
- });
80
- var SEVERITIES = Object.freeze([
81
- "debug",
82
- "info",
83
- "warn",
84
- "error"
85
- ]);
86
- function meetsSeverity(severity, minimum) {
87
- return SEVERITY_NUMBER[severity] >= SEVERITY_NUMBER[minimum];
88
- }
89
- var SPAN_KIND_NUMBER = Object.freeze({
90
- internal: 1,
91
- server: 2,
92
- client: 3,
93
- producer: 4,
94
- consumer: 5
95
- });
96
- function signalAt(signal) {
97
- return signal.type === "log" ? signal.at : signal.startedAt;
94
+ // src/context/current.ts
95
+ import * as asyncHooks from "node:async_hooks";
96
+
97
+ // src/export/pipeline.ts
98
+ class Pipeline {
99
+ constructor(options) {
100
+ this.buffer = [];
101
+ this.draining = Promise.resolve();
102
+ this.closed = false;
103
+ this.options = options;
104
+ }
105
+ post(signal) {
106
+ if (this.closed)
107
+ return false;
108
+ this.buffer.push(signal);
109
+ if (this.buffer.length >= this.options.batch) {
110
+ this.flush();
111
+ } else if (this.timer === undefined) {
112
+ this.timer = setTimeout(() => {
113
+ this.timer = undefined;
114
+ this.flush();
115
+ }, this.options.linger);
116
+ this.timer.unref?.();
117
+ }
118
+ return true;
119
+ }
120
+ close() {
121
+ this.closing ??= this.drainAndClose();
122
+ return this.closing;
123
+ }
124
+ flush() {
125
+ this.clearTimer();
126
+ if (this.buffer.length === 0)
127
+ return;
128
+ const batch = this.buffer;
129
+ this.buffer = [];
130
+ this.draining = this.draining.then(() => this.ship(batch));
131
+ }
132
+ clearTimer() {
133
+ if (this.timer === undefined)
134
+ return;
135
+ clearTimeout(this.timer);
136
+ this.timer = undefined;
137
+ }
138
+ async ship(batch) {
139
+ for (const exporter of this.options.exporters) {
140
+ try {
141
+ await exporter.export(this.options.resource, batch);
142
+ } catch (failure) {
143
+ this.report(failure);
144
+ }
145
+ }
146
+ }
147
+ async drainAndClose() {
148
+ this.closed = true;
149
+ this.flush();
150
+ const deadline = timeout(this.options.drainTimeout);
151
+ const drained = await Promise.race([
152
+ this.draining.then(() => true),
153
+ deadline.then(() => false)
154
+ ]);
155
+ if (!drained) {
156
+ this.report(new Error(`[telemetry] the backlog did not ship within ${this.options.drainTimeout}ms; closing anyway`));
157
+ }
158
+ await Promise.race([this.closeExporters(), deadline]);
159
+ }
160
+ async closeExporters() {
161
+ for (const exporter of this.options.exporters) {
162
+ try {
163
+ await exporter.close?.();
164
+ } catch (failure) {
165
+ this.report(failure);
166
+ }
167
+ }
168
+ }
169
+ report(failure) {
170
+ try {
171
+ this.options.onExportError(failure);
172
+ } catch {}
173
+ }
98
174
  }
99
- function signalSpan(signal) {
100
- return signal.type === "log" ? signal.span : signal.context;
175
+ function timeout(milliseconds) {
176
+ return new Promise((resolve) => {
177
+ const timer = setTimeout(resolve, milliseconds);
178
+ timer.unref?.();
179
+ });
101
180
  }
181
+
102
182
  // src/trace/ids.ts
103
183
  var INVALID_TRACE_ID = "0".repeat(32);
104
184
  var INVALID_SPAN_ID = "0".repeat(16);
@@ -164,6 +244,7 @@ function randomHex(bytes) {
164
244
  }
165
245
  return hex;
166
246
  }
247
+
167
248
  // src/trace/sampler.ts
168
249
  var alwaysSample = { sample: () => true };
169
250
  var neverSample = { sample: () => false };
@@ -186,32 +267,763 @@ function ratioSampler(ratio) {
186
267
  }
187
268
  };
188
269
  }
270
+
271
+ // src/telemetry/telemetry.ts
272
+ var TELEMETRY_DEFAULTS = Object.freeze({
273
+ minimum: "info",
274
+ stackTraces: true,
275
+ batch: 512,
276
+ linger: 1000,
277
+ drainTimeout: 1e4
278
+ });
279
+ var installed;
280
+
281
+ class Telemetry {
282
+ constructor(options) {
283
+ this.resource = {
284
+ service: options.service,
285
+ ...options.version === undefined ? {} : { version: options.version },
286
+ ...options.environment === undefined ? {} : { environment: options.environment },
287
+ attributes: attributesOf(options.attributes)
288
+ };
289
+ this.sampler = options.sampler ?? alwaysSample;
290
+ this.minimum = options.minimum ?? TELEMETRY_DEFAULTS.minimum;
291
+ this.stackTraces = options.stackTraces ?? TELEMETRY_DEFAULTS.stackTraces;
292
+ this.pipeline = new Pipeline({
293
+ resource: this.resource,
294
+ exporters: options.exporters ?? [],
295
+ batch: options.batch ?? TELEMETRY_DEFAULTS.batch,
296
+ linger: options.linger ?? TELEMETRY_DEFAULTS.linger,
297
+ drainTimeout: options.drainTimeout ?? TELEMETRY_DEFAULTS.drainTimeout,
298
+ onExportError: options.onExportError ?? defaultOnExportError
299
+ });
300
+ }
301
+ emit(signal) {
302
+ return this.pipeline.post(signal);
303
+ }
304
+ install() {
305
+ installed = this;
306
+ return this;
307
+ }
308
+ async close() {
309
+ if (installed === this)
310
+ installed = undefined;
311
+ await this.pipeline.close();
312
+ }
313
+ async[Symbol.asyncDispose]() {
314
+ await this.close();
315
+ }
316
+ }
317
+ function createTelemetry(service, options = {}) {
318
+ return new Telemetry({ ...options, service });
319
+ }
320
+ function installedTelemetry() {
321
+ return installed;
322
+ }
323
+ function uninstallTelemetry(telemetry) {
324
+ if (telemetry === undefined || installed === telemetry)
325
+ installed = undefined;
326
+ }
327
+ function defaultOnExportError(failure) {
328
+ console.error("[telemetry] export failed", failure);
329
+ }
330
+
331
+ // src/context/current.ts
332
+ var storage = createStorage();
333
+ function currentContext() {
334
+ return storage.getStore();
335
+ }
336
+ function runWithContext(context, fn) {
337
+ return storage.run(context, fn);
338
+ }
339
+ function resolveTelemetry() {
340
+ return currentContext()?.telemetry ?? installedTelemetry();
341
+ }
342
+ function withTelemetry(telemetry, fn) {
343
+ const context = currentContext();
344
+ return runWithContext({
345
+ telemetry,
346
+ ...context?.span === undefined ? {} : { span: context.span },
347
+ attributes: context?.attributes ?? EMPTY_ATTRIBUTES
348
+ }, fn);
349
+ }
350
+ function withAttributes(attributes, fn) {
351
+ const given = attributesOf(attributes);
352
+ const context = currentContext();
353
+ if (context === undefined) {
354
+ const telemetry = installedTelemetry();
355
+ if (telemetry === undefined)
356
+ return fn();
357
+ return runWithContext({ telemetry, attributes: given }, fn);
358
+ }
359
+ return runWithContext({ ...context, attributes: mergeAttributes(context.attributes, given) }, fn);
360
+ }
361
+ function currentSpan() {
362
+ return currentContext()?.span;
363
+ }
364
+ function currentTraceparent() {
365
+ const span = currentSpan();
366
+ return span === undefined ? undefined : renderTraceparent(span);
367
+ }
368
+ function currentAttributes() {
369
+ return currentContext()?.attributes ?? EMPTY_ATTRIBUTES;
370
+ }
371
+ function createStorage() {
372
+ const AsyncLocalStorage2 = asyncHooks.AsyncLocalStorage;
373
+ if (typeof AsyncLocalStorage2 === "function") {
374
+ return new AsyncLocalStorage2;
375
+ }
376
+ let current;
377
+ return {
378
+ getStore: () => current,
379
+ run(context, fn) {
380
+ const previous = current;
381
+ current = context;
382
+ try {
383
+ return fn();
384
+ } finally {
385
+ current = previous;
386
+ }
387
+ }
388
+ };
389
+ }
390
+ // src/export/console.ts
391
+ function consoleExporter(options = {}) {
392
+ const write = options.write ?? ((line) => console.log(line));
393
+ const stackTraces = options.stackTraces ?? true;
394
+ return {
395
+ export(_resource, batch) {
396
+ for (const signal of batch) {
397
+ write(signal.type === "log" ? renderLog(signal) : renderSpan(signal));
398
+ const error = signal.error;
399
+ if (stackTraces && error?.stackTrace)
400
+ write(error.stackTrace);
401
+ }
402
+ }
403
+ };
404
+ }
405
+ function renderLog(log) {
406
+ return [
407
+ clock(log.at),
408
+ log.severity.toUpperCase().padEnd(5),
409
+ log.source,
410
+ log.name,
411
+ renderAttributes(log.attributes),
412
+ renderError(log.error),
413
+ renderTrace(log)
414
+ ].filter(Boolean).join(" ");
415
+ }
416
+ function renderSpan(span) {
417
+ return [
418
+ clock(span.endedAt),
419
+ "SPAN ",
420
+ span.name,
421
+ `${span.endedAt - span.startedAt}ms`,
422
+ span.status === "ok" ? "" : span.status.toUpperCase(),
423
+ renderAttributes(span.attributes),
424
+ renderError(span.error),
425
+ renderTrace(span)
426
+ ].filter(Boolean).join(" ");
427
+ }
428
+ function clock(at) {
429
+ if (!Number.isFinite(at) || Math.abs(at) > 8640000000000000)
430
+ return String(at);
431
+ return new Date(at).toISOString().slice(11, 23);
432
+ }
433
+ function renderAttributes(attributes) {
434
+ return Object.entries(attributes).map(([key, value]) => `${key}=${renderValue(value)}`).join(" ");
435
+ }
436
+ function renderValue(value) {
437
+ return Array.isArray(value) ? `[${value.join(",")}]` : String(value);
438
+ }
439
+ function renderError(error) {
440
+ if (error === undefined)
441
+ return "";
442
+ return error.message ? `${error.type}: ${error.message}` : error.type;
443
+ }
444
+ function renderTrace(signal) {
445
+ const span = signal.type === "log" ? signal.span : signal.context;
446
+ if (span === undefined)
447
+ return "";
448
+ return `[${span.traceId.slice(0, 8)}/${span.spanId.slice(0, 8)}]`;
449
+ }
450
+ // src/export/file.ts
451
+ import {
452
+ appendFile,
453
+ mkdir,
454
+ readdir,
455
+ readFile,
456
+ rename,
457
+ rm,
458
+ stat,
459
+ writeFile
460
+ } from "node:fs/promises";
461
+ import { dirname, join } from "node:path";
462
+ import { promisify } from "node:util";
463
+ import { gzip } from "node:zlib";
464
+
465
+ // src/export/rotation.ts
466
+ import { basename } from "node:path";
467
+ function rotationDue(size, openedAt, now, policy) {
468
+ if (size <= 0)
469
+ return false;
470
+ if (policy.maxSize > 0 && size >= policy.maxSize)
471
+ return true;
472
+ return policy.every > 0 && period(openedAt, policy) !== period(now, policy);
473
+ }
474
+ function rolledName(path, at, taken = 0) {
475
+ const file = basename(path);
476
+ const directory = path.slice(0, path.length - file.length);
477
+ const dot = file.lastIndexOf(".");
478
+ const base = dot <= 0 ? file : file.slice(0, dot);
479
+ const extension = dot <= 0 ? "" : file.slice(dot);
480
+ const suffix = taken === 0 ? "" : `-${taken}`;
481
+ return `${directory}${base}-${stamp(at)}${suffix}${extension}`;
482
+ }
483
+ function rolledOf(path, names) {
484
+ const found = new Map;
485
+ for (const name of names) {
486
+ const rolled = parse(path, name);
487
+ if (rolled === undefined)
488
+ continue;
489
+ const key = `${rolled.at}-${rolled.taken}`;
490
+ const seen = found.get(key);
491
+ if (seen === undefined || name.endsWith(".gz")) {
492
+ found.set(key, { ...rolled, name });
493
+ }
494
+ }
495
+ return [...found.values()].sort((one, other) => other.at.localeCompare(one.at) || other.taken - one.taken).map((rolled) => rolled.name);
496
+ }
497
+ function prunable(path, names, keep) {
498
+ const kept = new Set(rolledOf(path, names).slice(0, Math.max(keep, 0)));
499
+ return names.filter((name) => parse(path, name) !== undefined && !kept.has(name));
500
+ }
501
+ function period(at, policy) {
502
+ return Math.floor(at / policy.every);
503
+ }
504
+ function parse(path, name) {
505
+ const file = basename(path);
506
+ const dot = file.lastIndexOf(".");
507
+ const base = dot <= 0 ? file : file.slice(0, dot);
508
+ const extension = dot <= 0 ? "" : file.slice(dot);
509
+ const pattern = new RegExp(`^${escapeRegex(base)}-(\\d{8}-\\d{6})(?:-(\\d+))?${escapeRegex(extension)}(\\.gz)?$`);
510
+ const found = pattern.exec(name);
511
+ if (found === null)
512
+ return;
513
+ return { at: found[1], taken: Number(found[2] ?? 0) };
514
+ }
515
+ function stamp(at) {
516
+ const iso = new Date(at).toISOString();
517
+ return `${iso.slice(0, 10).replaceAll("-", "")}-${iso.slice(11, 19).replaceAll(":", "")}`;
518
+ }
519
+ function escapeRegex(text) {
520
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
521
+ }
522
+
523
+ // src/export/file.ts
524
+ var compressed = promisify(gzip);
525
+ var DEFAULT_MAX_SIZE = 64 * 1024 * 1024;
526
+ var DEFAULT_ROTATION_PERIOD = 24 * 60 * 60 * 1000;
527
+ var MAX_COLLISIONS = 1000;
528
+ function fileExporter(options) {
529
+ const policy = {
530
+ maxSize: options.maxSize ?? DEFAULT_MAX_SIZE,
531
+ every: options.every ?? DEFAULT_ROTATION_PERIOD,
532
+ keep: options.keep ?? 7,
533
+ compress: options.compress ?? false
534
+ };
535
+ const now = options.now ?? Date.now;
536
+ const path = options.path;
537
+ let state;
538
+ let queue = Promise.resolve();
539
+ const write = async (batch) => {
540
+ const text = render2(batch);
541
+ if (text.length === 0)
542
+ return;
543
+ try {
544
+ state ??= await currentState(path, now());
545
+ if (rotationDue(state.size, state.openedAt, now(), policy)) {
546
+ await roll(path, now(), policy);
547
+ state = { size: 0, openedAt: now() };
548
+ }
549
+ await appendFile(path, text, "utf8");
550
+ state.size += Buffer.byteLength(text, "utf8");
551
+ } catch (failure) {
552
+ state = undefined;
553
+ throw failure;
554
+ }
555
+ };
556
+ return {
557
+ export(_resource, batch) {
558
+ const next = queue.then(() => write(batch));
559
+ queue = next.catch(() => {
560
+ return;
561
+ });
562
+ return next;
563
+ }
564
+ };
565
+ }
566
+ function render2(batch) {
567
+ let text = "";
568
+ for (const signal of batch) {
569
+ try {
570
+ text += `${JSON.stringify(signal)}
571
+ `;
572
+ } catch {}
573
+ }
574
+ return text;
575
+ }
576
+ async function currentState(path, fallback) {
577
+ await mkdir(dirname(path), { recursive: true });
578
+ try {
579
+ const found = await stat(path);
580
+ return { size: found.size, openedAt: found.mtimeMs };
581
+ } catch {
582
+ return { size: 0, openedAt: fallback };
583
+ }
584
+ }
585
+ async function roll(path, at, policy) {
586
+ const target = await freeName(path, at);
587
+ await rename(path, target);
588
+ if (policy.compress)
589
+ await compress(target);
590
+ await prune(path, policy.keep);
591
+ }
592
+ async function freeName(path, at) {
593
+ for (let taken = 0;taken < MAX_COLLISIONS; taken++) {
594
+ const candidate = rolledName(path, at, taken);
595
+ if (!await exists(candidate) && !await exists(`${candidate}.gz`)) {
596
+ return candidate;
597
+ }
598
+ }
599
+ throw new Error(`[telemetry] ${MAX_COLLISIONS} archives of ${path} already share this second`);
600
+ }
601
+ async function compress(path) {
602
+ const pending = `${path}.gz.pending`;
603
+ await writeFile(pending, await compressed(await readFile(path)));
604
+ await rename(pending, `${path}.gz`);
605
+ await rm(path, { force: true });
606
+ }
607
+ async function prune(path, keep) {
608
+ const directory = dirname(path);
609
+ const names = await readdir(directory);
610
+ for (const name of prunable(path, names, keep)) {
611
+ await rm(join(directory, name), { force: true });
612
+ }
613
+ }
614
+ async function exists(path) {
615
+ return stat(path).then(() => true, () => false);
616
+ }
617
+ // src/export/json-lines.ts
618
+ function jsonLinesExporter(options = {}) {
619
+ const write = options.write ?? ((line) => console.log(line));
620
+ return {
621
+ export(_resource, batch) {
622
+ for (const signal of batch) {
623
+ const line = render3(signal);
624
+ if (line !== undefined)
625
+ write(line);
626
+ }
627
+ }
628
+ };
629
+ }
630
+ function render3(signal) {
631
+ try {
632
+ return JSON.stringify(signal);
633
+ } catch {
634
+ return;
635
+ }
636
+ }
637
+ // src/logger/event.ts
638
+ var INVALID_EVENT_ATTRIBUTE = "telemetry.event.invalid";
639
+ function event(name, schema) {
640
+ return (input) => {
641
+ if (schema === undefined)
642
+ return { name, attributes: attributesOf(input) };
643
+ let result;
644
+ try {
645
+ result = schema["~standard"].validate(input);
646
+ } catch {
647
+ return invalid(name, input);
648
+ }
649
+ if (isThenable(result)) {
650
+ Promise.resolve(result).catch(() => {
651
+ return;
652
+ });
653
+ return invalid(name, input);
654
+ }
655
+ const checked = result;
656
+ if (checked.issues !== undefined)
657
+ return invalid(name, input);
658
+ return { name, attributes: fields(checked.value) };
659
+ };
660
+ }
661
+ function isTelemetryEvent(value) {
662
+ return typeof value === "object" && value !== null && typeof value.name === "string" && typeof value.attributes === "object";
663
+ }
664
+ function invalid(name, input) {
665
+ return {
666
+ name,
667
+ attributes: { ...attributesOf(input), [INVALID_EVENT_ATTRIBUTE]: true },
668
+ invalid: true
669
+ };
670
+ }
671
+ function fields(value) {
672
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
673
+ return attributesOf(value);
674
+ }
675
+ return { value: coerceAttribute(value) };
676
+ }
677
+ function isThenable(value) {
678
+ return typeof value === "object" && value !== null && typeof value.then === "function";
679
+ }
680
+ // src/model/error.ts
681
+ function errorInfo(failure, stackTraces = true) {
682
+ try {
683
+ return flatten(failure, stackTraces);
684
+ } catch {
685
+ return { type: "Error", message: UNREADABLE };
686
+ }
687
+ }
688
+ function isAbort(failure) {
689
+ if (typeof failure !== "object" || failure === null)
690
+ return false;
691
+ const name = read(failure, "name");
692
+ return name === "AbortError" || name === "TimeoutError";
693
+ }
694
+ function flatten(failure, stackTraces) {
695
+ if (isError(failure)) {
696
+ const message = read(failure, "message");
697
+ const stack = stackTraces ? read(failure, "stack") : undefined;
698
+ return {
699
+ type: errorType(failure),
700
+ ...typeof message === "string" && message ? { message } : {},
701
+ ...typeof stack === "string" && stack ? { stackTrace: stack } : {}
702
+ };
703
+ }
704
+ return { type: typeName(failure), message: describe(failure) };
705
+ }
706
+ function isError(value) {
707
+ try {
708
+ if (value instanceof Error)
709
+ return true;
710
+ return typeof value === "object" && value !== null && Object.prototype.toString.call(value) === "[object Error]";
711
+ } catch {
712
+ return false;
713
+ }
714
+ }
715
+ function errorType(failure) {
716
+ const name = read(failure, "name");
717
+ const named = typeof name === "string" && name ? name : undefined;
718
+ if (named !== undefined && named !== "Error")
719
+ return named;
720
+ const constructed = constructorName(failure);
721
+ if (constructed !== undefined && constructed !== "Object")
722
+ return constructed;
723
+ return named ?? "Error";
724
+ }
725
+ function typeName(failure) {
726
+ if (failure === null)
727
+ return "null";
728
+ if (typeof failure !== "object")
729
+ return typeof failure;
730
+ return constructorName(failure) ?? "Object";
731
+ }
732
+ function constructorName(value) {
733
+ const name = read(value, "constructor");
734
+ if (typeof name !== "function" && typeof name !== "object")
735
+ return;
736
+ if (name === null)
737
+ return;
738
+ const own = read(name, "name");
739
+ return typeof own === "string" && own ? own : undefined;
740
+ }
741
+ function read(value, key) {
742
+ try {
743
+ return value[key];
744
+ } catch {
745
+ return;
746
+ }
747
+ }
748
+ function describe(failure) {
749
+ try {
750
+ return typeof failure === "object" && failure !== null ? JSON.stringify(failure) || String(failure) : String(failure);
751
+ } catch {
752
+ return UNREADABLE;
753
+ }
754
+ }
755
+
756
+ // src/model/signal.ts
757
+ var SEVERITY_NUMBER = Object.freeze({
758
+ debug: 5,
759
+ info: 9,
760
+ warn: 13,
761
+ error: 17
762
+ });
763
+ var SEVERITIES = Object.freeze([
764
+ "debug",
765
+ "info",
766
+ "warn",
767
+ "error"
768
+ ]);
769
+ function meetsSeverity(severity, minimum) {
770
+ return SEVERITY_NUMBER[severity] >= SEVERITY_NUMBER[minimum];
771
+ }
772
+ var SPAN_KIND_NUMBER = Object.freeze({
773
+ internal: 1,
774
+ server: 2,
775
+ client: 3,
776
+ producer: 4,
777
+ consumer: 5
778
+ });
779
+ function signalAt(signal) {
780
+ return signal.type === "log" ? signal.at : signal.startedAt;
781
+ }
782
+ function signalSpan(signal) {
783
+ return signal.type === "log" ? signal.span : signal.context;
784
+ }
785
+
786
+ // src/logger/logger.ts
787
+ function createLogger(source) {
788
+ const write = (severity, input, second, third) => {
789
+ const telemetry = resolveTelemetry();
790
+ if (telemetry === undefined)
791
+ return;
792
+ if (!meetsSeverity(severity, telemetry.minimum))
793
+ return;
794
+ const [failure, fields] = split(second, third);
795
+ const span = currentSpan();
796
+ const named = name(input);
797
+ const record = {
798
+ type: "log",
799
+ at: Date.now(),
800
+ severity,
801
+ name: named.name,
802
+ source,
803
+ attributes: mergeAttributes(mergeAttributes(currentAttributes(), named.attributes), attributesOf(fields)),
804
+ ...span === undefined ? {} : { span },
805
+ ...failure === undefined ? {} : { error: errorInfo(failure, telemetry.stackTraces) }
806
+ };
807
+ telemetry.emit(record);
808
+ };
809
+ return {
810
+ enabled(severity) {
811
+ const telemetry = resolveTelemetry();
812
+ return telemetry !== undefined && meetsSeverity(severity, telemetry.minimum);
813
+ },
814
+ debug: (input, attributes) => write("debug", input, attributes),
815
+ info: (input, attributes) => write("info", input, attributes),
816
+ warn: (input, second, third) => write("warn", input, second, third),
817
+ error: (input, second, third) => write("error", input, second, third)
818
+ };
819
+ }
820
+ function split(second, third) {
821
+ if (third !== undefined)
822
+ return [second, third];
823
+ if (second === undefined)
824
+ return [undefined, undefined];
825
+ return isFields(second) ? [undefined, second] : [second, undefined];
826
+ }
827
+ function isFields(value) {
828
+ if (typeof value !== "object" || value === null)
829
+ return false;
830
+ try {
831
+ if (value instanceof Error || Array.isArray(value))
832
+ return false;
833
+ const prototype = Object.getPrototypeOf(value);
834
+ if (prototype === null || prototype === Object.prototype)
835
+ return true;
836
+ return Object.getPrototypeOf(prototype) === null && prototype.constructor?.name === "Object";
837
+ } catch {
838
+ return false;
839
+ }
840
+ }
841
+ function name(input) {
842
+ if (typeof input === "string") {
843
+ return { name: input, attributes: EMPTY_ATTRIBUTES };
844
+ }
845
+ if (isTelemetryEvent(input)) {
846
+ return { name: input.name, attributes: input.attributes };
847
+ }
848
+ try {
849
+ return { name: input(), attributes: EMPTY_ATTRIBUTES };
850
+ } catch (failure) {
851
+ return {
852
+ name: "[message failed to build]",
853
+ attributes: {
854
+ "telemetry.message.invalid": errorInfo(failure, false).type
855
+ }
856
+ };
857
+ }
858
+ }
859
+ // src/span/scope.ts
860
+ class Span {
861
+ constructor(context, name, kind, stackTraces = true) {
862
+ this.status = "ok";
863
+ this.own = {};
864
+ this.happened = [];
865
+ this.context = context;
866
+ this.name = name;
867
+ this.kind = kind;
868
+ this.stackTraces = stackTraces;
869
+ }
870
+ get traceId() {
871
+ return this.context.traceId;
872
+ }
873
+ get spanId() {
874
+ return this.context.spanId;
875
+ }
876
+ traceparent() {
877
+ return renderTraceparent(this.context);
878
+ }
879
+ attribute(name, value) {
880
+ this.own[name] = coerceAttribute(value);
881
+ }
882
+ attributes(record) {
883
+ Object.assign(this.own, attributesOf(record));
884
+ }
885
+ event(input, attributes) {
886
+ const declared = isTelemetryEvent(input);
887
+ this.happened.push({
888
+ name: declared ? input.name : input,
889
+ at: Date.now(),
890
+ attributes: declared ? input.attributes : attributesOf(attributes)
891
+ });
892
+ }
893
+ fail(failure) {
894
+ if (this.error !== undefined)
895
+ return;
896
+ const cancelled = isAbort(failure);
897
+ this.status = cancelled ? "cancelled" : "error";
898
+ this.error = errorInfo(failure, !cancelled && this.stackTraces);
899
+ }
900
+ record(startedAt, endedAt, parent, inherited) {
901
+ return {
902
+ type: "span",
903
+ name: this.name,
904
+ context: this.context,
905
+ ...parent === undefined ? {} : { parent },
906
+ kind: this.kind,
907
+ startedAt,
908
+ endedAt,
909
+ status: this.status,
910
+ attributes: { ...mergeAttributes(inherited, this.own) },
911
+ events: [...this.happened],
912
+ ...this.error === undefined ? {} : { error: this.error }
913
+ };
914
+ }
915
+ }
916
+ // src/span/span.ts
917
+ function span(name, optionsOrBlock, maybeBlock) {
918
+ const [options, block] = read2(optionsOrBlock, maybeBlock);
919
+ return open(name, options, block, undefined, "internal");
920
+ }
921
+ function continuing(traceparent, name, optionsOrBlock, maybeBlock) {
922
+ const [options, block] = read2(optionsOrBlock, maybeBlock);
923
+ const remote = parseTraceparent(traceparent) ?? undefined;
924
+ return open(name, options, block, remote, "server");
925
+ }
926
+ async function open(name, options, block, remote, fallbackKind) {
927
+ const parent = currentContext();
928
+ const telemetry = parent?.telemetry ?? installedTelemetry();
929
+ const kind = options.kind ?? fallbackKind;
930
+ if (telemetry === undefined) {
931
+ return block(new Span(DETACHED_SPAN_CONTEXT, name, kind));
932
+ }
933
+ const parentSpan = remote ?? parent?.span;
934
+ const traceId = parentSpan?.traceId ?? randomTraceId();
935
+ const context = {
936
+ traceId,
937
+ spanId: randomSpanId(),
938
+ sampled: parentSpan?.sampled ?? decide(telemetry, traceId),
939
+ remote: false
940
+ };
941
+ const inherited = mergeAttributes(parent?.attributes ?? EMPTY_ATTRIBUTES, attributesOf(options.attributes));
942
+ const scope = new Span(context, name, kind, telemetry.stackTraces);
943
+ const startedAt = Date.now();
944
+ try {
945
+ return await runWithContext({ telemetry, span: context, attributes: inherited }, () => block(scope));
946
+ } catch (failure) {
947
+ try {
948
+ scope.fail(failure);
949
+ } catch {
950
+ scope.status = "error";
951
+ }
952
+ throw failure;
953
+ } finally {
954
+ if (context.sampled) {
955
+ telemetry.emit(scope.record(startedAt, Date.now(), parentSpan?.spanId, inherited));
956
+ }
957
+ }
958
+ }
959
+ function read2(optionsOrBlock, maybeBlock) {
960
+ return typeof optionsOrBlock === "function" ? [{}, optionsOrBlock] : [optionsOrBlock, maybeBlock];
961
+ }
962
+ function decide(telemetry, traceId) {
963
+ try {
964
+ return telemetry.sampler.sample(traceId);
965
+ } catch {
966
+ return false;
967
+ }
968
+ }
189
969
  export {
970
+ DEFAULT_MAX_SIZE,
971
+ DEFAULT_ROTATION_PERIOD,
190
972
  DETACHED_SPAN_CONTEXT,
191
973
  EMPTY_ATTRIBUTES,
974
+ INVALID_EVENT_ATTRIBUTE,
192
975
  INVALID_SPAN_ID,
193
976
  INVALID_TRACE_ID,
194
977
  SEVERITIES,
195
978
  SEVERITY_NUMBER,
196
979
  SPAN_KIND_NUMBER,
980
+ Span,
981
+ TELEMETRY_DEFAULTS,
982
+ Telemetry,
983
+ UNREADABLE,
197
984
  alwaysSample,
198
985
  attributesOf,
199
986
  coerceAttribute,
987
+ consoleExporter,
988
+ continuing,
989
+ createLogger,
990
+ createTelemetry,
991
+ currentAttributes,
992
+ currentContext,
993
+ currentSpan,
994
+ currentTraceparent,
995
+ errorInfo,
996
+ event,
997
+ fileExporter,
998
+ installedTelemetry,
999
+ isAbort,
200
1000
  isDetached,
201
1001
  isEmptyAttributes,
1002
+ isTelemetryEvent,
202
1003
  isValidSpanId,
203
1004
  isValidTraceId,
1005
+ jsonLinesExporter,
204
1006
  meetsSeverity,
205
1007
  mergeAttributes,
206
1008
  neverSample,
207
1009
  parseTraceparent,
1010
+ prunable,
208
1011
  randomSpanId,
209
1012
  randomTraceId,
210
1013
  ratioSampler,
211
1014
  renderTraceparent,
1015
+ resolveTelemetry,
1016
+ rolledName,
1017
+ rolledOf,
1018
+ rotationDue,
1019
+ runWithContext,
212
1020
  signalAt,
213
- signalSpan
1021
+ signalSpan,
1022
+ span,
1023
+ uninstallTelemetry,
1024
+ withAttributes,
1025
+ withTelemetry
214
1026
  };
215
1027
 
216
- //# debugId=909718EB5895F3DC64756E2164756E21
1028
+ //# debugId=48D06AD1E41A02B464756E2164756E21
217
1029
  //# sourceMappingURL=index.js.map