@aztec-labs/telemetry-client 6.0.0-nightly.20260829

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.
Files changed (105) hide show
  1. package/dest/attributes.d.ts +143 -0
  2. package/dest/attributes.d.ts.map +1 -0
  3. package/dest/attributes.js +91 -0
  4. package/dest/bench.d.ts +34 -0
  5. package/dest/bench.d.ts.map +1 -0
  6. package/dest/bench.js +115 -0
  7. package/dest/config.d.ts +21 -0
  8. package/dest/config.d.ts.map +1 -0
  9. package/dest/config.js +85 -0
  10. package/dest/index.d.ts +12 -0
  11. package/dest/index.d.ts.map +1 -0
  12. package/dest/index.js +11 -0
  13. package/dest/json_rpc_server_metrics.d.ts +27 -0
  14. package/dest/json_rpc_server_metrics.d.ts.map +1 -0
  15. package/dest/json_rpc_server_metrics.js +154 -0
  16. package/dest/l1_metrics.d.ts +17 -0
  17. package/dest/l1_metrics.d.ts.map +1 -0
  18. package/dest/l1_metrics.js +54 -0
  19. package/dest/lmdb_metrics.d.ts +18 -0
  20. package/dest/lmdb_metrics.d.ts.map +1 -0
  21. package/dest/lmdb_metrics.js +34 -0
  22. package/dest/metric-utils.d.ts +24 -0
  23. package/dest/metric-utils.d.ts.map +1 -0
  24. package/dest/metric-utils.js +59 -0
  25. package/dest/metrics.d.ts +338 -0
  26. package/dest/metrics.d.ts.map +1 -0
  27. package/dest/metrics.js +1702 -0
  28. package/dest/monitored_batch_span_processor.d.ts +33 -0
  29. package/dest/monitored_batch_span_processor.d.ts.map +1 -0
  30. package/dest/monitored_batch_span_processor.js +111 -0
  31. package/dest/nodejs_metrics_monitor.d.ts +19 -0
  32. package/dest/nodejs_metrics_monitor.d.ts.map +1 -0
  33. package/dest/nodejs_metrics_monitor.js +115 -0
  34. package/dest/noop.d.ts +19 -0
  35. package/dest/noop.d.ts.map +1 -0
  36. package/dest/noop.js +104 -0
  37. package/dest/otel.d.ts +43 -0
  38. package/dest/otel.d.ts.map +1 -0
  39. package/dest/otel.js +537 -0
  40. package/dest/otel_filter_metric_exporter.d.ts +20 -0
  41. package/dest/otel_filter_metric_exporter.d.ts.map +1 -0
  42. package/dest/otel_filter_metric_exporter.js +67 -0
  43. package/dest/otel_logger_provider.d.ts +4 -0
  44. package/dest/otel_logger_provider.d.ts.map +1 -0
  45. package/dest/otel_logger_provider.js +25 -0
  46. package/dest/otel_propagation.d.ts +6 -0
  47. package/dest/otel_propagation.d.ts.map +1 -0
  48. package/dest/otel_propagation.js +102 -0
  49. package/dest/otel_resource.d.ts +3 -0
  50. package/dest/otel_resource.d.ts.map +1 -0
  51. package/dest/otel_resource.js +53 -0
  52. package/dest/prom_otel_adapter.d.ts +176 -0
  53. package/dest/prom_otel_adapter.d.ts.map +1 -0
  54. package/dest/prom_otel_adapter.js +292 -0
  55. package/dest/start.d.ts +7 -0
  56. package/dest/start.d.ts.map +1 -0
  57. package/dest/start.js +25 -0
  58. package/dest/telemetry.d.ts +149 -0
  59. package/dest/telemetry.d.ts.map +1 -0
  60. package/dest/telemetry.js +139 -0
  61. package/dest/vendor/attributes.d.ts +6 -0
  62. package/dest/vendor/attributes.d.ts.map +1 -0
  63. package/dest/vendor/attributes.js +6 -0
  64. package/dest/vendor/otel-pino-stream.d.ts +40 -0
  65. package/dest/vendor/otel-pino-stream.d.ts.map +1 -0
  66. package/dest/vendor/otel-pino-stream.js +229 -0
  67. package/dest/with_tracer.d.ts +33 -0
  68. package/dest/with_tracer.d.ts.map +1 -0
  69. package/dest/with_tracer.js +32 -0
  70. package/dest/wrappers/fetch.d.ts +16 -0
  71. package/dest/wrappers/fetch.d.ts.map +1 -0
  72. package/dest/wrappers/fetch.js +42 -0
  73. package/dest/wrappers/index.d.ts +3 -0
  74. package/dest/wrappers/index.d.ts.map +1 -0
  75. package/dest/wrappers/index.js +2 -0
  76. package/dest/wrappers/json_rpc_server.d.ts +4 -0
  77. package/dest/wrappers/json_rpc_server.d.ts.map +1 -0
  78. package/dest/wrappers/json_rpc_server.js +16 -0
  79. package/package.json +95 -0
  80. package/src/attributes.ts +174 -0
  81. package/src/bench.ts +168 -0
  82. package/src/config.ts +135 -0
  83. package/src/index.ts +11 -0
  84. package/src/json_rpc_server_metrics.ts +150 -0
  85. package/src/l1_metrics.ts +64 -0
  86. package/src/lmdb_metrics.ts +45 -0
  87. package/src/metric-utils.ts +75 -0
  88. package/src/metrics.ts +1802 -0
  89. package/src/monitored_batch_span_processor.ts +147 -0
  90. package/src/nodejs_metrics_monitor.ts +135 -0
  91. package/src/noop.ts +152 -0
  92. package/src/otel.ts +482 -0
  93. package/src/otel_filter_metric_exporter.ts +80 -0
  94. package/src/otel_logger_provider.ts +31 -0
  95. package/src/otel_propagation.ts +107 -0
  96. package/src/otel_resource.ts +71 -0
  97. package/src/prom_otel_adapter.ts +450 -0
  98. package/src/start.ts +42 -0
  99. package/src/telemetry.ts +348 -0
  100. package/src/vendor/attributes.ts +6 -0
  101. package/src/vendor/otel-pino-stream.ts +279 -0
  102. package/src/with_tracer.ts +35 -0
  103. package/src/wrappers/fetch.ts +50 -0
  104. package/src/wrappers/index.ts +2 -0
  105. package/src/wrappers/json_rpc_server.ts +26 -0
