@aztec/telemetry-client 0.0.1-commit.fcb71a6 → 0.0.1-commit.fffb133c

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 (45) hide show
  1. package/dest/bench.d.ts +3 -1
  2. package/dest/bench.d.ts.map +1 -1
  3. package/dest/bench.js +24 -14
  4. package/dest/l1_metrics.d.ts +2 -2
  5. package/dest/l1_metrics.d.ts.map +1 -1
  6. package/dest/l1_metrics.js +4 -20
  7. package/dest/lmdb_metrics.d.ts +2 -2
  8. package/dest/lmdb_metrics.d.ts.map +1 -1
  9. package/dest/lmdb_metrics.js +4 -20
  10. package/dest/metric-utils.d.ts +5 -0
  11. package/dest/metric-utils.d.ts.map +1 -0
  12. package/dest/metric-utils.js +7 -0
  13. package/dest/metrics.d.ts +246 -224
  14. package/dest/metrics.d.ts.map +1 -1
  15. package/dest/metrics.js +1237 -222
  16. package/dest/nodejs_metrics_monitor.d.ts +3 -5
  17. package/dest/nodejs_metrics_monitor.d.ts.map +1 -1
  18. package/dest/nodejs_metrics_monitor.js +14 -41
  19. package/dest/noop.d.ts +6 -3
  20. package/dest/noop.d.ts.map +1 -1
  21. package/dest/noop.js +32 -1
  22. package/dest/otel.d.ts +5 -3
  23. package/dest/otel.d.ts.map +1 -1
  24. package/dest/otel.js +51 -4
  25. package/dest/prom_otel_adapter.d.ts +1 -1
  26. package/dest/prom_otel_adapter.d.ts.map +1 -1
  27. package/dest/prom_otel_adapter.js +15 -7
  28. package/dest/telemetry.d.ts +35 -24
  29. package/dest/telemetry.d.ts.map +1 -1
  30. package/dest/telemetry.js +46 -23
  31. package/dest/wrappers/l2_block_stream.d.ts +2 -2
  32. package/dest/wrappers/l2_block_stream.d.ts.map +1 -1
  33. package/dest/wrappers/l2_block_stream.js +385 -11
  34. package/package.json +4 -4
  35. package/src/bench.ts +27 -15
  36. package/src/l1_metrics.ts +5 -20
  37. package/src/lmdb_metrics.ts +5 -26
  38. package/src/metric-utils.ts +12 -0
  39. package/src/metrics.ts +1289 -250
  40. package/src/nodejs_metrics_monitor.ts +16 -52
  41. package/src/noop.ts +61 -3
  42. package/src/otel.ts +76 -6
  43. package/src/prom_otel_adapter.ts +12 -18
  44. package/src/telemetry.ts +102 -65
  45. package/src/wrappers/l2_block_stream.ts +4 -1
