@libp2p/opentelemetry-metrics 1.0.16 → 1.0.17

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/src/index.ts CHANGED
@@ -48,14 +48,15 @@ import { OpenTelemetryMetric } from './metric.js'
48
48
  import { OpenTelemetrySummaryGroup } from './summary-group.js'
49
49
  import { OpenTelemetrySummary } from './summary.js'
50
50
  import { collectSystemMetrics } from './system-metrics.js'
51
- import type { MultiaddrConnection, Stream, Connection, Metric, MetricGroup, Metrics, CalculatedMetricOptions, MetricOptions, Counter, CounterGroup, Histogram, HistogramOptions, HistogramGroup, Summary, SummaryOptions, SummaryGroup, CalculatedHistogramOptions, CalculatedSummaryOptions, NodeInfo, TraceFunctionOptions, TraceGeneratorFunctionOptions, TraceAttributes } from '@libp2p/interface'
52
- import type { Span, Attributes } from '@opentelemetry/api'
51
+ import type { MultiaddrConnection, Stream, Connection, Metric, MetricGroup, Metrics, CalculatedMetricOptions, MetricOptions, Counter, CounterGroup, Histogram, HistogramOptions, HistogramGroup, Summary, SummaryOptions, SummaryGroup, CalculatedHistogramOptions, CalculatedSummaryOptions, NodeInfo, TraceFunctionOptions, TraceGeneratorFunctionOptions, TraceAttributes, ComponentLogger, Logger } from '@libp2p/interface'
52
+ import type { Span, Attributes, Meter, Observable } from '@opentelemetry/api'
53
53
  import type { Duplex } from 'it-stream-types'
54
54
 
55
55
  // see https://betterstack.com/community/guides/observability/opentelemetry-metrics-nodejs/#prerequisites
56
56
 
57
57
  export interface OpenTelemetryComponents {
58
58
  nodeInfo: NodeInfo
59
+ logger: ComponentLogger
59
60
  }
60
61
 
