@aztec/telemetry-client 0.0.0-test.1 → 0.0.1-commit.017a351

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 (97) hide show
  1. package/dest/attributes.d.ts +45 -10
  2. package/dest/attributes.d.ts.map +1 -1
  3. package/dest/attributes.js +28 -9
  4. package/dest/bench.d.ts +6 -1
  5. package/dest/bench.d.ts.map +1 -1
  6. package/dest/bench.js +31 -14
  7. package/dest/config.d.ts +9 -2
  8. package/dest/config.d.ts.map +1 -1
  9. package/dest/config.js +44 -8
  10. package/dest/index.d.ts +2 -1
  11. package/dest/index.d.ts.map +1 -1
  12. package/dest/index.js +1 -0
  13. package/dest/l1_metrics.d.ts +17 -0
  14. package/dest/l1_metrics.d.ts.map +1 -0
  15. package/dest/l1_metrics.js +54 -0
  16. package/dest/lmdb_metrics.d.ts +5 -3
  17. package/dest/lmdb_metrics.d.ts.map +1 -1
  18. package/dest/lmdb_metrics.js +7 -15
  19. package/dest/metric-utils.d.ts +24 -0
  20. package/dest/metric-utils.d.ts.map +1 -0
  21. package/dest/metric-utils.js +59 -0
  22. package/dest/metrics.d.ts +312 -122
  23. package/dest/metrics.d.ts.map +1 -1
  24. package/dest/metrics.js +1595 -120
  25. package/dest/monitored_batch_span_processor.d.ts +29 -0
  26. package/dest/monitored_batch_span_processor.d.ts.map +1 -0
  27. package/dest/monitored_batch_span_processor.js +70 -0
  28. package/dest/nodejs_metrics_monitor.d.ts +19 -0
  29. package/dest/nodejs_metrics_monitor.d.ts.map +1 -0
  30. package/dest/nodejs_metrics_monitor.js +115 -0
  31. package/dest/noop.d.ts +9 -4
  32. package/dest/noop.d.ts.map +1 -1
  33. package/dest/noop.js +34 -1
  34. package/dest/otel.d.ts +13 -7
  35. package/dest/otel.d.ts.map +1 -1
  36. package/dest/otel.js +204 -24
  37. package/dest/otel_filter_metric_exporter.d.ts +12 -4
  38. package/dest/otel_filter_metric_exporter.d.ts.map +1 -1
  39. package/dest/otel_filter_metric_exporter.js +38 -4
  40. package/dest/otel_logger_provider.d.ts +1 -1
  41. package/dest/otel_propagation.d.ts +3 -1
  42. package/dest/otel_propagation.d.ts.map +1 -1
  43. package/dest/otel_propagation.js +49 -1
  44. package/dest/otel_resource.d.ts +1 -1
  45. package/dest/otel_resource.d.ts.map +1 -1
  46. package/dest/otel_resource.js +43 -2
  47. package/dest/prom_otel_adapter.d.ts +61 -12
  48. package/dest/prom_otel_adapter.d.ts.map +1 -1
  49. package/dest/prom_otel_adapter.js +157 -48
  50. package/dest/start.d.ts +3 -2
  51. package/dest/start.d.ts.map +1 -1
  52. package/dest/start.js +8 -7
  53. package/dest/telemetry.d.ts +63 -34
  54. package/dest/telemetry.d.ts.map +1 -1
  55. package/dest/telemetry.js +47 -24
  56. package/dest/vendor/attributes.d.ts +1 -1
  57. package/dest/vendor/otel-pino-stream.d.ts +1 -2
  58. package/dest/vendor/otel-pino-stream.d.ts.map +1 -1
  59. package/dest/vendor/otel-pino-stream.js +2 -2
  60. package/dest/with_tracer.d.ts +1 -1
  61. package/dest/with_tracer.d.ts.map +1 -1
  62. package/dest/wrappers/fetch.d.ts +3 -3
  63. package/dest/wrappers/fetch.d.ts.map +1 -1
  64. package/dest/wrappers/fetch.js +9 -6
  65. package/dest/wrappers/index.d.ts +1 -1
  66. package/dest/wrappers/json_rpc_server.d.ts +2 -2
  67. package/dest/wrappers/json_rpc_server.d.ts.map +1 -1
  68. package/dest/wrappers/l2_block_stream.d.ts +4 -3
  69. package/dest/wrappers/l2_block_stream.d.ts.map +1 -1
  70. package/dest/wrappers/l2_block_stream.js +385 -11
  71. package/package.json +21 -15
  72. package/src/attributes.ts +59 -12
  73. package/src/bench.ts +37 -15
  74. package/src/config.ts +76 -9
  75. package/src/index.ts +1 -0
  76. package/src/l1_metrics.ts +65 -0
  77. package/src/lmdb_metrics.ts +24 -24
  78. package/src/metric-utils.ts +75 -0
  79. package/src/metrics.ts +1679 -145
  80. package/src/monitored_batch_span_processor.ts +93 -0
  81. package/src/nodejs_metrics_monitor.ts +135 -0
  82. package/src/noop.ts +65 -4
  83. package/src/otel.ts +193 -28
  84. package/src/otel_filter_metric_exporter.ts +47 -5
  85. package/src/otel_propagation.ts +42 -1
  86. package/src/otel_resource.ts +57 -2
  87. package/src/prom_otel_adapter.ts +195 -70
  88. package/src/start.ts +17 -8
  89. package/src/telemetry.ts +152 -76
  90. package/src/vendor/otel-pino-stream.ts +1 -4
  91. package/src/wrappers/fetch.ts +32 -33
  92. package/src/wrappers/json_rpc_server.ts +1 -1
  93. package/src/wrappers/l2_block_stream.ts +3 -2
  94. package/dest/event_loop_monitor.d.ts +0 -18
  95. package/dest/event_loop_monitor.d.ts.map +0 -1
  96. package/dest/event_loop_monitor.js +0 -93
  97. package/src/event_loop_monitor.ts +0 -119