@@ -3,17 +3,9 @@ import { type EventLoopUtilization, type IntervalHistogram, monitorEventLoopDela
3
3
 
4
4
  import * as Attributes from './attributes.js';
5
5
  import * as Metrics from './metrics.js';
6
- import {
7
- type BatchObservableResult,
8
- type Meter,
9
- type ObservableGauge,
10
- type UpDownCounter,
11
- ValueType,
12
- } from './telemetry.js';
13
-
14
- /**
15
- * Detector for custom Aztec attributes
16
- */
6
+ import type { BatchObservableResult, Meter, ObservableGauge, UpDownCounter } from './telemetry.js';
7
+
8
+ /** Monitors Node.js runtime metrics */
17
9
  export class NodejsMetricsMonitor {
18
10
  private eventLoopDelayGauges: {
19
11
  min: ObservableGauge;
@@ -38,53 +30,25 @@ export class NodejsMetricsMonitor {
38
30
  private eventLoopDelay: IntervalHistogram;
39
31
 
40
32
  constructor(private meter: Meter) {
41
- const nsObsGauge = (name: (typeof Metrics)[keyof typeof Metrics], description: string) =>
42
- meter.createObservableGauge(name, {
43
- unit: 'ns',
44
- valueType: ValueType.INT,
45
- description,
46
- });
47
-
48
33
  this.eventLoopDelayGauges = {
49
- min: nsObsGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_MIN, 'Minimum delay of the event loop'),
50
- mean: nsObsGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_MEAN, 'Mean delay of the event loop'),
51
- max: nsObsGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_MAX, 'Max delay of the event loop'),
52
- stddev: nsObsGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_STDDEV, 'Stddev delay of the event loop'),
53
- p50: nsObsGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_P50, 'P50 delay of the event loop'),
54
- p90: nsObsGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_P90, 'P90 delay of the event loop'),
55
- p99: nsObsGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_P99, 'P99 delay of the event loop'),
34
+ min: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_MIN),
35
+ mean: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_MEAN),
36
+ max: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_MAX),
37
+ stddev: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_STDDEV),
38
+ p50: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_P50),
39
+ p90: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_P90),
40
+ p99: meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_DELAY_P99),
56
41
  };
57
42
 
58
- this.eventLoopUilization = meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_UTILIZATION, {
59
- valueType: ValueType.DOUBLE,
60
- description: 'How busy is the event loop',
61
- });
62
-
63
- this.eventLoopTime = meter.createUpDownCounter(Metrics.NODEJS_EVENT_LOOP_TIME, {
64
- unit: 'ms',
65
- valueType: ValueType.INT,
66
- description: 'How much time the event loop has spent in a given state',
67
- });
68
-
43
+ this.eventLoopUilization = meter.createObservableGauge(Metrics.NODEJS_EVENT_LOOP_UTILIZATION);
44
+ this.eventLoopTime = meter.createUpDownCounter(Metrics.NODEJS_EVENT_LOOP_TIME);
69
45
  this.eventLoopDelay = monitorEventLoopDelay();
70
46
 
71
47
  this.memoryGauges = {
72
- heapUsed: meter.createObservableGauge(Metrics.NODEJS_MEMORY_HEAP_USAGE, {
73
- unit: 'By',
74
- description: 'Memory used by the V8 heap',
75
- }),
76
- heapTotal: meter.createObservableGauge(Metrics.NODEJS_MEMORY_HEAP_TOTAL, {
77
- unit: 'By',
78
- description: 'The max size the V8 heap can grow to',
79
- }),
80
- arrayBuffers: meter.createObservableGauge(Metrics.NODEJS_MEMORY_BUFFER_USAGE, {
81
- unit: 'By',
82
- description: 'Memory allocated for buffers (includes native memory used)',
83
- }),
84
- external: meter.createObservableGauge(Metrics.NODEJS_MEMORY_NATIVE_USAGE, {
85
- unit: 'By',
86
- description: 'Memory allocated for native C++ objects',
87
- }),
48
+ heapUsed: meter.createObservableGauge(Metrics.NODEJS_MEMORY_HEAP_USAGE),
49
+ heapTotal: meter.createObservableGauge(Metrics.NODEJS_MEMORY_HEAP_TOTAL),
50
+ arrayBuffers: meter.createObservableGauge(Metrics.NODEJS_MEMORY_BUFFER_USAGE),
51
+ external: meter.createObservableGauge(Metrics.NODEJS_MEMORY_NATIVE_USAGE),
88
52
  };
89
53
  }
90
54
 
package/src/noop.ts CHANGED
@@ -1,13 +1,63 @@
1
- import { type Meter, type Span, type SpanContext, type Tracer, createNoopMeter } from '@opentelemetry/api';
1
+ import { type Context, type Span, type SpanContext, type Tracer, createNoopMeter } from '@opentelemetry/api';
2
2
 
3
- import type { TelemetryClient } from './telemetry.js';
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
+ }
4
52
 