61
62
  export interface OpenTelemetryMetricsInit {
@@ -92,14 +93,20 @@ export interface OpenTelemetryMetricsInit {
92
93
  class OpenTelemetryMetrics implements Metrics {
93
94
  private transferStats: Map<string, number>
94
95
  private readonly tracer: ReturnType<typeof trace.getTracer>
95
- private readonly meterName: string
96
+ private readonly meter: Meter
97
+ private readonly log: Logger
98
+ private metrics: Map<string, OpenTelemetryMetric | OpenTelemetryMetricGroup | OpenTelemetryCounter | OpenTelemetryCounterGroup | OpenTelemetryHistogram | OpenTelemetryHistogramGroup | OpenTelemetrySummary | OpenTelemetrySummaryGroup>
99
+ private observables: Map<string, Observable>
96
100
 
97
101
  constructor (components: OpenTelemetryComponents, init?: OpenTelemetryMetricsInit) {
102
+ this.log = components.logger.forComponent('libp2p:open-telemetry-metrics')
98
103
  this.tracer = trace.getTracer(init?.appName ?? components.nodeInfo.name, init?.appVersion ?? components.nodeInfo.version)
104
+ this.metrics = new Map()
105
+ this.observables = new Map()
99
106
 
100
107
  // holds global and per-protocol sent/received stats
101
108
  this.transferStats = new Map()
102
- this.meterName = init?.meterName ?? components.nodeInfo.name
109
+ this.meter = metrics.getMeterProvider().getMeter(init?.meterName ?? components.nodeInfo.name)
103
110
 
104
111
  this.registerCounterGroup('libp2p_data_transfer_bytes_total', {
105
112
  label: 'protocol',
@@ -111,7 +118,7 @@ class OpenTelemetryMetrics implements Metrics {
111
118
  }
112
119
 
113
120
  // reset counts for next time
114
- this.transferStats = new Map()
121
+ this.transferStats.clear()
115
122
 
116
123
  return output
117
124
  }
@@ -126,6 +133,14 @@ class OpenTelemetryMetrics implements Metrics {
126
133
  '@libp2p/metrics'
127
134
  ]
128
135
 
136
+ start (): void {
137
+
138
+ }
139
+
140
+ stop (): void {
141
+ this.transferStats.clear()
142
+ }
143
+
129
144
  /**
130
145
  * Increment the transfer stat for the passed key, making sure
131
146
  * it exists first
@@ -177,23 +192,38 @@ class OpenTelemetryMetrics implements Metrics {
177
192
  throw new InvalidParametersError('Metric name is required')
178
193
  }
179
194
 
180
- const meter = metrics.getMeterProvider().getMeter(this.meterName)
181
-
182
195
  if (isCalculatedMetricOptions<CalculatedMetricOptions>(opts)) {
183
- const calculate = opts.calculate
184
- const counter = meter.createObservableGauge(name, {
196
+ let gauge = this.observables.get(name)
197
+
198
+ if (gauge != null) {
199
+ return
200
+ }
201
+
202
+ gauge = this.meter.createObservableGauge(name, {
185
203
  description: opts?.help ?? name
186
204
  })
187
- counter.addCallback(async (result) => {
205
+
206
+ const calculate = opts.calculate
207
+ gauge.addCallback(async (result) => {
188
208
  result.observe(await calculate())
189
209
  })
190
210
 
211
+ this.observables.set(name, gauge)
212
+
191
213
  return
192
214
  }
193
215
 
194
- return new OpenTelemetryMetric(meter.createGauge(name, {
195
- description: opts?.help ?? name
196
- }))
216
+ let metric = this.metrics.get(name)
217
+
218
+ if (metric == null) {
219
+ metric = new OpenTelemetryMetric(this.meter.createGauge(name, {
220
+ description: opts?.help ?? name
221
+ }))
222
+
223
+ this.metrics.set(name, metric)
224
+ }
225
+
226
+ return metric
197
227
  }
198
228
 
199
229
  registerMetricGroup (name: string, opts: CalculatedMetricOptions<Record<string, number>>): void
@@ -203,14 +233,20 @@ class OpenTelemetryMetrics implements Metrics {
203
233
  throw new InvalidParametersError('Metric name is required')
204
234
  }
205
235
 
206
- const meter = metrics.getMeterProvider().getMeter(this.meterName)
207
236
  const label = opts?.label ?? name
208
237
 
209
238
  if (isCalculatedMetricOptions<CalculatedMetricOptions<Record<string, number>>>(opts)) {
210
- const calculate = opts.calculate
211
- const gauge = meter.createObservableGauge(name, {
239
+ let gauge = this.observables.get(name)
240
+
241
+ if (gauge != null) {
242
+ return
243
+ }
244
+
245
+ gauge = this.meter.createObservableGauge(name, {
212
246
  description: opts?.help ?? name
213
247
  })
248
+
249
+ const calculate = opts.calculate
214
250
  gauge.addCallback(async (observable) => {
215
251
  const observed = await calculate()
216
252
 
@@ -221,12 +257,22 @@ class OpenTelemetryMetrics implements Metrics {
221
257
  }
222
258
  })
223
259
 
260
+ this.observables.set(name, gauge)
261
+
224
262
  return
225
263
  }
226
264
 
227
- return new OpenTelemetryMetricGroup(label, meter.createGauge(name, {
228
- description: opts?.help ?? name
229
- }))
265
+ let metric = this.metrics.get(name)
266
+
267
+ if (metric == null) {
268
+ metric = new OpenTelemetryMetricGroup(label, this.meter.createGauge(name, {
269
+ description: opts?.help ?? name
270
+ }))
271
+
272
+ this.metrics.set(name, metric)
273
+ }
274
+
275
+ return metric
230
276
  }
231
277
 
232
278
  registerCounter (name: string, opts: CalculatedMetricOptions): void
@@ -236,23 +282,38 @@ class OpenTelemetryMetrics implements Metrics {
236
282
  throw new InvalidParametersError('Metric name is required')
237
283
  }
238
284
 
239
- const meter = metrics.getMeterProvider().getMeter(this.meterName)
240
-
241
285
  if (isCalculatedMetricOptions<CalculatedMetricOptions>(opts)) {
242
- const calculate = opts.calculate
243
- const counter = meter.createObservableCounter(name, {
286
+ let counter = this.observables.get(name)
287
+
288
+ if (counter != null) {
289
+ return
290
+ }
291
+
292
+ counter = this.meter.createObservableCounter(name, {
244
293
  description: opts?.help ?? name
245
294
  })
295
+
296
+ const calculate = opts.calculate
246
297
  counter.addCallback(async (result) => {
247
298
  result.observe(await calculate())
248
299
  })
249
300
 
301
+ this.observables.set(name, counter)
302
+
250
303
  return
251
304
  }
252
305
 
253
- return new OpenTelemetryCounter(meter.createCounter(name, {
254
- description: opts?.help ?? name
255
- }))
306
+ let metric = this.metrics.get(name)
307
+
308
+ if (metric == null) {
309
+ metric = new OpenTelemetryCounter(this.meter.createCounter(name, {
310
+ description: opts?.help ?? name
311
+ }))
312
+
313
+ this.metrics.set(name, metric)
314
+ }
315
+
316
+ return metric
256
317
  }
257
318
 
258
319
  registerCounterGroup (name: string, opts: CalculatedMetricOptions<Record<string, number>>): void
@@ -262,15 +323,21 @@ class OpenTelemetryMetrics implements Metrics {
262
323
  throw new InvalidParametersError('Metric name is required')
263
324
  }
264
325
 
265
- const meter = metrics.getMeterProvider().getMeter(this.meterName)
266
326
  const label = opts?.label ?? name
267
327
 
268
328
  if (isCalculatedMetricOptions<CalculatedMetricOptions<Record<string, number>>>(opts)) {
269
- const values: Record<string, number> = {}
270
- const calculate = opts.calculate
271
- const counter = meter.createObservableGauge(name, {
329
+ let counter = this.observables.get(name)
330
+
331
+ if (counter != null) {
332
+ return
333
+ }
334
+
335
+ counter = this.meter.createObservableCounter(name, {
272
336
  description: opts?.help ?? name
273
337
  })
338
+
339
+ const values: Record<string, number> = {}
340
+ const calculate = opts.calculate
274
341
  counter.addCallback(async (observable) => {
275
342
  const observed = await calculate()
276
343
 
@@ -290,9 +357,17 @@ class OpenTelemetryMetrics implements Metrics {
290
357
  return
291
358
  }
292
359
 
293
- return new OpenTelemetryCounterGroup(label, meter.createCounter(name, {
294
- description: opts?.help ?? name
295
- }))
360
+ let metric = this.metrics.get(name)
361
+
362
+ if (metric == null) {
363
+ metric = new OpenTelemetryCounterGroup(label, this.meter.createCounter(name, {
364
+ description: opts?.help ?? name
365
+ }))
366
+
367
+ this.metrics.set(name, metric)
368
+ }
369
+
370
+ return metric
296
371
  }
297
372
 
298
373
  registerHistogram (name: string, opts: CalculatedHistogramOptions): void
@@ -302,18 +377,24 @@ class OpenTelemetryMetrics implements Metrics {
302
377
  throw new InvalidParametersError('Metric name is required')
303
378
  }
304
379
 
305
- const meter = metrics.getMeterProvider().getMeter(this.meterName)
306
-
307
380
  if (isCalculatedMetricOptions<CalculatedHistogramOptions>(opts)) {
308
381
  return
309
382
  }
310
383
 
311
- return new OpenTelemetryHistogram(meter.createHistogram(name, {
312
- advice: {
313
- explicitBucketBoundaries: opts.buckets
314
- },
315
- description: opts?.help ?? name
316
- }))
384
+ let metric = this.metrics.get(name)
385
+
386
+ if (metric == null) {
387
+ metric = new OpenTelemetryHistogram(this.meter.createHistogram(name, {
388
+ advice: {
389
+ explicitBucketBoundaries: opts.buckets
390
+ },
391
+ description: opts?.help ?? name
392
+ }))
393
+
394
+ this.metrics.set(name, metric)
395
+ }
396
+
397
+ return metric
317
398
  }
318
399
 
319
400
  registerHistogramGroup (name: string, opts: CalculatedHistogramOptions<Record<string, number>>): void
@@ -323,19 +404,26 @@ class OpenTelemetryMetrics implements Metrics {
323
404
  throw new InvalidParametersError('Metric name is required')
324
405
  }
325
406
 
326
- const meter = metrics.getMeterProvider().getMeter(this.meterName)
327
407
  const label = opts?.label ?? name
328
408
 
329
409
  if (isCalculatedMetricOptions<CalculatedHistogramOptions<Record<string, number>>>(opts)) {
330
410
  return
331
411
  }
332
412
 
333
- return new OpenTelemetryHistogramGroup(label, meter.createHistogram(name, {
334
- advice: {
335
- explicitBucketBoundaries: opts.buckets
336
- },
337
- description: opts?.help ?? name
338
- }))
413
+ let metric = this.metrics.get(name)
414
+
415
+ if (metric == null) {
416
+ metric = new OpenTelemetryHistogramGroup(label, this.meter.createHistogram(name, {
417
+ advice: {
418
+ explicitBucketBoundaries: opts.buckets
419
+ },
420
+ description: opts?.help ?? name
421
+ }))
422
+
423
+ this.metrics.set(name, metric)
424
+ }
425
+
426
+ return metric
339
427
  }
340
428
 
341
429
  registerSummary (name: string, opts: CalculatedSummaryOptions): void
@@ -345,15 +433,21 @@ class OpenTelemetryMetrics implements Metrics {
345
433
  throw new InvalidParametersError('Metric name is required')
346
434
  }
347
435
 
348
- const meter = metrics.getMeterProvider().getMeter(this.meterName)
349
-
350
436
  if (isCalculatedMetricOptions<CalculatedHistogramOptions>(opts)) {
351
437
  return
352
438
  }
353
439
 
354
- return new OpenTelemetrySummary(meter.createGauge(name, {
355
- description: opts?.help ?? name
356
- }))
440
+ let metric = this.metrics.get(name)
441
+
442
+ if (metric == null) {
443
+ metric = new OpenTelemetrySummary(this.meter.createGauge(name, {
444
+ description: opts?.help ?? name
445
+ }))
446
+
447
+ this.metrics.set(name, metric)
448
+ }
449
+
450
+ return metric
357
451
  }
358
452
 
359
453
  registerSummaryGroup (name: string, opts: CalculatedSummaryOptions<Record<string, number>>): void
@@ -363,16 +457,23 @@ class OpenTelemetryMetrics implements Metrics {
363
457
  throw new InvalidParametersError('Metric name is required')
364
458
  }
365
459
 
366
- const meter = metrics.getMeterProvider().getMeter(this.meterName)
367
460
  const label = opts?.label ?? name
368
461
 
369
462
  if (isCalculatedMetricOptions<CalculatedSummaryOptions>(opts)) {
370
463
  return
371
464
  }
372
465
 
373
- return new OpenTelemetrySummaryGroup(label, meter.createGauge(name, {
374
- description: opts?.help ?? name
375
- }))
466
+ let metric = this.metrics.get(name)
467
+
468
+ if (metric == null) {
469
+ metric = new OpenTelemetrySummaryGroup(label, this.meter.createGauge(name, {
470
+ description: opts?.help ?? name
471
+ }))
472
+
473
+ this.metrics.set(name, metric)
474
+ }
475
+
476
+ return metric
376
477
  }
377
478
 
378
479
  createTrace (): any {