package/dest/otel.js CHANGED
@@ -1,38 +1,80 @@
1
1
  import { addLogDataHandler } from '@aztec/foundation/log';
2
- import { DiagConsoleLogger, DiagLogLevel, context, diag, isSpanContextValid, trace } from '@opentelemetry/api';
2
+ import { DiagConsoleLogger, DiagLogLevel, ROOT_CONTEXT, context, diag, isSpanContextValid, propagation, trace } from '@opentelemetry/api';
3
+ import { W3CTraceContextPropagator } from '@opentelemetry/core';
3
4
  import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
4
5
  import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
5
6
  import { HostMetrics } from '@opentelemetry/host-metrics';
6
7
  import { ExplicitBucketHistogramAggregation, InstrumentType, MeterProvider, PeriodicExportingMetricReader, View } from '@opentelemetry/sdk-metrics';
7
- import { BatchSpanProcessor, NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
8
+ import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
8
9
  import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
9
- import { EventLoopMonitor } from './event_loop_monitor.js';
10
- import { OtelFilterMetricExporter } from './otel_filter_metric_exporter.js';
10
+ import { toMetricOptions } from './metric-utils.js';
11
+ import { MonitoredBatchSpanProcessor } from './monitored_batch_span_processor.js';
12
+ import { NodejsMetricsMonitor } from './nodejs_metrics_monitor.js';
13
+ import { OtelFilterMetricExporter, PublicOtelFilterMetricExporter } from './otel_filter_metric_exporter.js';
11
14
  import { registerOtelLoggerProvider } from './otel_logger_provider.js';
12
15
  import { getOtelResource } from './otel_resource.js';
16
+ /** Wraps an OpenTelemetry Meter to implement our custom Meter interface */ class WrappedMeter {
17
+ otelMeter;
18
+ constructor(otelMeter){
19
+ this.otelMeter = otelMeter;
20
+ }
21
+ createGauge(metric) {
22
+ return this.otelMeter.createGauge(metric.name, toMetricOptions(metric));
23
+ }
24
+ createObservableGauge(metric) {
25
+ return this.otelMeter.createObservableGauge(metric.name, toMetricOptions(metric));
26
+ }
27
+ createHistogram(metric, extraOptions) {
28
+ return this.otelMeter.createHistogram(metric.name, {
29
+ ...toMetricOptions(metric),
30
+ ...extraOptions
31
+ });
32
+ }
33
+ createUpDownCounter(metric) {
34
+ return this.otelMeter.createUpDownCounter(metric.name, toMetricOptions(metric));
35
+ }
36
+ createObservableUpDownCounter(metric) {
37
+ return this.otelMeter.createObservableUpDownCounter(metric.name, toMetricOptions(metric));
38
+ }
39
+ addBatchObservableCallback(callback, observables) {
40
+ this.otelMeter.addBatchObservableCallback(callback, observables);
41
+ }
42
+ removeBatchObservableCallback(callback, observables) {
43
+ this.otelMeter.removeBatchObservableCallback(callback, observables);
44
+ }
45
+ }
13
46
  export class OpenTelemetryClient {
14
47
  resource;
15
48
  meterProvider;
16
49
  traceProvider;
17
50
  loggerProvider;
51
+ publicMetricExporter;
18
52
  log;
19
53
  hostMetrics;
20
- eventLoopMonitor;
54
+ nodejsMetricsMonitor;
21
55
  meters;
22
56
  tracers;
23
- constructor(resource, meterProvider, traceProvider, loggerProvider, log){
57
+ constructor(resource, meterProvider, traceProvider, loggerProvider, publicMetricExporter, log){
24
58
  this.resource = resource;
25
59
  this.meterProvider = meterProvider;
26
60
  this.traceProvider = traceProvider;
27
61
  this.loggerProvider = loggerProvider;
62
+ this.publicMetricExporter = publicMetricExporter;
28
63
  this.log = log;
29
64
  this.meters = new Map();
30
65
  this.tracers = new Map();
31
66
  }
67
+ setExportedPublicTelemetry(metrics) {
68
+ this.publicMetricExporter?.setMetricPrefixes(metrics);
69
+ }
70
+ setPublicTelemetryCollectFrom(roles) {
71
+ this.publicMetricExporter?.setAllowedRoles(roles);
72
+ }
32
73
  getMeter(name) {
33
74
  let meter = this.meters.get(name);
34
75
  if (!meter) {
35
- meter = this.meterProvider.getMeter(name, this.resource.attributes[ATTR_SERVICE_VERSION]);
76
+ const otelMeter = this.meterProvider.getMeter(name, this.resource.attributes[ATTR_SERVICE_VERSION]);
77
+ meter = new WrappedMeter(otelMeter);
36
78
  this.meters.set(name, meter);
37
79
  }
38
80
  return meter;
@@ -63,9 +105,10 @@ export class OpenTelemetryClient {
63
105
  name: this.resource.attributes[ATTR_SERVICE_NAME],
64
106
  meterProvider: this.meterProvider
65
107
  });
66
- this.eventLoopMonitor = new EventLoopMonitor(this.meterProvider.getMeter(this.resource.attributes[ATTR_SERVICE_NAME]));
108
+ const nodejsMeter = new WrappedMeter(this.meterProvider.getMeter(this.resource.attributes[ATTR_SERVICE_NAME]));
109
+ this.nodejsMetricsMonitor = new NodejsMetricsMonitor(nodejsMeter);
67
110
  this.hostMetrics.start();
68
- this.eventLoopMonitor.start();
111
+ this.nodejsMetricsMonitor.start();
69
112
  }
70
113
  isEnabled() {
71
114
  return true;
@@ -78,7 +121,7 @@ export class OpenTelemetryClient {
78
121
  ]);
79
122
  }
80
123
  async stop() {
81
- this.eventLoopMonitor?.stop();
124
+ this.nodejsMetricsMonitor?.stop();
82
125
  const flushAndShutdown = async (provider)=>{
83
126
  if (!provider) {
84
127
  return;
@@ -92,14 +135,58 @@ export class OpenTelemetryClient {
92
135
  this.traceProvider instanceof NodeTracerProvider ? flushAndShutdown(this.traceProvider) : Promise.resolve()
93
136
  ]);
94
137
  }
95
- static createMeterProvider(resource, options) {
138
+ getTraceContext() {
139
+ const carrier = {};
140
+ propagation.inject(context.active(), carrier);
141
+ return carrier['traceparent'];
142
+ }
143
+ extractPropagatedContext(traceContext) {
144
+ const extractedContext = propagation.extract(ROOT_CONTEXT, {
145
+ traceparent: traceContext
146
+ });
147
+ return extractedContext;
148
+ }
149
+ static createMeterProvider(resource, exporters) {
96
150
  return new MeterProvider({
97
151
  resource,
98
- readers: options.exporter ? [
99
- new PeriodicExportingMetricReader(options)
100
- ] : [],
152
+ readers: exporters.map((options)=>new PeriodicExportingMetricReader(options)),
101
153
  views: [
102
154
  // Every histogram matching the selector (type + unit) gets these custom buckets assigned
155
+ new View({
156
+ instrumentType: InstrumentType.HISTOGRAM,
157
+ instrumentUnit: 'Mmana',
158
+ aggregation: new ExplicitBucketHistogramAggregation([
159
+ 0.1,
160
+ 0.5,
161
+ 1,
162
+ 2,
163
+ 4,
164
+ 8,
165
+ 10,
166
+ 25,
167
+ 50,
168
+ 100,
169
+ 500,
170
+ 1000,
171
+ 5000,
172
+ 10000
173
+ ], true)
174
+ }),
175
+ new View({
176
+ instrumentType: InstrumentType.HISTOGRAM,
177
+ instrumentUnit: 'tx',
178
+ aggregation: new ExplicitBucketHistogramAggregation(// TPS
179
+ [
180
+ 0.1 * 36,
181
+ 0.2 * 36,
182
+ 0.5 * 36,
183
+ 1 * 36,
184
+ 2 * 36,
185
+ 5 * 36,
186
+ 10 * 36,
187
+ 15 * 36
188
+ ].map(Math.ceil), true)
189
+ }),
103
190
  new View({
104
191
  instrumentType: InstrumentType.HISTOGRAM,
105
192
  instrumentUnit: 's',
@@ -283,6 +370,61 @@ export class OpenTelemetryClient {
283
370
  15_000_000,
284
371
  30_000_000
285
372
  ], true)
373
+ }),
374
+ // L1 gas prices in gwei: priority fees ~0.01-10, base fees ~1-500, spikes to 1000+
375
+ new View({
376
+ instrumentType: InstrumentType.HISTOGRAM,
377
+ instrumentUnit: 'gwei',
378
+ aggregation: new ExplicitBucketHistogramAggregation([
379
+ 0.1,
380
+ 0.5,
381
+ 1,
382
+ 2,
383
+ 5,
384
+ 10,
385
+ 20,
386
+ 50,
387
+ 100,
388
+ 200,
389
+ 500,
390
+ 1_000
391
+ ], true)
392
+ }),
393
+ // L1 gas consumption: tx gas 100k-30M, calldata/blob gas varies
394
+ new View({
395
+ instrumentType: InstrumentType.HISTOGRAM,
396
+ instrumentUnit: 'gas',
397
+ aggregation: new ExplicitBucketHistogramAggregation([
398
+ 10_000,
399
+ 50_000,
400
+ 100_000,
401
+ 250_000,
402
+ 500_000,
403
+ 1_000_000,
404
+ 2_000_000,
405
+ 5_000_000,
406
+ 10_000_000,
407
+ 15_000_000,
408
+ 30_000_000
409
+ ], true)
410
+ }),
411
+ // L1 tx total fee in ETH: typically 0.001 - 1 ETH
412
+ new View({
413
+ instrumentType: InstrumentType.HISTOGRAM,
414
+ instrumentUnit: 'eth',
415
+ aggregation: new ExplicitBucketHistogramAggregation([
416
+ 0.0001,
417
+ 0.0005,
418
+ 0.001,
419
+ 0.005,
420
+ 0.01,
421
+ 0.05,
422
+ 0.1,
423
+ 0.5,
424
+ 1,
425
+ 5,
426
+ 10
427
+ ], true)
286
428
  })
287
429
  ]
288
430
  });
@@ -292,21 +434,59 @@ export class OpenTelemetryClient {
292
434
  const tracerProvider = new NodeTracerProvider({
293
435
  resource,
294
436
  spanProcessors: config.tracesCollectorUrl ? [
295
- new BatchSpanProcessor(new OTLPTraceExporter({
437
+ new MonitoredBatchSpanProcessor(new OTLPTraceExporter({
296
438
  url: config.tracesCollectorUrl.href
297
- }))
439
+ }), log, {
440
+ maxQueueSize: config.otelBspMaxQueueSize,
441
+ minTraceDurationMs: config.otelMinTraceDurationMs
442
+ })
298
443
  ] : []
299
444
  });
300
- tracerProvider.register();
301
- const meterProvider = OpenTelemetryClient.createMeterProvider(resource, {
302
- exporter: config.metricsCollectorUrl ? new OtelFilterMetricExporter(new OTLPMetricExporter({
303
- url: config.metricsCollectorUrl.href
304
- }), config.otelExcludeMetrics ?? []) : undefined,
305
- exportTimeoutMillis: config.otelExportTimeoutMs,
306
- exportIntervalMillis: config.otelCollectIntervalMs
445
+ tracerProvider.register({
446
+ propagator: new W3CTraceContextPropagator()
307
447
  });
448
+ const exporters = [];
449
+ if (config.metricsCollectorUrl) {
450
+ // Default to a blacklist that is empty (allow all metrics)
451
+ let filter = [];
452
+ let mode = 'deny';
453
+ if (config.otelExcludeMetrics.length > 0) {
454
+ // Implement a blacklist as specified in config
455
+ log.info(`Excluding metrics from export: ${config.otelExcludeMetrics}`);
456
+ filter = config.otelExcludeMetrics;
457
+ mode = 'deny';
458
+ } else if (config.otelIncludeMetrics.length > 0) {
459
+ // Implement a whitelist as specified in config
460
+ log.info(`Including only specified metrics for export: ${config.otelIncludeMetrics}`);
461
+ filter = config.otelIncludeMetrics;
462
+ mode = 'allow';
463
+ }
464
+ exporters.push({
465
+ exporter: new OtelFilterMetricExporter(new OTLPMetricExporter({
466
+ url: config.metricsCollectorUrl.href
467
+ }), filter, mode),
468
+ exportTimeoutMillis: config.otelExportTimeoutMs,
469
+ exportIntervalMillis: config.otelCollectIntervalMs
470
+ });
471
+ }
472
+ let publicExporter;
473
+ if (config.publicMetricsCollectorUrl && !config.publicMetricsOptOut) {
474
+ log.info(`Exporting public metrics: ${config.publicIncludeMetrics}`, {
475
+ publicMetrics: config.publicIncludeMetrics,
476
+ collectorUrl: config.publicMetricsCollectorUrl
477
+ });
478
+ publicExporter = new PublicOtelFilterMetricExporter(config.publicMetricsCollectFrom, new OTLPMetricExporter({
479
+ url: config.publicMetricsCollectorUrl.href
480
+ }), config.publicIncludeMetrics);
481
+ exporters.push({
482
+ exporter: publicExporter,
483
+ exportTimeoutMillis: config.otelExportTimeoutMs,
484
+ exportIntervalMillis: config.otelCollectIntervalMs
485
+ });
486
+ }
487
+ const meterProvider = OpenTelemetryClient.createMeterProvider(resource, exporters);
308
488
  const loggerProvider = registerOtelLoggerProvider(resource, config.logsCollectorUrl);
309
- return new OpenTelemetryClient(resource, meterProvider, tracerProvider, loggerProvider, log);
489
+ return new OpenTelemetryClient(resource, meterProvider, tracerProvider, loggerProvider, publicExporter, log);
310
490
  };
311
491
  }
312
492
  static createAndStart(config, log) {
@@ -1,12 +1,20 @@
1
- import type { ExportResult } from '@opentelemetry/core';
1
+ import { type ExportResult } from '@opentelemetry/core';
2
2
  import type { PushMetricExporter, ResourceMetrics } from '@opentelemetry/sdk-metrics';
3
3
  export declare class OtelFilterMetricExporter implements PushMetricExporter {
4
4
  private readonly exporter;
5
- private readonly excludeMetricPrefixes;
6
- constructor(exporter: PushMetricExporter, excludeMetricPrefixes: string[]);
5
+ private metricPrefix;
6
+ private readonly filter;
7
+ constructor(exporter: PushMetricExporter, metricPrefix: string[], filter?: 'allow' | 'deny');
7
8
  export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void;
8
9
  private filterMetrics;
9
10
  forceFlush(): Promise<void>;
10
11
  shutdown(): Promise<void>;
12
+ setMetricPrefixes(metrics: string[]): void;
11
13
  }
12
- //# sourceMappingURL=otel_filter_metric_exporter.d.ts.map
14
+ export declare class PublicOtelFilterMetricExporter extends OtelFilterMetricExporter {
15
+ private allowedRoles;
16
+ constructor(allowedRoles: string[], exporter: PushMetricExporter, metricPrefix: string[]);
17
+ export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void;
18
+ setAllowedRoles(roles: string[]): void;
19
+ }
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3RlbF9maWx0ZXJfbWV0cmljX2V4cG9ydGVyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvb3RlbF9maWx0ZXJfbWV0cmljX2V4cG9ydGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLFlBQVksRUFBb0IsTUFBTSxxQkFBcUIsQ0FBQztBQUMxRSxPQUFPLEtBQUssRUFBYyxrQkFBa0IsRUFBRSxlQUFlLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUlsRyxxQkFBYSx3QkFBeUIsWUFBVyxrQkFBa0I7SUFFL0QsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRO0lBQ3pCLE9BQU8sQ0FBQyxZQUFZO0lBQ3BCLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTTtJQUh6QixZQUNtQixRQUFRLEVBQUUsa0JBQWtCLEVBQ3JDLFlBQVksRUFBRSxNQUFNLEVBQUUsRUFDYixNQUFNLEdBQUUsT0FBTyxHQUFHLE1BQWUsRUFRbkQ7SUFFTSxNQUFNLENBQUMsT0FBTyxFQUFFLGVBQWUsRUFBRSxjQUFjLEVBQUUsQ0FBQyxNQUFNLEVBQUUsWUFBWSxLQUFLLElBQUksR0FBRyxJQUFJLENBUzVGO0lBRUQsT0FBTyxDQUFDLGFBQWE7SUFjZCxVQUFVLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUVqQztJQUVNLFFBQVEsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBRS9CO0lBRU0saUJBQWlCLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxRQUV6QztDQUNGO0FBRUQscUJBQWEsOEJBQStCLFNBQVEsd0JBQXdCO0lBRXhFLE9BQU8sQ0FBQyxZQUFZO0lBRHRCLFlBQ1UsWUFBWSxFQUFFLE1BQU0sRUFBRSxFQUM5QixRQUFRLEVBQUUsa0JBQWtCLEVBQzVCLFlBQVksRUFBRSxNQUFNLEVBQUUsRUFHdkI7SUFFZSxNQUFNLENBQUMsT0FBTyxFQUFFLGVBQWUsRUFBRSxjQUFjLEVBQUUsQ0FBQyxNQUFNLEVBQUUsWUFBWSxLQUFLLElBQUksR0FBRyxJQUFJLENBUXJHO0lBRU0sZUFBZSxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsUUFFckM7Q0FDRiJ9
@@ -1 +1 @@
1
- {"version":3,"file":"otel_filter_metric_exporter.d.ts","sourceRoot":"","sources":["../src/otel_filter_metric_exporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAc,kBAAkB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElG,qBAAa,wBAAyB,YAAW,kBAAkB;IACrD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAAsB,OAAO,CAAC,QAAQ,CAAC,qBAAqB;gBAApE,QAAQ,EAAE,kBAAkB,EAAmB,qBAAqB,EAAE,MAAM,EAAE;IASpG,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAW7F,OAAO,CAAC,aAAa;IAMd,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGjC"}
1
+ {"version":3,"file":"otel_filter_metric_exporter.d.ts","sourceRoot":"","sources":["../src/otel_filter_metric_exporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,KAAK,EAAc,kBAAkB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAIlG,qBAAa,wBAAyB,YAAW,kBAAkB;IAE/D,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHzB,YACmB,QAAQ,EAAE,kBAAkB,EACrC,YAAY,EAAE,MAAM,EAAE,EACb,MAAM,GAAE,OAAO,GAAG,MAAe,EAQnD;IAEM,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI,CAS5F;IAED,OAAO,CAAC,aAAa;IAcd,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjC;IAEM,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/B;IAEM,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,QAEzC;CACF;AAED,qBAAa,8BAA+B,SAAQ,wBAAwB;IAExE,OAAO,CAAC,YAAY;IADtB,YACU,YAAY,EAAE,MAAM,EAAE,EAC9B,QAAQ,EAAE,kBAAkB,EAC5B,YAAY,EAAE,MAAM,EAAE,EAGvB;IAEe,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI,CAQrG;IAEM,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,QAErC;CACF"}
@@ -1,9 +1,13 @@
1
+ import { ExportResultCode } from '@opentelemetry/core';
2
+ import { AZTEC_NODE_ROLE } from './attributes.js';
1
3
  export class OtelFilterMetricExporter {
2
4
  exporter;
3
- excludeMetricPrefixes;
4
- constructor(exporter, excludeMetricPrefixes){
5
+ metricPrefix;
6
+ filter;
7
+ constructor(exporter, metricPrefix, filter = 'deny'){
5
8
  this.exporter = exporter;
6
- this.excludeMetricPrefixes = excludeMetricPrefixes;
9
+ this.metricPrefix = metricPrefix;
10
+ this.filter = filter;
7
11
  if (exporter.selectAggregation) {
8
12
  this.selectAggregation = exporter.selectAggregation.bind(exporter);
9
13
  }
@@ -22,7 +26,15 @@ export class OtelFilterMetricExporter {
22
26
  this.exporter.export(filteredMetrics, resultCallback);
23
27
  }
24
28
  filterMetrics(metrics) {
25
- return metrics.filter((metric)=>!this.excludeMetricPrefixes.some((prefix)=>metric.descriptor.name.startsWith(prefix)));
29
+ return metrics.filter((metric)=>{
30
+ const matched = this.metricPrefix.some((prefix)=>metric.descriptor.name.startsWith(prefix));
31
+ if (this.filter === 'deny') {
32
+ return !matched;
33
+ }
34
+ if (this.filter === 'allow') {
35
+ return matched;
36
+ }
37
+ });
26
38
  }
27
39
  forceFlush() {
28
40
  return this.exporter.forceFlush();
@@ -30,4 +42,26 @@ export class OtelFilterMetricExporter {
30
42
  shutdown() {
31
43
  return this.exporter.shutdown();
32
44
  }
45
+ setMetricPrefixes(metrics) {
46
+ this.metricPrefix = metrics;
47
+ }
48
+ }
49
+ export class PublicOtelFilterMetricExporter extends OtelFilterMetricExporter {
50
+ allowedRoles;
51
+ constructor(allowedRoles, exporter, metricPrefix){
52
+ super(exporter, metricPrefix, 'allow'), this.allowedRoles = allowedRoles;
53
+ }
54
+ export(metrics, resultCallback) {
55
+ const role = String(metrics.resource.attributes[AZTEC_NODE_ROLE] ?? '');
56
+ if (!role || !this.allowedRoles.includes(role)) {
57
+ // noop
58
+ return resultCallback({
59
+ code: ExportResultCode.SUCCESS
60
+ });
61
+ }
62
+ super.export(metrics, resultCallback);
63
+ }
64
+ setAllowedRoles(roles) {
65
+ this.allowedRoles = roles;
66
+ }
33
67
  }
@@ -1,4 +1,4 @@
1
1
  import type { IResource } from '@opentelemetry/resources';
2
2
  import { LoggerProvider } from '@opentelemetry/sdk-logs';
3
3
  export declare function registerOtelLoggerProvider(resource: IResource, otelLogsUrl?: URL): LoggerProvider;
4
- //# sourceMappingURL=otel_logger_provider.d.ts.map
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3RlbF9sb2dnZXJfcHJvdmlkZXIuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9vdGVsX2xvZ2dlcl9wcm92aWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMxRCxPQUFPLEVBQTJCLGNBQWMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRWxGLHdCQUFnQiwwQkFBMEIsQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLFdBQVcsQ0FBQyxFQUFFLEdBQUcsa0JBd0JoRiJ9
@@ -1,3 +1,5 @@
1
+ import type { DiagnosticsMiddleware } from '@aztec/foundation/json-rpc/server';
1
2
  import type Koa from 'koa';
2
3
  export declare function getOtelJsonRpcPropagationMiddleware(scope?: string): (ctx: Koa.Context, next: () => Promise<void>) => Promise<void>;
3
- //# sourceMappingURL=otel_propagation.d.ts.map
4
+ export declare function getOtelJsonRpcDiagnosticsMiddleware(): DiagnosticsMiddleware;
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3RlbF9wcm9wYWdhdGlvbi5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL290ZWxfcHJvcGFnYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUcvRSxPQUFPLEtBQUssR0FBRyxNQUFNLEtBQUssQ0FBQztBQVUzQix3QkFBZ0IsbUNBQW1DLENBQ2pELEtBQUssU0FBa0IsR0FDdEIsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssT0FBTyxDQUFDLElBQUksQ0FBQyxDQW9DaEU7QUFFRCx3QkFBZ0IsbUNBQW1DLElBQUkscUJBQXFCLENBNEIzRSJ9
@@ -1 +1 @@
1
- {"version":3,"file":"otel_propagation.d.ts","sourceRoot":"","sources":["../src/otel_propagation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAU3B,wBAAgB,mCAAmC,CACjD,KAAK,SAAkB,GACtB,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAoChE"}
1
+ {"version":3,"file":"otel_propagation.d.ts","sourceRoot":"","sources":["../src/otel_propagation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAG/E,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAU3B,wBAAgB,mCAAmC,CACjD,KAAK,SAAkB,GACtB,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAoChE;AAED,wBAAgB,mCAAmC,IAAI,qBAAqB,CA4B3E"}
@@ -6,7 +6,7 @@ export function getOtelJsonRpcPropagationMiddleware(scope = 'JsonRpcServer') {
6
6
  const tracer = getTelemetryClient().getTracer(scope);
7
7
  const context = propagation.extract(ROOT_CONTEXT, ctx.request.headers);
8
8
  const method = ctx.request.body?.method;
9
- return tracer.startActiveSpan(`JsonRpcServer.${method ?? 'unknown'}`, {
9
+ return tracer.startActiveSpan(`JsonRpcServer.${method ?? 'batch'}`, {
10
10
  kind: SpanKind.SERVER
11
11
  }, context, async (span)=>{
12
12
  if (ctx.id) {
@@ -42,3 +42,51 @@ export function getOtelJsonRpcPropagationMiddleware(scope = 'JsonRpcServer') {
42
42
  });
43
43
  };
44
44
  }
45
+ export function getOtelJsonRpcDiagnosticsMiddleware() {
46
+ return function otelJsonRpcDiagnostics(ctx, next) {
47
+ const [namespace, method] = splitNamespace(ctx.method);
48
+ const scope = namespace ?? 'UnknownHandler';
49
+ const tracer = getTelemetryClient().getTracer(scope);
50
+ return tracer.startActiveSpan(`${scope}.${method}`, {
51
+ kind: SpanKind.INTERNAL,
52
+ attributes: {
53
+ [ATTR_JSONRPC_METHOD]: ctx.method
54
+ }
55
+ }, async (span)=>{
56
+ if (ctx.id !== null) {
57
+ span.setAttribute(ATTR_JSONRPC_REQUEST_ID, ctx.id);
58
+ }
59
+ try {
60
+ await next();
61
+ span.setStatus({
62
+ code: SpanStatusCode.OK
63
+ });
64
+ } catch (err) {
65
+ span.setStatus({
66
+ code: SpanStatusCode.ERROR,
67
+ message: err instanceof Error ? err.message : String(err)
68
+ });
69
+ if (typeof err === 'string' || err instanceof Error) {
70
+ span.recordException(err);
71
+ }
72
+ throw err;
73
+ } finally{
74
+ span.end();
75
+ }
76
+ });
77
+ };
78
+ }
79
+ function splitNamespace(fullMethod) {
80
+ const idx = fullMethod.indexOf('_');
81
+ if (idx > -1) {
82
+ return [
83
+ fullMethod.slice(0, idx),
84
+ fullMethod.slice(idx + 1)
85
+ ];
86
+ } else {
87
+ return [
88
+ undefined,
89
+ fullMethod
90
+ ];
91
+ }
92
+ }
@@ -1,3 +1,3 @@
1
1
  import { type IResource } from '@opentelemetry/resources';
2
2
  export declare function getOtelResource(): IResource;
3
- //# sourceMappingURL=otel_resource.d.ts.map
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3RlbF9yZXNvdXJjZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL290ZWxfcmVzb3VyY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVMLEtBQUssU0FBUyxFQU1mLE1BQU0sMEJBQTBCLENBQUM7QUFxQmxDLHdCQUFnQixlQUFlLElBQUksU0FBUyxDQWUzQyJ9
@@ -1 +1 @@
1
- {"version":3,"file":"otel_resource.d.ts","sourceRoot":"","sources":["../src/otel_resource.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EAMf,MAAM,0BAA0B,CAAC;AAElC,wBAAgB,eAAe,IAAI,SAAS,CAM3C"}
1
+ {"version":3,"file":"otel_resource.d.ts","sourceRoot":"","sources":["../src/otel_resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EAMf,MAAM,0BAA0B,CAAC;AAqBlC,wBAAgB,eAAe,IAAI,SAAS,CAe3C"}
@@ -1,12 +1,53 @@
1
- import { detectResourcesSync, envDetectorSync, osDetectorSync, processDetectorSync, serviceInstanceIdDetectorSync } from '@opentelemetry/resources';
1
+ import { Resource, detectResourcesSync, envDetectorSync, osDetectorSync, serviceInstanceIdDetectorSync } from '@opentelemetry/resources';
2
+ import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
3
+ import { readFileSync } from 'fs';
4
+ import { dirname, resolve } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { AZTEC_NODE_ROLE, AZTEC_REGISTRY_ADDRESS, AZTEC_ROLLUP_ADDRESS, AZTEC_ROLLUP_VERSION } from './attributes.js';
7
+ /** Reads the Aztec client version from the release manifest. */ function getAztecVersion() {
8
+ try {
9
+ const releasePleasePath = resolve(dirname(fileURLToPath(import.meta.url)), '../../../.release-please-manifest.json');
10
+ return JSON.parse(readFileSync(releasePleasePath, 'utf-8'))['.'];
11
+ } catch {
12
+ return undefined;
13
+ }
14
+ }
2
15
  export function getOtelResource() {
3
16
  const resource = detectResourcesSync({
4
17
  detectors: [
18
+ aztecNetworkDetectorSync,
5
19
  osDetectorSync,
6
20
  envDetectorSync,
7
- processDetectorSync,
21
+ // this detector is disabled because:
22
+ // 1. our software runs in a docker container, a lot of the attributes detected would be identical across different machines (e.g. all run node v22, executing the same script, running PID 1, etc)
23
+ // 2. it catures process.argv which could contain sensitive values in plain text (e.g. validator private keys)
24
+ // processDetectorSync,
8
25
  serviceInstanceIdDetectorSync
9
26
  ]
10
27
  });
11
28
  return resource;
12
29
  }
30
+ const aztecNetworkDetectorSync = {
31
+ detect () {
32
+ let role;
33
+ if (process.argv.includes('--sequencer')) {
34
+ role = 'sequencer';
35
+ } else if (process.argv.includes('--prover-node')) {
36
+ role = 'prover-node';
37
+ } else if (process.argv.includes('--node')) {
38
+ role = 'node';
39
+ } else if (process.argv.includes('--p2p-bootstrap')) {
40
+ role = 'bootnode';
41
+ }
42
+ const aztecAttributes = {
43
+ // this gets overwritten by OTEL_RESOURCE_ATTRIBUTES (if set)
44
+ [ATTR_SERVICE_NAME]: role ? `aztec-${role}` : undefined,
45
+ [ATTR_SERVICE_VERSION]: getAztecVersion(),
46
+ [AZTEC_NODE_ROLE]: role,
47
+ [AZTEC_ROLLUP_VERSION]: process.env.ROLLUP_VERSION ?? 'canonical',
48
+ [AZTEC_ROLLUP_ADDRESS]: process.env.ROLLUP_CONTRACT_ADDRESS,
49
+ [AZTEC_REGISTRY_ADDRESS]: process.env.REGISTRY_CONTRACT_ADDRESS
50
+ };
51
+ return new Resource(aztecAttributes);
52
+ }
53
+ };
@@ -1,4 +1,4 @@
1
- import { type Logger } from '@aztec/foundation/log';
1
+ import { type Logger, type LoggerBindings } from '@aztec/foundation/log';
2
2
  import { Registry } from 'prom-client';
3
3
  import type { Meter, TelemetryClient } from './telemetry.js';
4
4
  /**
@@ -97,18 +97,67 @@ export declare class OtelGauge<Labels extends LabelsGeneric = NoLabels> implemen
97
97
  * Resets the gauge to initial state
98
98
  */
99
99
  reset(): void;
100
+ }
101
+ /**
102
+ * Implementation of a Histogram collector
103
+ */
104
+ export declare class OtelHistogram<Labels extends LabelsGeneric = NoLabels> implements IHistogram<Labels> {
105
+ private logger;
106
+ private labelNames;
107
+ private histogram;
108
+ constructor(logger: Logger, meter: Meter, name: string, help: string, buckets?: number[], labelNames?: Array<keyof Labels>);
109
+ /**
110
+ * Starts a timer and returns a function that when called will record the time elapsed
111
+ * @param labels - Optional labels for the observation
112
+ */
113
+ startTimer(labels?: Labels): () => void;
114
+ /**
115
+ * Observes a value
116
+ * @param value - Value to observe
117
+ */
118
+ observe(value: number): void;
119
+ /**
120
+ * Observes a value with labels
121
+ * @param labels - Labels object
122
+ * @param value - Value to observe
123
+ */
124
+ observe(labels: Labels, value: number): void;
125
+ reset(): void;
126
+ }
127
+ /**
128
+ * Implementation of an AvgMinMax collector
129
+ */
130
+ export declare class OtelAvgMinMax<Labels extends LabelsGeneric = NoLabels> implements IAvgMinMax<Labels> {
131
+ private logger;
132
+ private labelNames;
133
+ private gauges;
134
+ private currentValues;
135
+ private labeledValues;
136
+ constructor(logger: Logger, meter: Meter, name: string, help: string, labelNames?: Array<keyof Labels>);
100
137
  /**
101
- * Validates that provided labels match the expected schema
102
- * @param labels - Labels object to validate
103
- * @throws Error if invalid labels are provided
138
+ * Sets the values for calculating avg, min, max
139
+ * @param values - Array of values
104
140
  */
105
- private validateLabels;
141
+ set(values: number[]): void;
106
142
  /**
107
- * Safely parses label string back to object
108
- * @param labelStr - Stringified labels object
109
- * @returns Labels object or null if parsing fails
143
+ * Sets the values for calculating avg, min, max with labels
144
+ * @param labels - Labels object
145
+ * @param values - Array of values
110
146
  */
111
- private parseLabelsSafely;
147
+ set(labels: Labels, values: number[]): void;
148
+ /**
149
+ * Resets all stored values
150
+ */
151
+ reset(): void;
152
+ /**
153
+ * General function to observe an aggregation
154
+ * @param result - Observer result
155
+ * @param aggregateFn - Function that calculates the aggregation
156
+ */
157
+ private observeAggregation;
158
+ private observeAvg;
159
+ private observeMin;
160
+ private observeMax;
112
161
  }
113
162
  /**
114
163
  * Otel metrics Adapter
@@ -116,12 +165,12 @@ export declare class OtelGauge<Labels extends LabelsGeneric = NoLabels> implemen
116
165
  * Maps the PromClient based MetricsRegister from gossipsub and discv5 services to the Otel MetricsRegister
117
166
  */
118
167
  export declare class OtelMetricsAdapter extends Registry implements MetricsRegister {
119
- private logger;
120
168
  private readonly meter;
121
- constructor(telemetryClient: TelemetryClient, logger?: Logger);
169
+ private logger;
170
+ constructor(telemetryClient: TelemetryClient, bindings?: LoggerBindings);
122
171
  gauge<Labels extends LabelsGeneric = NoLabels>(configuration: GaugeConfig<Labels>): IGauge<Labels>;
123
172
  histogram<Labels extends LabelsGeneric = NoLabels>(configuration: HistogramConfig<Labels>): IHistogram<Labels>;
124
173
  avgMinMax<Labels extends LabelsGeneric = NoLabels>(configuration: AvgMinMaxConfig<Labels>): IAvgMinMax<Labels>;
125
174
  }
126
175
  export {};
127
- //# sourceMappingURL=prom_otel_adapter.d.ts.map
176
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvbV9vdGVsX2FkYXB0ZXIuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9wcm9tX290ZWxfYWRhcHRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQUUsS0FBSyxjQUFjLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFHdkYsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUd2QyxPQUFPLEtBQUssRUFBYSxLQUFLLEVBQW1CLGVBQWUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXpGOztHQUVHO0FBQ0gsS0FBSyxRQUFRLEdBQUcsTUFBTSxDQUFDO0FBQ3ZCLE1BQU0sTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDO0FBQ2hDLE1BQU0sTUFBTSxlQUFlLEdBQUcsR0FBRyxDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUMsQ0FBQztBQUV4RCxvQkFBWSxhQUFhO0lBQ3ZCLE9BQU8sWUFBWTtJQUNuQixPQUFPLFlBQVk7Q0FDcEI7QUFFRCxLQUFLLFFBQVEsR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxDQUFDO0FBQ3RDLEtBQUssYUFBYSxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsTUFBTSxHQUFHLE1BQU0sQ0FBQyxDQUFDO0FBQ3JELEtBQUssU0FBUyxDQUFDLE1BQU0sU0FBUyxhQUFhLElBQUksT0FBTyxDQUFDLE1BQU0sTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBQzdFLFVBQVUsU0FBUyxDQUFDLE1BQU0sU0FBUyxhQUFhO0lBQzlDLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUM7Q0FDaEM7QUFFRCxVQUFVLE1BQU0sQ0FBQyxNQUFNLFNBQVMsYUFBYSxHQUFHLFFBQVE7SUFDdEQsR0FBRyxFQUFFLFFBQVEsU0FBUyxNQUFNLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxNQUFNLEtBQUssSUFBSSxH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