5
53
  export class NoopTelemetryClient implements TelemetryClient {
54
+ private meter = new NoopMeter();
55
+
6
56
  setExportedPublicTelemetry(_prefixes: string[]): void {}
7
57
  setPublicTelemetryCollectFrom(_roles: string[]): void {}
8
58
 
9
59
  getMeter(): Meter {
10
- return createNoopMeter();
60
+ return this.meter;
11
61
  }
12
62
 
13
63
  getTracer(): Tracer {
@@ -25,6 +75,14 @@ export class NoopTelemetryClient implements TelemetryClient {
25
75
  isEnabled() {
26
76
  return false;
27
77
  }
78
+
79
+ getTraceContext(): string | undefined {
80
+ return undefined;
81
+ }
82
+
83
+ extractPropagatedContext(_traceContext: string): Context | undefined {
84
+ return undefined;
85
+ }
28
86
  }
29
87
 
30
88
  // @opentelemetry/api internally uses NoopTracer and NoopSpan but they're not exported
package/src/otel.ts CHANGED
@@ -1,16 +1,20 @@
1
1
  import { type LogData, type Logger, addLogDataHandler } from '@aztec/foundation/log';
2
2
 
3
3
  import {
4
+ type Context,
4
5
  DiagConsoleLogger,
5
6
  DiagLogLevel,
6
- type Meter,
7
+ type Meter as OtelMeter,
8
+ ROOT_CONTEXT,
7
9
  type Tracer,
8
10
  type TracerProvider,
9
11
  context,
10
12
  diag,
11
13
  isSpanContextValid,
14
+ propagation,
12
15
  trace,
13
16
  } from '@opentelemetry/api';
17
+ import { W3CTraceContextPropagator } from '@opentelemetry/core';
14
18
  import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
15
19
  import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
16
20
  import { HostMetrics } from '@opentelemetry/host-metrics';
@@ -28,18 +32,67 @@ import { BatchSpanProcessor, NodeTracerProvider } from '@opentelemetry/sdk-trace
28
32
  import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
29
33
 
30
34
  import type { TelemetryClientConfig } from './config.js';
35
+ import { toMetricOptions } from './metric-utils.js';
36
+ import type { MetricDefinition } from './metrics.js';
31
37
  import { NodejsMetricsMonitor } from './nodejs_metrics_monitor.js';
32
38
  import { OtelFilterMetricExporter, PublicOtelFilterMetricExporter } from './otel_filter_metric_exporter.js';
33
39
  import { registerOtelLoggerProvider } from './otel_logger_provider.js';
34
40
  import { getOtelResource } from './otel_resource.js';
35
- import type { TelemetryClient } from './telemetry.js';
41
+ import type {
42
+ Gauge,
43
+ Histogram,
44
+ Meter,
45
+ ObservableGauge,
46
+ ObservableUpDownCounter,
47
+ TelemetryClient,
48
+ UpDownCounter,
49
+ } from './telemetry.js';
50
+
51
+ /** Wraps an OpenTelemetry Meter to implement our custom Meter interface */
52
+ class WrappedMeter implements Meter {
53
+ constructor(private otelMeter: OtelMeter) {}
54
+
55
+ createGauge(metric: MetricDefinition): Gauge {
56
+ return this.otelMeter.createGauge(metric.name, toMetricOptions(metric));
57
+ }
58
+
59
+ createObservableGauge(metric: MetricDefinition): ObservableGauge {
60
+ return this.otelMeter.createObservableGauge(metric.name, toMetricOptions(metric));
61
+ }
62
+
63
+ createHistogram(metric: MetricDefinition, extraOptions?: Parameters<Meter['createHistogram']>[1]): Histogram {
64
+ return this.otelMeter.createHistogram(metric.name, { ...toMetricOptions(metric), ...extraOptions });
65
+ }
66
+
67
+ createUpDownCounter(metric: MetricDefinition): UpDownCounter {
68
+ return this.otelMeter.createUpDownCounter(metric.name, toMetricOptions(metric));
69
+ }
70
+
71
+ createObservableUpDownCounter(metric: MetricDefinition): ObservableUpDownCounter {
72
+ return this.otelMeter.createObservableUpDownCounter(metric.name, toMetricOptions(metric));
73
+ }
74
+
75
+ addBatchObservableCallback(
76
+ callback: Parameters<Meter['addBatchObservableCallback']>[0],
77
+ observables: Parameters<Meter['addBatchObservableCallback']>[1],
78
+ ): void {
79
+ this.otelMeter.addBatchObservableCallback(callback, observables);
80
+ }
81
+
82
+ removeBatchObservableCallback(
83
+ callback: Parameters<Meter['removeBatchObservableCallback']>[0],
84
+ observables: Parameters<Meter['removeBatchObservableCallback']>[1],
85
+ ): void {
86
+ this.otelMeter.removeBatchObservableCallback(callback, observables);
87
+ }
88
+ }
36
89
 
37
90
  export type OpenTelemetryClientFactory = (resource: IResource, log: Logger) => OpenTelemetryClient;
38
91
 
39
92
  export class OpenTelemetryClient implements TelemetryClient {
40
93
  hostMetrics: HostMetrics | undefined;
41
94
  nodejsMetricsMonitor: NodejsMetricsMonitor | undefined;
42
- private meters: Map<string, Meter> = new Map<string, Meter>();
95
+ private meters: Map<string, WrappedMeter> = new Map<string, WrappedMeter>();
43
96
  private tracers: Map<string, Tracer> = new Map<string, Tracer>();
44
97
 
45
98
  protected constructor(
@@ -62,7 +115,8 @@ export class OpenTelemetryClient implements TelemetryClient {
62
115
  getMeter(name: string): Meter {
63
116
  let meter = this.meters.get(name);
64
117
  if (!meter) {
65
- meter = this.meterProvider.getMeter(name, this.resource.attributes[ATTR_SERVICE_VERSION] as string);
118
+ const otelMeter = this.meterProvider.getMeter(name, this.resource.attributes[ATTR_SERVICE_VERSION] as string);
119
+ meter = new WrappedMeter(otelMeter);
66
120
  this.meters.set(name, meter);
67
121
  }
68
122
  return meter;
@@ -100,9 +154,10 @@ export class OpenTelemetryClient implements TelemetryClient {
100
154
  meterProvider: this.meterProvider,
101
155
  });
102
156
 
103
- this.nodejsMetricsMonitor = new NodejsMetricsMonitor(
157
+ const nodejsMeter = new WrappedMeter(
104
158
  this.meterProvider.getMeter(this.resource.attributes[ATTR_SERVICE_NAME] as string),
105
159
  );
160
+ this.nodejsMetricsMonitor = new NodejsMetricsMonitor(nodejsMeter);
106
161
 
107
162
  this.hostMetrics.start();
108
163
  this.nodejsMetricsMonitor.start();
@@ -138,6 +193,19 @@ export class OpenTelemetryClient implements TelemetryClient {
138
193
  ]);
139
194
  }
140
195
 
196
+ public getTraceContext(): string | undefined {
197
+ const carrier: Record<string, string> = {};
198
+ propagation.inject(context.active(), carrier);
199
+ return carrier['traceparent'];
200
+ }
201
+
202
+ public extractPropagatedContext(traceContext: string): Context {
203
+ const extractedContext = propagation.extract(ROOT_CONTEXT, {
204
+ traceparent: traceContext,
205
+ });
206
+ return extractedContext;
207
+ }
208
+
141
209
  public static createMeterProvider(
142
210
  resource: IResource,
143
211
  exporters: Array<PeriodicExportingMetricReaderOptions>,
@@ -279,7 +347,9 @@ export class OpenTelemetryClient implements TelemetryClient {
279
347
  : [],
280
348
  });
281
349
 
282
- tracerProvider.register();
350
+ tracerProvider.register({
351
+ propagator: new W3CTraceContextPropagator(),
352
+ });
283
353
 
284
354
  const exporters: PeriodicExportingMetricReaderOptions[] = [];
285
355
  if (config.metricsCollectorUrl) {
@@ -3,7 +3,8 @@ import { Timer } from '@aztec/foundation/timer';
3
3
 
4
4
  import { Registry } from 'prom-client';
5
5
 
6
- import type { Histogram, Meter, MetricsType, ObservableGauge, TelemetryClient } from './telemetry.js';
6
+ import type { MetricDefinition } from './metrics.js';
7
+ import type { Histogram, Meter, ObservableGauge, TelemetryClient } from './telemetry.js';
7
8
 
8
9
  /**
9
10
  * Types matching the gossipsub and libp2p services
@@ -94,9 +95,8 @@ export class OtelGauge<Labels extends LabelsGeneric = NoLabels> implements IGaug
94
95
  help: string,
95
96
  private labelNames: Array<keyof Labels> = [],
96
97
  ) {
97
- this.gauge = meter.createObservableGauge(name as MetricsType, {
98
- description: help,
99
- });
98
+ const metricDef: MetricDefinition = { name, description: help };
99
+ this.gauge = meter.createObservableGauge(metricDef);
100
100
 
101
101
  // Only observe in the callback when collect() is called
102
102
  this.gauge.addCallback(this.handleObservation.bind(this));
@@ -214,8 +214,8 @@ export class OtelHistogram<Labels extends LabelsGeneric = NoLabels> implements I
214
214
  buckets: number[] = [],
215
215
  private labelNames: Array<keyof Labels> = [],
216
216
  ) {
217
- this.histogram = meter.createHistogram(name as MetricsType, {
218
- description: help,
217
+ const metricDef: MetricDefinition = { name, description: help };
218
+ this.histogram = meter.createHistogram(metricDef, {
219
219
  advice: buckets.length ? { explicitBucketBoundaries: buckets } : undefined,
220
220
  });
221
221
  }
@@ -289,15 +289,9 @@ export class OtelAvgMinMax<Labels extends LabelsGeneric = NoLabels> implements I
289
289
  ) {
290
290
  // Create three separate gauges for avg, min, and max
291
291
  this.gauges = {
292
- avg: meter.createObservableGauge(`${name}_avg` as MetricsType, {
293
- description: `${help} (average)`,
294
- }),
295
- min: meter.createObservableGauge(`${name}_min` as MetricsType, {
296
- description: `${help} (minimum)`,
297
- }),
298
- max: meter.createObservableGauge(`${name}_max` as MetricsType, {
299
- description: `${help} (maximum)`,
300
- }),
292
+ avg: meter.createObservableGauge({ name: `${name}_avg`, description: `${help} (average)` }),
293
+ min: meter.createObservableGauge({ name: `${name}_min`, description: `${help} (minimum)` }),
294
+ max: meter.createObservableGauge({ name: `${name}_max`, description: `${help} (maximum)` }),
301
295
  };
302
296
 
303
297
  // Register callbacks for each gauge
@@ -429,7 +423,7 @@ export class OtelMetricsAdapter extends Registry implements MetricsRegister {
429
423
  return new OtelGauge<Labels>(
430
424
  this.logger,
431
425
  this.meter,
432
- configuration.name as MetricsType,
426
+ configuration.name,
433
427
  configuration.help,
434
428
  configuration.labelNames,
435
429
  );
@@ -439,7 +433,7 @@ export class OtelMetricsAdapter extends Registry implements MetricsRegister {
439
433
  return new OtelHistogram<Labels>(
440
434
  this.logger,
441
435
  this.meter,
442
- configuration.name as MetricsType,
436
+ configuration.name,
443
437
  configuration.help,
444
438
  configuration.buckets,
445
439
  configuration.labelNames,
@@ -450,7 +444,7 @@ export class OtelMetricsAdapter extends Registry implements MetricsRegister {
450
444
  return new OtelAvgMinMax<Labels>(
451
445
  this.logger,
452
446
  this.meter,
453
- configuration.name as MetricsType,
447
+ configuration.name,
454
448
  configuration.help,
455
449
  configuration.labelNames,
456
450
  );
package/src/telemetry.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  type AttributeValue,
3
3
  type BatchObservableCallback,
4
+ type Context,
4
5
  type MetricOptions,
5
6
  type Observable,
6
7
  type BatchObservableResult as OtelBatchObservableResult,
@@ -14,13 +15,14 @@ import {
14
15
  SpanStatusCode,
15
16
  type Tracer,
16
17
  } from '@opentelemetry/api';
17
- import { isPromise } from 'node:util/types';
18
18
 
19
19
  import type * as Attributes from './attributes.js';
20
- import type * as Metrics from './metrics.js';
20
+ import type { MetricDefinition } from './metrics.js';
21
21
  import { getTelemetryClient } from './start.js';
22
22
 
23
- export { type Span, SpanStatusCode, ValueType } from '@opentelemetry/api';
23
+ export { toMetricOptions } from './metric-utils.js';
24
+
25
+ export { type Span, SpanStatusCode, ValueType, type Context } from '@opentelemetry/api';
24
26
 
25
27
  type ValuesOf<T> = T extends Record<string, infer U> ? U : never;
26
28
 
@@ -57,8 +59,8 @@ export type AttributesType = Partial<Record<AttributeNames, AttributeValue>>;
57
59
  /** Subset of attributes allowed to be added to metrics */
58
60
  export type MetricAttributesType = Partial<Record<Exclude<AttributeNames, BannedMetricAttributeNames>, AttributeValue>>;
59
61
 
60
- /** Global registry of metrics */
61
- export type MetricsType = (typeof Metrics)[keyof typeof Metrics];
62
+ /** Re-export MetricDefinition for convenience */
63
+ export type { MetricDefinition } from './metrics.js';
62
64
 
63
65
  export type Gauge = OtelGauge<MetricAttributesType>;
64
66
  export type Histogram = OtelHistogram<MetricAttributesType>;
@@ -77,17 +79,15 @@ export type { Tracer };
77
79
  export interface Meter {
78
80
  /**
79
81
  * Creates a new gauge instrument. A gauge is a metric that represents a single numerical value that can arbitrarily go up and down.
80
- * @param name - The name of the gauge
81
- * @param options - The options for the gauge
82
+ * @param metric - The metric definition
82
83
  */
83
- createGauge(name: MetricsType, options?: MetricOptions): Gauge;
84
+ createGauge(metric: MetricDefinition): Gauge;
84
85
 
85
86
  /**
86
- * Creates a new gauge instrument. A gauge is a metric that represents a single numerical value that can arbitrarily go up and down.
87
- * @param name - The name of the gauge
88
- * @param options - The options for the gauge
87
+ * Creates a new observable gauge instrument. A gauge is a metric that represents a single numerical value that can arbitrarily go up and down.
88
+ * @param metric - The metric definition
89
89
  */
90
- createObservableGauge(name: MetricsType, options?: MetricOptions): ObservableGauge;
90
+ createObservableGauge(metric: MetricDefinition): ObservableGauge;
91
91
 
92
92
  addBatchObservableCallback(
93
93
  callback: BatchObservableCallback<AttributesType>,
@@ -101,24 +101,22 @@ export interface Meter {
101
101
 
102
102
  /**
103
103
  * Creates a new histogram instrument. A histogram is a metric that samples observations (usually things like request durations or response sizes) and counts them in configurable buckets.
104
- * @param name - The name of the histogram
105
- * @param options - The options for the histogram
104
+ * @param metric - The metric definition
105
+ * @param extraOptions - Optional extra options (e.g., advice for bucket boundaries)
106
106
  */
107
- createHistogram(name: MetricsType, options?: MetricOptions): Histogram;
107
+ createHistogram(metric: MetricDefinition, extraOptions?: Partial<MetricOptions>): Histogram;
108
108
 
109
109
  /**
110
110
  * Creates a new counter instrument. A counter can go up or down with a delta from the previous value.
111
- * @param name - The name of the counter
112
- * @param options - The options for the counter
111
+ * @param metric - The metric definition
113
112
  */
114
- createUpDownCounter(name: MetricsType, options?: MetricOptions): UpDownCounter;
113
+ createUpDownCounter(metric: MetricDefinition): UpDownCounter;
115
114
 
116
115
  /**
117
- * Creates a new gauge instrument. A gauge is a metric that represents a single numerical value that can arbitrarily go up and down.
118
- * @param name - The name of the gauge
119
- * @param options - The options for the gauge
116
+ * Creates a new observable up/down counter instrument.
117
+ * @param metric - The metric definition
120
118
  */
121
- createObservableUpDownCounter(name: MetricsType, options?: MetricOptions): ObservableUpDownCounter;
119
+ createObservableUpDownCounter(metric: MetricDefinition): ObservableUpDownCounter;
122
120
  }
123
121
 
124
122
  /**
@@ -160,6 +158,17 @@ export interface TelemetryClient {
160
158
  * Updates the roles that would share telemetry (if enabled)
161
159
  */
162
160
  setPublicTelemetryCollectFrom(roles: string[]): void;
161
+
162
+ /**
163
+ * Get current trace context as an opaque string for propagation.
164
+ * Returns the W3C traceparent header value if a trace is active, undefined otherwise.
165
+ */
166
+ getTraceContext(): string | undefined;
167
+
168
+ /**
169
+ * Recreates a context propagated by a remote system
170
+ */
171
+ extractPropagatedContext(traceContext: string): Context | undefined;
163
172
  }
164
173
 
165
174
  /** Objects that adhere to this interface can use @trackSpan */
@@ -204,24 +213,36 @@ export function trackSpan<T extends Traceable, F extends (...args: any[]) => any
204
213
  // "active" means the span will be alive for the duration of the function execution
205
214
  // and if any other spans are started during the execution of originalMethod, they will be children of this span
206
215
  // behind the scenes this uses AsyncLocalStorage https://nodejs.org/dist/latest-v22.x/docs/api/async_context.html
207
- return this.tracer.startActiveSpan(name, async (span: Span) => {
208
- span.setAttributes(currentAttrs ?? {});
209
-
210
- try {
211
- const res = await originalMethod.call(this, ...args);
212
- const extraAttrs = extraAttributes?.call(this, res);
213
- span.setAttributes(extraAttrs ?? {});
214
- return res;
215
- } catch (err) {
216
- span.setStatus({
217
- code: SpanStatusCode.ERROR,
218
- message: String(err),
219
- });
220
- throw err;
221
- } finally {
222
- span.end();
223
- }
224
- });
216
+ return this.tracer.startActiveSpan(
217
+ name,
218
+ {
219
+ attributes: currentAttrs,
220
+ },
221
+ async (span: Span) => {
222
+ try {
223
+ const res = await originalMethod.call(this, ...args);
224
+ const extraAttrs = extraAttributes?.call(this, res);
225
+ span.setAttributes(extraAttrs ?? {});
226
+ span.setStatus({
227
+ code: SpanStatusCode.OK,
228
+ });
229
+ return res;
230
+ } catch (err) {
231
+ span.setStatus({
232
+ code: SpanStatusCode.ERROR,
233
+ message: String(err),
234
+ });
235
+
236
+ if (typeof err === 'string' || (err && err instanceof Error)) {
237
+ span.recordException(err);
238
+ }
239
+
240
+ throw err;
241
+ } finally {
242
+ span.end();
243
+ }
244
+ },
245
+ );
225
246
  } as F;
226
247
  };
227
248
  }
@@ -265,41 +286,57 @@ export function wrapCallbackInSpan<F extends (...args: any[]) => any>(
265
286
  export function runInSpan<A extends any[], R>(
266
287
  tracer: Tracer | string,
267
288
  spanName: string,
268
- callback: (span: Span, ...args: A) => R,
269
- ): (...args: A) => R {
270
- return (...args: A): R => {
289
+ callback: (span: Span, ...args: A) => Promise<R>,
290
+ ): (...args: A) => Promise<R> {
291
+ return (...args: A): Promise<R> => {
271
292
  const actualTracer = typeof tracer === 'string' ? getTelemetryClient().getTracer(tracer) : tracer;
272
- return actualTracer.startActiveSpan(spanName, (span: Span): R => {
273
- let deferSpanEnd = false;
293
+ return actualTracer.startActiveSpan(spanName, async (span: Span): Promise<R> => {
274
294
  try {
275
- const res = callback(span, ...args);
276
- if (isPromise(res)) {
277
- deferSpanEnd = true;
278
- return res
279
- .catch(err => {
280
- span.setStatus({
281
- code: SpanStatusCode.ERROR,
282
- message: String(err),
283
- });
284
- throw err;
285
- })
286
- .finally(() => {
287
- span.end();
288
- }) as R;
289
- } else {
290
- return res;
291
- }
295
+ const res = await callback(span, ...args);
296
+ span.setStatus({
297
+ code: SpanStatusCode.OK,
298
+ });
299
+
300
+ return res;
292
301
  } catch (err) {
293
302
  span.setStatus({
294
303
  code: SpanStatusCode.ERROR,
295
304
  message: String(err),
296
305
  });
306
+ if (typeof err === 'string' || (err && err instanceof Error)) {
307
+ span.recordException(err);
308
+ }
297
309
  throw err;
298
310
  } finally {
299
- if (!deferSpanEnd) {
300
- span.end();
301
- }
311
+ span.end();
302
312
  }
303
313
  });
304
314
  };
305
315
  }
316
+
317
+ /**
318
+ * Execute a callback within a span immediately (for one-off traced calls).
319
+ * Unlike runInSpan which returns a reusable function, this executes right away.
320
+ */
321
+ export function execInSpan<R>(
322
+ tracer: Tracer | string,
323
+ spanName: string,
324
+ callback: (span: Span) => Promise<R>,
325
+ ): Promise<R> {
326
+ const actualTracer = typeof tracer === 'string' ? getTelemetryClient().getTracer(tracer) : tracer;
327
+ return actualTracer.startActiveSpan(spanName, async (span: Span): Promise<R> => {
328
+ try {
329
+ const res = await callback(span);
330
+ span.setStatus({ code: SpanStatusCode.OK });
331
+ return res;
332
+ } catch (err) {
333
+ span.setStatus({ code: SpanStatusCode.ERROR, message: String(err) });
334
+ if (typeof err === 'string' || (err && err instanceof Error)) {
335
+ span.recordException(err);
336
+ }
337
+ throw err;
338
+ } finally {
339
+ span.end();
340
+ }
341
+ });
342
+ }
@@ -11,7 +11,10 @@ import { type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client'
11
11
  /** Extends an L2BlockStream with a tracer to create a new trace per iteration. */
12
12
  export class TraceableL2BlockStream extends L2BlockStream implements Traceable {
13
13
  constructor(
14
- l2BlockSource: Pick<L2BlockSource, 'getPublishedBlocks' | 'getBlockHeader' | 'getL2Tips'>,
14
+ l2BlockSource: Pick<
15
+ L2BlockSource,
16
+ 'getBlocks' | 'getBlockHeader' | 'getL2Tips' | 'getCheckpoints' | 'getCheckpointedBlocks'
17
+ >,
15
18
  localData: L2BlockStreamLocalDataProvider,
16
19
  handler: L2BlockStreamEventHandler,
17
20
  public readonly tracer: Tracer,