@libp2p/simple-metrics 1.3.12 → 1.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +3 -3
- package/dist/src/index.d.ts +5 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +119 -96
- package/dist/src/index.js.map +1 -1
- package/dist/typedoc-urls.json +2 -0
- package/package.json +4 -4
- package/src/index.ts +162 -107
package/src/index.ts
CHANGED
|
@@ -27,13 +27,26 @@ import { serviceCapabilities } from '@libp2p/interface'
|
|
|
27
27
|
import { logger } from '@libp2p/logger'
|
|
28
28
|
import each from 'it-foreach'
|
|
29
29
|
import { TDigest } from 'tdigest'
|
|
30
|
-
import type { Startable, MultiaddrConnection, Stream, Connection, Metric, MetricGroup, StopTimer, Metrics, CalculatedMetricOptions, MetricOptions, Counter, CounterGroup, CalculateMetric, Histogram, HistogramOptions, HistogramGroup, Summary, SummaryOptions, SummaryGroup, CalculatedHistogramOptions, CalculatedSummaryOptions } from '@libp2p/interface'
|
|
30
|
+
import type { Startable, MultiaddrConnection, Stream, Connection, Metric, MetricGroup, StopTimer, Metrics, CalculatedMetricOptions, MetricOptions, Counter, CounterGroup, CalculateMetric, Histogram, HistogramOptions, HistogramGroup, Summary, SummaryOptions, SummaryGroup, CalculatedHistogramOptions, CalculatedSummaryOptions, ComponentLogger, Logger } from '@libp2p/interface'
|
|
31
31
|
import type { Duplex } from 'it-stream-types'
|
|
32
32
|
|
|
33
33
|
const log = logger('libp2p:simple-metrics')
|
|
34
34
|
|
|
35
|
-
class
|
|
36
|
-
|
|
35
|
+
class SimpleMetric implements Metric {
|
|
36
|
+
private value: number = 0
|
|
37
|
+
private readonly calculate?: CalculateMetric
|
|
38
|
+
|
|
39
|
+
constructor (opts?: CalculatedMetricOptions) {
|
|
40
|
+
this.calculate = opts?.calculate
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async collect (): Promise<number> {
|
|
44
|
+
if (this.calculate != null) {
|
|
45
|
+
return this.calculate()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return this.value
|
|
49
|
+
}
|
|
37
50
|
|
|
38
51
|
update (value: number): void {
|
|
39
52
|
this.value = value
|
|
@@ -60,8 +73,21 @@ class DefaultMetric implements Metric {
|
|
|
60
73
|
}
|
|
61
74
|
}
|
|
62
75
|
|
|
63
|
-
class
|
|
64
|
-
|
|
76
|
+
class SimpleGroupMetric implements MetricGroup {
|
|
77
|
+
private values: Record<string, number> = {}
|
|
78
|
+
private readonly calculate?: CalculateMetric<Record<string, number>>
|
|
79
|
+
|
|
80
|
+
constructor (opts?: CalculatedMetricOptions<Record<string, number>>) {
|
|
81
|
+
this.calculate = opts?.calculate
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async collect (): Promise<Record<string, number>> {
|
|
85
|
+
if (this.calculate != null) {
|
|
86
|
+
return this.calculate()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return this.values
|
|
90
|
+
}
|
|
65
91
|
|
|
66
92
|
update (values: Record<string, number>): void {
|
|
67
93
|
Object.entries(values).forEach(([key, value]) => {
|
|
@@ -100,19 +126,33 @@ class DefaultGroupMetric implements MetricGroup {
|
|
|
100
126
|
}
|
|
101
127
|
}
|
|
102
128
|
|
|
103
|
-
class
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
129
|
+
class SimpleHistogram implements Histogram {
|
|
130
|
+
private bucketValues = new Map<number, number>()
|
|
131
|
+
private countValue: number = 0
|
|
132
|
+
private sumValue: number = 0
|
|
133
|
+
private readonly calculate?: CalculateMetric
|
|
107
134
|
|
|
108
|
-
constructor (opts
|
|
135
|
+
constructor (opts?: CalculatedHistogramOptions) {
|
|
109
136
|
const buckets = [
|
|
110
|
-
...(opts
|
|
137
|
+
...(opts?.buckets ?? [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]),
|
|
111
138
|
Infinity
|
|
112
139
|
]
|
|
113
140
|
for (const bucket of buckets) {
|
|
114
141
|
this.bucketValues.set(bucket, 0)
|
|
115
142
|
}
|
|
143
|
+
this.calculate = opts?.calculate
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public async collect (): Promise<{ count: number, sum: number, buckets: Record<number, number> }> {
|
|
147
|
+
if (this.calculate != null) {
|
|
148
|
+
this.observe(await this.calculate())
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
count: this.countValue,
|
|
153
|
+
sum: this.sumValue,
|
|
154
|
+
buckets: { ...this.bucketValues }
|
|
155
|
+
}
|
|
116
156
|
}
|
|
117
157
|
|
|
118
158
|
observe (value: number): void {
|
|
@@ -143,17 +183,29 @@ class DefaultHistogram implements Histogram {
|
|
|
143
183
|
}
|
|
144
184
|
}
|
|
145
185
|
|
|
146
|
-
class
|
|
147
|
-
public histograms: Record<string,
|
|
186
|
+
class SimpleHistogramGroup implements HistogramGroup {
|
|
187
|
+
public histograms: Record<string, SimpleHistogram> = {}
|
|
188
|
+
private readonly calculate?: CalculateMetric
|
|
148
189
|
|
|
149
|
-
constructor (opts
|
|
190
|
+
constructor (opts?: CalculatedHistogramOptions) {
|
|
150
191
|
this.histograms = {}
|
|
192
|
+
this.calculate = opts?.calculate
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public async collect (): Promise<Record<string, { count: number, sum: number, buckets: Record<number, number> }>> {
|
|
196
|
+
const output: Record<string, { count: number, sum: number, buckets: Record<number, number> }> = {}
|
|
197
|
+
|
|
198
|
+
for (const [key, histogram] of Object.entries(this.histograms)) {
|
|
199
|
+
output[key] = await histogram.collect()
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return output
|
|
151
203
|
}
|
|
152
204
|
|
|
153
205
|
observe (values: Partial<Record<string, number>>): void {
|
|
154
206
|
for (const [key, value] of Object.entries(values) as Array<[string, number]>) {
|
|
155
207
|
if (this.histograms[key] === undefined) {
|
|
156
|
-
this.histograms[key] = new
|
|
208
|
+
this.histograms[key] = new SimpleHistogram()
|
|
157
209
|
}
|
|
158
210
|
|
|
159
211
|
this.histograms[key].observe(value)
|
|
@@ -175,16 +227,30 @@ class DefaultHistogramGroup implements HistogramGroup {
|
|
|
175
227
|
}
|
|
176
228
|
}
|
|
177
229
|
|
|
178
|
-
class
|
|
230
|
+
class SimpleSummary implements Summary {
|
|
179
231
|
public sumValue: number = 0
|
|
180
232
|
public countValue: number = 0
|
|
181
233
|
public percentiles: number[]
|
|
182
234
|
public tdigest = new TDigest(0.01)
|
|
183
235
|
private readonly compressCount: number
|
|
236
|
+
private readonly calculate?: CalculateMetric
|
|
184
237
|
|
|
185
|
-
constructor (opts
|
|
186
|
-
this.percentiles = opts
|
|
187
|
-
this.compressCount = opts
|
|
238
|
+
constructor (opts?: CalculatedSummaryOptions) {
|
|
239
|
+
this.percentiles = opts?.percentiles ?? [0.01, 0.05, 0.5, 0.9, 0.95, 0.99, 0.999]
|
|
240
|
+
this.compressCount = opts?.compressCount ?? 1000
|
|
241
|
+
this.calculate = opts?.calculate
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
public async collect (): Promise<{ count: number, sum: number, percentiles: Record<string, number> }> {
|
|
245
|
+
if (this.calculate != null) {
|
|
246
|
+
this.observe(await this.calculate())
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
count: this.countValue,
|
|
251
|
+
sum: this.sumValue,
|
|
252
|
+
percentiles: Object.fromEntries(this.percentiles.map(p => [p, this.tdigest.percentile(p)]))
|
|
253
|
+
}
|
|
188
254
|
}
|
|
189
255
|
|
|
190
256
|
observe (value: number): void {
|
|
@@ -213,19 +279,31 @@ class DefaultSummary implements Summary {
|
|
|
213
279
|
}
|
|
214
280
|
}
|
|
215
281
|
|
|
216
|
-
class
|
|
217
|
-
public summaries: Record<string,
|
|
218
|
-
private readonly opts
|
|
282
|
+
class SimpleSummaryGroup implements SummaryGroup {
|
|
283
|
+
public summaries: Record<string, SimpleSummary> = {}
|
|
284
|
+
private readonly opts?: CalculatedSummaryOptions
|
|
219
285
|
|
|
220
|
-
constructor (opts
|
|
286
|
+
constructor (opts?: CalculatedSummaryOptions) {
|
|
221
287
|
this.summaries = {}
|
|
222
288
|
this.opts = opts
|
|
223
289
|
}
|
|
224
290
|
|
|
291
|
+
public async collect (): Promise<Record<string, { count: number, sum: number, percentiles: Record<string, number> }>> {
|
|
292
|
+
return {
|
|
293
|
+
...Object.fromEntries(Object.entries(this.summaries).map(([key, summary]) => {
|
|
294
|
+
return [key, {
|
|
295
|
+
count: summary.countValue,
|
|
296
|
+
sum: summary.sumValue,
|
|
297
|
+
percentiles: Object.fromEntries(summary.percentiles.map(p => [p, summary.tdigest.percentile(p)]))
|
|
298
|
+
}]
|
|
299
|
+
}))
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
225
303
|
observe (values: Record<string, number>): void {
|
|
226
304
|
for (const [key, value] of Object.entries(values)) {
|
|
227
305
|
if (this.summaries[key] === undefined) {
|
|
228
|
-
this.summaries[key] = new
|
|
306
|
+
this.summaries[key] = new SimpleSummary(this.opts)
|
|
229
307
|
}
|
|
230
308
|
|
|
231
309
|
this.summaries[key].observe(value)
|
|
@@ -261,15 +339,21 @@ export interface SimpleMetricsInit {
|
|
|
261
339
|
onMetrics: OnMetrics
|
|
262
340
|
}
|
|
263
341
|
|
|
342
|
+
export interface SimpleMetricsComponents {
|
|
343
|
+
logger: ComponentLogger
|
|
344
|
+
}
|
|
345
|
+
|
|
264
346
|
class SimpleMetrics implements Metrics, Startable {
|
|
265
|
-
public metrics = new Map<string,
|
|
347
|
+
public metrics = new Map<string, SimpleMetric | SimpleGroupMetric | SimpleHistogram | SimpleHistogramGroup | SimpleSummary | SimpleSummaryGroup>()
|
|
266
348
|
private readonly transferStats: Map<string, number>
|
|
267
349
|
private started: boolean
|
|
268
350
|
private interval?: ReturnType<typeof setInterval>
|
|
269
351
|
private readonly intervalMs: number
|
|
270
352
|
private readonly onMetrics: OnMetrics
|
|
353
|
+
private readonly log: Logger
|
|
271
354
|
|
|
272
|
-
constructor (components:
|
|
355
|
+
constructor (components: SimpleMetricsComponents, init: SimpleMetricsInit) {
|
|
356
|
+
this.log = components.logger.forComponent('libp2p:simple-metrics')
|
|
273
357
|
this.started = false
|
|
274
358
|
|
|
275
359
|
this._emitMetrics = this._emitMetrics.bind(this)
|
|
@@ -301,6 +385,7 @@ class SimpleMetrics implements Metrics, Startable {
|
|
|
301
385
|
this.started = false
|
|
302
386
|
|
|
303
387
|
clearInterval(this.interval)
|
|
388
|
+
this.transferStats.clear()
|
|
304
389
|
}
|
|
305
390
|
|
|
306
391
|
private _emitMetrics (): void {
|
|
@@ -308,45 +393,7 @@ class SimpleMetrics implements Metrics, Startable {
|
|
|
308
393
|
const output: Record<string, any> = {}
|
|
309
394
|
|
|
310
395
|
for (const [name, metric] of this.metrics.entries()) {
|
|
311
|
-
|
|
312
|
-
output[name] = metric.value
|
|
313
|
-
} else if (metric instanceof DefaultGroupMetric) {
|
|
314
|
-
output[name] = metric.values
|
|
315
|
-
} else if (metric instanceof DefaultHistogram) {
|
|
316
|
-
output[name] = {
|
|
317
|
-
count: metric.countValue,
|
|
318
|
-
sum: metric.sumValue,
|
|
319
|
-
buckets: { ...metric.bucketValues }
|
|
320
|
-
}
|
|
321
|
-
} else if (metric instanceof DefaultHistogramGroup) {
|
|
322
|
-
output[name] = {
|
|
323
|
-
...Object.fromEntries(Object.entries(metric.histograms).map(([key, histogram]) => {
|
|
324
|
-
return [key, {
|
|
325
|
-
count: histogram.countValue,
|
|
326
|
-
sum: histogram.sumValue,
|
|
327
|
-
buckets: { ...histogram.bucketValues }
|
|
328
|
-
}]
|
|
329
|
-
}))
|
|
330
|
-
}
|
|
331
|
-
} else if (metric instanceof DefaultSummary) {
|
|
332
|
-
output[name] = {
|
|
333
|
-
count: metric.countValue,
|
|
334
|
-
sum: metric.sumValue,
|
|
335
|
-
percentiles: Object.fromEntries(metric.percentiles.map(p => [p, metric.tdigest.percentile(p)]))
|
|
336
|
-
}
|
|
337
|
-
} else if (metric instanceof DefaultSummaryGroup) {
|
|
338
|
-
output[name] = {
|
|
339
|
-
...Object.fromEntries(Object.entries(metric.summaries).map(([key, summary]) => {
|
|
340
|
-
return [key, {
|
|
341
|
-
count: summary.countValue,
|
|
342
|
-
sum: summary.sumValue,
|
|
343
|
-
percentiles: Object.fromEntries(summary.percentiles.map(p => [p, summary.tdigest.percentile(p)]))
|
|
344
|
-
}]
|
|
345
|
-
}))
|
|
346
|
-
}
|
|
347
|
-
} else {
|
|
348
|
-
output[name] = await metric()
|
|
349
|
-
}
|
|
396
|
+
output[name] = await metric.collect()
|
|
350
397
|
}
|
|
351
398
|
|
|
352
399
|
this.onMetrics(structuredClone(output))
|
|
@@ -407,13 +454,14 @@ class SimpleMetrics implements Metrics, Startable {
|
|
|
407
454
|
throw new Error('Metric name is required')
|
|
408
455
|
}
|
|
409
456
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
457
|
+
let metric = this.metrics.get(name)
|
|
458
|
+
|
|
459
|
+
if (metric != null) {
|
|
460
|
+
this.log('reuse existing metric', name)
|
|
461
|
+
return metric
|
|
414
462
|
}
|
|
415
463
|
|
|
416
|
-
|
|
464
|
+
metric = new SimpleMetric(opts)
|
|
417
465
|
this.metrics.set(name, metric)
|
|
418
466
|
|
|
419
467
|
return metric
|
|
@@ -426,13 +474,14 @@ class SimpleMetrics implements Metrics, Startable {
|
|
|
426
474
|
throw new Error('Metric name is required')
|
|
427
475
|
}
|
|
428
476
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
477
|
+
let metric = this.metrics.get(name)
|
|
478
|
+
|
|
479
|
+
if (metric != null) {
|
|
480
|
+
this.log('reuse existing metric', name)
|
|
481
|
+
return metric
|
|
433
482
|
}
|
|
434
483
|
|
|
435
|
-
|
|
484
|
+
metric = new SimpleGroupMetric(opts)
|
|
436
485
|
this.metrics.set(name, metric)
|
|
437
486
|
|
|
438
487
|
return metric
|
|
@@ -445,13 +494,14 @@ class SimpleMetrics implements Metrics, Startable {
|
|
|
445
494
|
throw new Error('Metric name is required')
|
|
446
495
|
}
|
|
447
496
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
497
|
+
let metric = this.metrics.get(name)
|
|
498
|
+
|
|
499
|
+
if (metric != null) {
|
|
500
|
+
this.log('reuse existing metric', name)
|
|
501
|
+
return metric
|
|
452
502
|
}
|
|
453
503
|
|
|
454
|
-
|
|
504
|
+
metric = new SimpleMetric(opts)
|
|
455
505
|
this.metrics.set(name, metric)
|
|
456
506
|
|
|
457
507
|
return metric
|
|
@@ -464,13 +514,14 @@ class SimpleMetrics implements Metrics, Startable {
|
|
|
464
514
|
throw new Error('Metric name is required')
|
|
465
515
|
}
|
|
466
516
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
517
|
+
let metric = this.metrics.get(name)
|
|
518
|
+
|
|
519
|
+
if (metric != null) {
|
|
520
|
+
this.log('reuse existing metric', name)
|
|
521
|
+
return metric
|
|
471
522
|
}
|
|
472
523
|
|
|
473
|
-
|
|
524
|
+
metric = new SimpleGroupMetric(opts)
|
|
474
525
|
this.metrics.set(name, metric)
|
|
475
526
|
|
|
476
527
|
return metric
|
|
@@ -483,13 +534,14 @@ class SimpleMetrics implements Metrics, Startable {
|
|
|
483
534
|
throw new Error('Metric name is required')
|
|
484
535
|
}
|
|
485
536
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
537
|
+
let metric = this.metrics.get(name)
|
|
538
|
+
|
|
539
|
+
if (metric != null) {
|
|
540
|
+
this.log('reuse existing metric', name)
|
|
541
|
+
return metric
|
|
490
542
|
}
|
|
491
543
|
|
|
492
|
-
|
|
544
|
+
metric = new SimpleHistogram(opts)
|
|
493
545
|
this.metrics.set(name, metric)
|
|
494
546
|
|
|
495
547
|
return metric
|
|
@@ -502,13 +554,14 @@ class SimpleMetrics implements Metrics, Startable {
|
|
|
502
554
|
throw new Error('Metric name is required')
|
|
503
555
|
}
|
|
504
556
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
557
|
+
let metric = this.metrics.get(name)
|
|
558
|
+
|
|
559
|
+
if (metric != null) {
|
|
560
|
+
this.log('reuse existing metric', name)
|
|
561
|
+
return metric
|
|
509
562
|
}
|
|
510
563
|
|
|
511
|
-
|
|
564
|
+
metric = new SimpleHistogramGroup(opts)
|
|
512
565
|
this.metrics.set(name, metric)
|
|
513
566
|
|
|
514
567
|
return metric
|
|
@@ -521,13 +574,14 @@ class SimpleMetrics implements Metrics, Startable {
|
|
|
521
574
|
throw new Error('Metric name is required')
|
|
522
575
|
}
|
|
523
576
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
577
|
+
let metric = this.metrics.get(name)
|
|
578
|
+
|
|
579
|
+
if (metric != null) {
|
|
580
|
+
this.log('reuse existing metric', name)
|
|
581
|
+
return metric
|
|
528
582
|
}
|
|
529
583
|
|
|
530
|
-
|
|
584
|
+
metric = new SimpleSummary(opts)
|
|
531
585
|
this.metrics.set(name, metric)
|
|
532
586
|
|
|
533
587
|
return metric
|
|
@@ -540,13 +594,14 @@ class SimpleMetrics implements Metrics, Startable {
|
|
|
540
594
|
throw new Error('Metric name is required')
|
|
541
595
|
}
|
|
542
596
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
597
|
+
let metric = this.metrics.get(name)
|
|
598
|
+
|
|
599
|
+
if (metric != null) {
|
|
600
|
+
this.log('reuse existing metric', name)
|
|
601
|
+
return metric
|
|
547
602
|
}
|
|
548
603
|
|
|
549
|
-
|
|
604
|
+
metric = new SimpleSummaryGroup(opts)
|
|
550
605
|
this.metrics.set(name, metric)
|
|
551
606
|
|
|
552
607
|
return metric
|
|
@@ -562,6 +617,6 @@ class SimpleMetrics implements Metrics, Startable {
|
|
|
562
617
|
}
|
|
563
618
|
}
|
|
564
619
|
|
|
565
|
-
export function simpleMetrics (init: SimpleMetricsInit): (components:
|
|
566
|
-
return (components
|
|
620
|
+
export function simpleMetrics (init: SimpleMetricsInit): (components: SimpleMetricsComponents) => Metrics {
|
|
621
|
+
return (components) => new SimpleMetrics(components, init)
|
|
567
622
|
}
|