@@ -0,0 +1,147 @@
1
+ import type { Logger } from '@aztec-labs/foundation/log';
2
+ import { type Context, SpanStatusCode, TraceFlags } from '@opentelemetry/api';
3
+ import { type ExportResult, hrTimeToMilliseconds } from '@opentelemetry/core';
4
+ import type { SpanExporter } from '@opentelemetry/sdk-trace-base';
5
+ import { BatchSpanProcessor, type BufferConfig, type ReadableSpan, type Span } from '@opentelemetry/sdk-trace-node';
6
+
7
+ /** Minimum interval between drop warnings to avoid log spam. */
8
+ const DROP_WARNING_INTERVAL_MS = 30_000;
9
+
10
+ const DEFAULT_MIN_TRACE_DURATION_MS = 10;
11
+
12
+ const DEFAULT_MAX_QUEUE_SIZE = 65536;
13
+
14
+ /** Cap on the per-export batch size, so a large queue can actually be drained instead of dribbling out
15
+ * at the SDK default of 512 spans per scheduled export. Kept <= maxQueueSize per the BatchSpanProcessor contract. */
16
+ const DEFAULT_MAX_EXPORT_BATCH_SIZE = 4096;
17
+
18
+ export type MonitoredBatchSpanProcessorConfig = BufferConfig & {
19
+ minTraceDurationMs?: number;
20
+ };
21
+
22
+ /** Shared counter of spans sitting in the SDK's queue. It is a plain object rather than a field on the
23
+ * processor because the exporter wrapper that decrements it is built before `super()` runs, when `this`
24
+ * is not yet available. */
25
+ type QueueGauge = { size: number };
26
+
27
+ /**
28
+ * Delegating exporter that reports how many spans left the queue.
29
+ *
30
+ * `BatchSpanProcessor` removes a batch from its internal buffer and hands it straight to
31
+ * `exporter.export()` — exactly once per batch — so this is an exact drain signal. Spans in flight are
32
+ * already off the queue, which matches how the SDK evaluates its own `maxQueueSize` limit.
33
+ */
34
+ class DrainCountingExporter implements SpanExporter {
35
+ constructor(
36
+ private readonly inner: SpanExporter,
37
+ private readonly queue: QueueGauge,
38
+ ) {}
39
+
40
+ export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {
41
+ this.queue.size = Math.max(0, this.queue.size - spans.length);
42
+ this.inner.export(spans, resultCallback);
43
+ }
44
+
45
+ shutdown(): Promise<void> {
46
+ return this.inner.shutdown();
47
+ }
48
+
49
+ forceFlush(): Promise<void> {
50
+ return this.inner.forceFlush?.() ?? Promise.resolve();
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Wraps BatchSpanProcessor to emit warnings when spans are dropped due to a full queue.
56
+ * The standard BatchSpanProcessor silently discards spans when its internal queue reaches
57
+ * maxQueueSize, making telemetry data loss invisible to operators.
58
+ */
59
+ export class MonitoredBatchSpanProcessor extends BatchSpanProcessor {
60
+ private readonly maxQueueSize: number;
61
+ private readonly maxExportBatchSize: number;
62
+ private readonly minTraceDurationMs: number;
63
+ private readonly log: Logger;
64
+ private readonly queue: QueueGauge;
65
+
66
+ private droppedSinceLastWarning = 0;
67
+ private totalDropped = 0;
68
+ private lastWarningTime = 0;
69
+ private shuttingDown = false;
70
+
71
+ constructor(exporter: SpanExporter, log: Logger, config?: MonitoredBatchSpanProcessorConfig) {
72
+ const maxQueueSize = config?.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE;
73
+ const maxExportBatchSize = Math.min(config?.maxExportBatchSize ?? DEFAULT_MAX_EXPORT_BATCH_SIZE, maxQueueSize);
74
+ const queue: QueueGauge = { size: 0 };
75
+ super(new DrainCountingExporter(exporter, queue), { ...config, maxQueueSize, maxExportBatchSize });
76
+ this.queue = queue;
77
+ this.maxQueueSize = maxQueueSize;
78
+ this.maxExportBatchSize = maxExportBatchSize;
79
+ this.minTraceDurationMs = Math.max(0, config?.minTraceDurationMs ?? DEFAULT_MIN_TRACE_DURATION_MS);
80
+ this.log = log;
81
+ }
82
+
83
+ override onStart(span: Span, parentContext: Context): void {
84
+ super.onStart(span, parentContext);
85
+ }
86
+
87
+ override onEnd(span: ReadableSpan): void {
88
+ if (this.shouldDropShortSpan(span)) {
89
+ return;
90
+ }
91
+
92
+ if (this.isQueued(span)) {
93
+ if (this.queue.size >= this.maxQueueSize) {
94
+ this.droppedSinceLastWarning++;
95
+ this.totalDropped++;
96
+ this.maybeLogDropWarning();
97
+ } else {
98
+ this.queue.size++;
99
+ }
100
+ }
101
+
102
+ super.onEnd(span);
103
+ }
104
+
105
+ override async shutdown(): Promise<void> {
106
+ this.shuttingDown = true;
107
+ if (this.totalDropped > 0) {
108
+ this.log.warn(`BatchSpanProcessor shutting down with ${this.totalDropped} total spans dropped`, {
109
+ totalDropped: this.totalDropped,
110
+ });
111
+ }
112
+ await super.shutdown();
113
+ }
114
+
115
+ private shouldDropShortSpan(span: ReadableSpan): boolean {
116
+ return (
117
+ this.minTraceDurationMs > 0 &&
118
+ span.status.code !== SpanStatusCode.ERROR &&
119
+ hrTimeToMilliseconds(span.duration) < this.minTraceDurationMs
120
+ );
121
+ }
122
+
123
+ /** Mirrors the guards the SDK applies before buffering a span. Spans it discards outright never reach the
124
+ * queue and never reach the exporter, so counting them would leak the estimate upwards forever. */
125
+ private isQueued(span: ReadableSpan): boolean {
126
+ return !this.shuttingDown && (span.spanContext().traceFlags & TraceFlags.SAMPLED) !== 0;
127
+ }
128
+
129
+ private maybeLogDropWarning(): void {
130
+ const now = Date.now();
131
+ if (now - this.lastWarningTime >= DROP_WARNING_INTERVAL_MS) {
132
+ this.log.warn(
133
+ `BatchSpanProcessor dropping spans: queue full (maxQueueSize=${this.maxQueueSize}, ` +
134
+ `maxExportBatchSize=${this.maxExportBatchSize}). ` +
135
+ `${this.droppedSinceLastWarning} dropped since last warning, ${this.totalDropped} total.`,
136
+ {
137
+ droppedSinceLastWarning: this.droppedSinceLastWarning,
138
+ totalDropped: this.totalDropped,
139
+ maxQueueSize: this.maxQueueSize,
140
+ maxExportBatchSize: this.maxExportBatchSize,
141
+ },
142
+ );
143
+ this.droppedSinceLastWarning = 0;
144
+ this.lastWarningTime = now;
145
+ }
146
+ }
147
+ }
@@ -0,0 +1,135 @@
1
+ import type { Observable } from '@opentelemetry/api';
2
+ import { type EventLoopUtilization, type IntervalHistogram, monitorEventLoopDelay, performance } from 'node:perf_hooks';
3
+
4
+ import * as Attributes from './attributes.js';
5
+ import { createUpDownCounterWithDefault } from './metric-utils.js';
6
+ import * as Metrics from './metrics.js';
7
+ import type { BatchObservableResult, Meter, ObservableGauge, UpDownCounter } from './telemetry.js';
8
+
9
+ /** Monitors Node.js runtime metrics */
10
+ export class NodejsMetricsMonitor {
11
+ private eventLoopDelayGauges: {
12
+ min: ObservableGauge;
13
+ max: ObservableGauge;
14
+ mean: ObservableGauge;
15
+ stddev: ObservableGauge;
16
+ p50: ObservableGauge;
17
+ p90: ObservableGauge;
18
+ p99: ObservableGauge;
19
+ };
20
+
21
+ // skip `rss` because that's already tracked by @opentelemetry/host-metrics
22
+ // description of each field here https://nodejs.org/api/process.html#processmemoryusage
23
+ private memoryGauges: Record<Exclude<keyof NodeJS.MemoryUsage, 'rss'>, ObservableGauge>;
24
+
25
+ private eventLoopUilization: ObservableGauge;
26
+ private eventLoopTime: UpDownCounter;
27
+
28
+ private started = false;
29
+
30
+ private lastELU: EventLoopUtilization | undefined;
31
+ private eventLoopDelay: IntervalHistogram;
32
+
33
+ constructor(private meter: Meter) {
34
+ this.eventLoopDelayGauges = {
35
+ min: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_MIN),
36
+ mean: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_MEAN),
37
+ max: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_MAX),
38
+ stddev: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_STDDEV),
39
+ p50: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_P50),
40
+ p90: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_P90),
41
+ p99: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_P99),
42
+ };
43
+
44
+ this.eventLoopUilization = meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_UTILIZATION);
45
+ this.eventLoopTime = createUpDownCounterWithDefault(meter, Metrics.NODEJS_EVENT_LOOP_TIME, {
46
+ [Attributes.NODEJS_EVENT_LOOP_STATE]: ['idle', 'active'],
47
+ });
48
+ this.eventLoopDelay = monitorEventLoopDelay();
49
+
50
+ this.memoryGauges = {
51
+ heapUsed: meter.createObservableGauge(Metrics.NODEJS_MEMORY_HEAP_USAGE),
52
+ heapTotal: meter.createObservableGauge(Metrics.NODEJS_MEMORY_HEAP_TOTAL),
53
+ arrayBuffers: meter.createObservableGauge(Metrics.NODEJS_MEMORY_BUFFER_USAGE),
54
+ external: meter.createObservableGauge(Metrics.NODEJS_MEMORY_NATIVE_USAGE),
55
+ };
56
+ }
57
+
58
+ start(): void {
59
+ if (this.started) {
60
+ return;
61
+ }
62
+
63
+ this.lastELU = performance.eventLoopUtilization();
64
+ this.eventLoopDelay.enable();
65
+ this.meter.addBatchObservableCallback(this.measure, [
66
+ this.eventLoopUilization,
67
+ ...Object.values(this.eventLoopDelayGauges),
68
+ ...Object.values(this.memoryGauges),
69
+ ]);
70
+ }
71
+
72
+ stop(): void {
73
+ if (!this.started) {
74
+ return;
75
+ }
76
+ this.meter.removeBatchObservableCallback(this.measure, [
77
+ this.eventLoopUilization,
78
+ ...Object.values(this.eventLoopDelayGauges),
79
+ ...Object.values(this.memoryGauges),
80
+ ]);
81
+ this.eventLoopDelay.disable();
82
+ this.eventLoopDelay.reset();
83
+ this.lastELU = undefined;
84
+ }
85
+
86
+ private measure = (obs: BatchObservableResult): void => {
87
+ this.measureMemoryUsage(obs);
88
+ this.measureEventLoopDelay(obs);
89
+ };
90
+
91
+ private measureMemoryUsage = (observer: BatchObservableResult) => {
92
+ const mem = process.memoryUsage();
93
+
94
+ observer.observe(this.memoryGauges.heapUsed, mem.heapUsed);
95
+ observer.observe(this.memoryGauges.heapTotal, mem.heapTotal);
96
+ observer.observe(this.memoryGauges.arrayBuffers, mem.arrayBuffers);
97
+ observer.observe(this.memoryGauges.external, mem.external);
98
+ };
99
+
100
+ private measureEventLoopDelay = (obs: BatchObservableResult): void => {
101
+ const newELU = performance.eventLoopUtilization();
102
+ const delta = performance.eventLoopUtilization(newELU, this.lastELU);
103
+ this.lastELU = newELU;
104
+
105
+ // `utilization` [0,1] represents how much the event loop is busy vs waiting for new events to come in
106
+ // This should be corelated with CPU usage to gauge the performance characteristics of services
107
+ // 100% utilization leads to high latency because the event loop is _always_ busy, there's no breathing room for events to be processed quickly.
108
+ // Docs and examples:
109
+ // - https://nodesource.com/blog/event-loop-utilization-nodejs
110
+ // - https://youtu.be/WetXnEPraYM
111
+ obs.observe(this.eventLoopUilization, delta.utilization);
112
+
113
+ this.eventLoopTime.add(Math.trunc(delta.idle), { [Attributes.NODEJS_EVENT_LOOP_STATE]: 'idle' });
114
+ this.eventLoopTime.add(Math.trunc(delta.active), { [Attributes.NODEJS_EVENT_LOOP_STATE]: 'active' });
115
+
116
+ safeObserveInt(obs, this.eventLoopDelayGauges.min, this.eventLoopDelay.min);
117
+ safeObserveInt(obs, this.eventLoopDelayGauges.mean, this.eventLoopDelay.mean);
118
+ safeObserveInt(obs, this.eventLoopDelayGauges.max, this.eventLoopDelay.max);
119
+ safeObserveInt(obs, this.eventLoopDelayGauges.stddev, this.eventLoopDelay.stddev);
120
+ safeObserveInt(obs, this.eventLoopDelayGauges.p50, this.eventLoopDelay.percentile(50));
121
+ safeObserveInt(obs, this.eventLoopDelayGauges.p90, this.eventLoopDelay.percentile(90));
122
+ safeObserveInt(obs, this.eventLoopDelayGauges.p99, this.eventLoopDelay.percentile(99));
123
+
124
+ this.eventLoopDelay.reset();
125
+ };
126
+ }
127
+
128
+ function safeObserveInt(observer: BatchObservableResult, metric: Observable, value: number, attrs?: object) {
129
+ // discard NaN, Infinity, -Infinity
130
+ if (!Number.isFinite(value)) {
131
+ return;
132
+ }
133
+
134
+ observer.observe(metric, Math.trunc(value), attrs);
135
+ }
package/src/noop.ts ADDED
@@ -0,0 +1,152 @@
1
+ import { type Context, type Span, type SpanContext, type Tracer, createNoopMeter } from '@opentelemetry/api';
2
+
3
+ import type { MetricDefinition } from './metrics.js';
4
+ import type {
5
+ Gauge,
6
+ Histogram,
7
+ Meter,
8
+ ObservableGauge,
9
+ ObservableUpDownCounter,
10
+ TelemetryClient,
11
+ UpDownCounter,
12
+ } from './telemetry.js';
13
+
14
+ /** A no-op meter that implements our custom Meter interface */
15
+ class NoopMeter implements Meter {
16
+ private otelMeter = createNoopMeter();
17
+
18
+ createGauge(_metric: MetricDefinition): Gauge {
19
+ return this.otelMeter.createGauge('');
20
+ }
21
+
22
+ createObservableGauge(_metric: MetricDefinition): ObservableGauge {
23
+ return this.otelMeter.createObservableGauge('');
24
+ }
25
+
26
+ createHistogram(_metric: MetricDefinition, _extraOptions?: Parameters<Meter['createHistogram']>[1]): Histogram {
27
+ return this.otelMeter.createHistogram('');
28
+ }
29
+
30
+ createUpDownCounter(_metric: MetricDefinition): UpDownCounter {
31
+ return this.otelMeter.createUpDownCounter('');
32
+ }
33
+
34
+ createObservableUpDownCounter(_metric: MetricDefinition): ObservableUpDownCounter {
35
+ return this.otelMeter.createObservableUpDownCounter('');
36
+ }
37
+
38
+ addBatchObservableCallback(
39
+ callback: Parameters<Meter['addBatchObservableCallback']>[0],
40
+ observables: Parameters<Meter['addBatchObservableCallback']>[1],
41
+ ): void {
42
+ this.otelMeter.addBatchObservableCallback(callback, observables);
43
+ }
44
+
45
+ removeBatchObservableCallback(
46
+ callback: Parameters<Meter['removeBatchObservableCallback']>[0],
47
+ observables: Parameters<Meter['removeBatchObservableCallback']>[1],
48
+ ): void {
49
+ this.otelMeter.removeBatchObservableCallback(callback, observables);
50
+ }
51
+ }
52
+
53
+ export class NoopTelemetryClient implements TelemetryClient {
54
+ private meter = new NoopMeter();
55
+
56
+ setExportedPublicTelemetry(_prefixes: string[]): void {}
57
+ setPublicTelemetryCollectFrom(_roles: string[]): void {}
58
+
59
+ getMeter(): Meter {
60
+ return this.meter;
61
+ }
62
+
63
+ getTracer(): Tracer {
64
+ return new NoopTracer();
65
+ }
66
+
67
+ stop(): Promise<void> {
68
+ return Promise.resolve();
69
+ }
70
+
71
+ flush(): Promise<void> {
72
+ return Promise.resolve();
73
+ }
74
+
75
+ isEnabled() {
76
+ return false;
77
+ }
78
+
79
+ getTraceContext(): string | undefined {
80
+ return undefined;
81
+ }
82
+
83
+ extractPropagatedContext(_traceContext: string): Context | undefined {
84
+ return undefined;
85
+ }
86
+ }
87
+
88
+ // @opentelemetry/api internally uses NoopTracer and NoopSpan but they're not exported
89
+ // make our own versions
90
+ // https://github.com/open-telemetry/opentelemetry-js/issues/4518#issuecomment-2179405444
91
+ export class NoopTracer implements Tracer {
92
+ startSpan(): Span {
93
+ return new NoopSpan();
94
+ }
95
+
96
+ startActiveSpan<F extends (...args: any[]) => any>(_name: string, ...args: unknown[]): ReturnType<F> {
97
+ // there are three different signatures for startActiveSpan, grab the function, we don't care about the rest
98
+ const fn = args.find(arg => typeof arg === 'function') as F;
99
+ return fn(new NoopSpan());
100
+ }
101
+ }
102
+
103
+ class NoopSpan implements Span {
104
+ private recording: boolean = true;
105
+ addEvent(): this {
106
+ return this;
107
+ }
108
+
109
+ addLink(): this {
110
+ return this;
111
+ }
112
+
113
+ addLinks(): this {
114
+ return this;
115
+ }
116
+
117
+ end(): void {
118
+ this.recording = false;
119
+ }
120
+
121
+ isRecording(): boolean {
122
+ return this.recording;
123
+ }
124
+
125
+ recordException(): void {
126
+ return;
127
+ }
128
+
129
+ setAttribute(): this {
130
+ return this;
131
+ }
132
+
133
+ setAttributes(): this {
134
+ return this;
135
+ }
136
+
137
+ setStatus(): this {
138
+ return this;
139
+ }
140
+
141
+ spanContext(): SpanContext {
142
+ return {
143
+ spanId: '',
144
+ traceId: '',
145
+ traceFlags: 0,
146
+ };
147
+ }
148
+
149
+ updateName(): this {
150
+ return this;
151
+ }
152
+ }