@libp2p/prometheus-metrics 0.0.0 → 1.0.1
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/README.md +62 -1
- package/dist/src/counter-group.d.ts +9 -0
- package/dist/src/counter-group.d.ts.map +1 -0
- package/dist/src/counter-group.js +36 -0
- package/dist/src/counter-group.js.map +1 -0
- package/dist/src/counter.d.ts +8 -0
- package/dist/src/counter.d.ts.map +1 -0
- package/dist/src/counter.js +31 -0
- package/dist/src/counter.js.map +1 -0
- package/dist/src/index.d.ts +14 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +84 -57
- package/dist/src/index.js.map +1 -1
- package/dist/src/metric-group.d.ts +2 -2
- package/dist/src/metric-group.d.ts.map +1 -1
- package/dist/src/metric-group.js +14 -2
- package/dist/src/metric-group.js.map +1 -1
- package/dist/src/metric.d.ts +2 -2
- package/dist/src/metric.d.ts.map +1 -1
- package/dist/src/metric.js +12 -2
- package/dist/src/metric.js.map +1 -1
- package/dist/src/utils.d.ts +4 -0
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +7 -1
- package/dist/src/utils.js.map +1 -1
- package/package.json +12 -11
- package/src/counter-group.ts +47 -0
- package/src/counter.ts +40 -0
- package/src/index.ts +122 -69
- package/src/metric-group.ts +20 -5
- package/src/metric.ts +20 -7
- package/src/utils.ts +7 -1
- package/dist/src/moving-average.d.ts +0 -20
- package/dist/src/moving-average.d.ts.map +0 -1
- package/dist/src/moving-average.js +0 -40
- package/dist/src/moving-average.js.map +0 -1
package/README.md
CHANGED
|
@@ -5,11 +5,18 @@
|
|
|
5
5
|
[](https://codecov.io/gh/libp2p/js-libp2p-prometheus-metrics)
|
|
6
6
|
[](https://github.com/libp2p/js-libp2p-prometheus-metrics/actions/workflows/js-test-and-release.yml)
|
|
7
7
|
|
|
8
|
-
> Collect libp2p metrics for scraping by Prometheus
|
|
8
|
+
> Collect libp2p metrics for scraping by Prometheus or Graphana
|
|
9
9
|
|
|
10
10
|
## Table of contents <!-- omit in toc -->
|
|
11
11
|
|
|
12
12
|
- [Install](#install)
|
|
13
|
+
- [Usage](#usage)
|
|
14
|
+
- [Queries](#queries)
|
|
15
|
+
- [Data sent/received](#data-sentreceived)
|
|
16
|
+
- [CPU usage](#cpu-usage)
|
|
17
|
+
- [Memory usage](#memory-usage)
|
|
18
|
+
- [DHT query time](#dht-query-time)
|
|
19
|
+
- [TCP transport dialer errors](#tcp-transport-dialer-errors)
|
|
13
20
|
- [License](#license)
|
|
14
21
|
- [Contribute](#contribute)
|
|
15
22
|
|
|
@@ -19,6 +26,60 @@
|
|
|
19
26
|
$ npm i @libp2p/prometheus-metrics
|
|
20
27
|
```
|
|
21
28
|
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
Configure your libp2p node with Prometheus metrics:
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
import { createLibp2p } from 'libp2p'
|
|
35
|
+
import { prometheusMetrics } from '@libp2p/prometheus-metrics'
|
|
36
|
+
|
|
37
|
+
const node = await createLibp2p({
|
|
38
|
+
metrics: prometheusMetrics()
|
|
39
|
+
})
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then use the `prom-client` module to supply metrics to the Prometheus/Graphana client using your http framework:
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
import client from 'prom-client'
|
|
46
|
+
|
|
47
|
+
async handler (request, h) {
|
|
48
|
+
return h.response(await client.register.metrics())
|
|
49
|
+
.type(client.register.contentType)
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
All Prometheus metrics are global so there's no other work required to extract them.
|
|
54
|
+
|
|
55
|
+
### Queries
|
|
56
|
+
|
|
57
|
+
Some useful queries are:
|
|
58
|
+
|
|
59
|
+
#### Data sent/received
|
|
60
|
+
|
|
61
|
+
rate(libp2p_data_transfer_bytes_total[30s])
|
|
62
|
+
|
|
63
|
+
#### CPU usage
|
|
64
|
+
|
|
65
|
+
rate(process_cpu_user_seconds_total[30s]) * 100
|
|
66
|
+
|
|
67
|
+
#### Memory usage
|
|
68
|
+
|
|
69
|
+
nodejs_memory_usage_bytes
|
|
70
|
+
|
|
71
|
+
#### DHT query time
|
|
72
|
+
|
|
73
|
+
libp2p_kad_dht_wan_query_time_seconds
|
|
74
|
+
|
|
75
|
+
or
|
|
76
|
+
|
|
77
|
+
libp2p_kad_dht_lan_query_time_seconds
|
|
78
|
+
|
|
79
|
+
#### TCP transport dialer errors
|
|
80
|
+
|
|
81
|
+
rate(libp2p_tcp_dialer_errors_total[30s])
|
|
82
|
+
|
|
22
83
|
## License
|
|
23
84
|
|
|
24
85
|
Licensed under either of
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CounterGroup, CalculatedMetricOptions } from '@libp2p/interface-metrics';
|
|
2
|
+
export declare class PrometheusCounterGroup implements CounterGroup {
|
|
3
|
+
private readonly counter;
|
|
4
|
+
private readonly label;
|
|
5
|
+
constructor(name: string, opts: CalculatedMetricOptions<Record<string, number>>);
|
|
6
|
+
increment(values: Record<string, number | unknown>): void;
|
|
7
|
+
reset(): void;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=counter-group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter-group.d.ts","sourceRoot":"","sources":["../../src/counter-group.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAmB,MAAM,2BAA2B,CAAA;AAIvG,qBAAa,sBAAuB,YAAW,YAAY;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;gBAEjB,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IA2BhF,SAAS,CAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI;IAQ1D,KAAK,IAAK,IAAI;CAGf"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Counter as PromCounter } from 'prom-client';
|
|
2
|
+
import { normaliseString } from './utils.js';
|
|
3
|
+
export class PrometheusCounterGroup {
|
|
4
|
+
constructor(name, opts) {
|
|
5
|
+
name = normaliseString(name);
|
|
6
|
+
const help = normaliseString(opts.help ?? name);
|
|
7
|
+
const label = this.label = normaliseString(opts.label ?? name);
|
|
8
|
+
let collect;
|
|
9
|
+
// calculated metric
|
|
10
|
+
if (opts?.calculate != null) {
|
|
11
|
+
const calculate = opts.calculate;
|
|
12
|
+
collect = async function () {
|
|
13
|
+
const values = await calculate();
|
|
14
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
15
|
+
this.inc({ [label]: key }, value);
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
this.counter = new PromCounter({
|
|
20
|
+
name,
|
|
21
|
+
help,
|
|
22
|
+
labelNames: [this.label],
|
|
23
|
+
collect
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
increment(values) {
|
|
27
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
28
|
+
const inc = typeof value === 'number' ? value : 1;
|
|
29
|
+
this.counter.inc({ [this.label]: key }, inc);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
reset() {
|
|
33
|
+
this.counter.reset();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=counter-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter-group.js","sourceRoot":"","sources":["../../src/counter-group.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAmB,MAAM,aAAa,CAAA;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE5C,MAAM,OAAO,sBAAsB;IAIjC,YAAa,IAAY,EAAE,IAAqD;QAC9E,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAA;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAA;QAC9D,IAAI,OAAsD,CAAA;QAE1D,oBAAoB;QACpB,IAAI,IAAI,EAAE,SAAS,IAAI,IAAI,EAAE;YAC3B,MAAM,SAAS,GAA4C,IAAI,CAAC,SAAS,CAAA;YAEzE,OAAO,GAAG,KAAK;gBACb,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;gBAEhC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;oBAC9C,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,CAAC,CAAA;gBACnC,CAAC,CAAC,CAAA;YACJ,CAAC,CAAA;SACF;QAED,IAAI,CAAC,OAAO,GAAG,IAAI,WAAW,CAAC;YAC7B,IAAI;YACJ,IAAI;YACJ,UAAU,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;YACxB,OAAO;SACR,CAAC,CAAA;IACJ,CAAC;IAED,SAAS,CAAE,MAAwC;QACjD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;YAC9C,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;YAEjD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,CAAC,CAAA;QAC9C,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Counter, CalculatedMetricOptions } from '@libp2p/interface-metrics';
|
|
2
|
+
export declare class PrometheusCounter implements Counter {
|
|
3
|
+
private readonly counter;
|
|
4
|
+
constructor(name: string, opts: CalculatedMetricOptions);
|
|
5
|
+
increment(value?: number): void;
|
|
6
|
+
reset(): void;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=counter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter.d.ts","sourceRoot":"","sources":["../../src/counter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAA;AAIjF,qBAAa,iBAAkB,YAAW,OAAO;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;gBAExB,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB;IAyBxD,SAAS,CAAE,KAAK,GAAE,MAAU,GAAG,IAAI;IAInC,KAAK,IAAK,IAAI;CAGf"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Counter as PromCounter } from 'prom-client';
|
|
2
|
+
import { normaliseString } from './utils.js';
|
|
3
|
+
export class PrometheusCounter {
|
|
4
|
+
constructor(name, opts) {
|
|
5
|
+
name = normaliseString(name);
|
|
6
|
+
const help = normaliseString(opts.help ?? name);
|
|
7
|
+
const labels = opts.label != null ? [normaliseString(opts.label)] : [];
|
|
8
|
+
let collect;
|
|
9
|
+
// calculated metric
|
|
10
|
+
if (opts?.calculate != null) {
|
|
11
|
+
const calculate = opts.calculate;
|
|
12
|
+
collect = async function () {
|
|
13
|
+
const value = await calculate();
|
|
14
|
+
this.inc(value);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
this.counter = new PromCounter({
|
|
18
|
+
name,
|
|
19
|
+
help,
|
|
20
|
+
labelNames: labels,
|
|
21
|
+
collect
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
increment(value = 1) {
|
|
25
|
+
this.counter.inc(value);
|
|
26
|
+
}
|
|
27
|
+
reset() {
|
|
28
|
+
this.counter.reset();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=counter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter.js","sourceRoot":"","sources":["../../src/counter.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,OAAO,IAAI,WAAW,EAAE,MAAM,aAAa,CAAA;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE5C,MAAM,OAAO,iBAAiB;IAG5B,YAAa,IAAY,EAAE,IAA6B;QACtD,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACtE,IAAI,OAAsD,CAAA;QAE1D,oBAAoB;QACpB,IAAI,IAAI,EAAE,SAAS,IAAI,IAAI,EAAE;YAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;YAEhC,OAAO,GAAG,KAAK;gBACb,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAA;gBAE/B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACjB,CAAC,CAAA;SACF;QAED,IAAI,CAAC,OAAO,GAAG,IAAI,WAAW,CAAC;YAC7B,IAAI;YACJ,IAAI;YACJ,UAAU,EAAE,MAAM;YAClB,OAAO;SACR,CAAC,CAAA;IACJ,CAAC;IAED,SAAS,CAAE,QAAgB,CAAC;QAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;CACF"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import type { Metrics } from '@libp2p/interface-metrics';
|
|
2
2
|
import { DefaultMetricsCollectorConfiguration } from 'prom-client';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
export interface PrometheusMetricsInit {
|
|
4
|
+
/**
|
|
5
|
+
* By default we collect default metrics - CPU, memory etc, to not do
|
|
6
|
+
* this, pass true here
|
|
7
|
+
*/
|
|
8
|
+
collectDefaultMetrics?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* prom-client options to pass to the `collectDefaultMetrics` function
|
|
11
|
+
*/
|
|
5
12
|
defaultMetrics?: DefaultMetricsCollectorConfiguration;
|
|
13
|
+
/**
|
|
14
|
+
* All metrics in prometheus are global so to prevent clashes in naming
|
|
15
|
+
* we reset the global metrics registry on creation - to not do this,
|
|
16
|
+
* pass true here
|
|
17
|
+
*/
|
|
6
18
|
preserveExistingMetrics?: boolean;
|
|
7
|
-
collectDefaultMetrics?: boolean;
|
|
8
19
|
}
|
|
9
20
|
export declare function prometheusMetrics(init?: Partial<PrometheusMetricsInit>): () => Metrics;
|
|
10
21
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsF,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAC5I,OAAO,EAAyB,oCAAoC,EAAY,MAAM,aAAa,CAAA;AAYnG,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAE/B;;OAEG;IACH,cAAc,CAAC,EAAE,oCAAoC,CAAA;IAErD;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAClC;AAwJD,wBAAgB,iBAAiB,CAAE,IAAI,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,MAAM,OAAO,CAIvF"}
|
package/dist/src/index.js
CHANGED
|
@@ -1,38 +1,37 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { collectDefaultMetrics, register } from 'prom-client';
|
|
2
|
+
import each from 'it-foreach';
|
|
2
3
|
import { PrometheusMetric } from './metric.js';
|
|
3
4
|
import { PrometheusMetricGroup } from './metric-group.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
5
|
+
import { PrometheusCounter } from './counter.js';
|
|
6
|
+
import { PrometheusCounterGroup } from './counter-group.js';
|
|
7
|
+
import { logger } from '@libp2p/logger';
|
|
8
|
+
const log = logger('libp2p:prometheus-metrics');
|
|
9
|
+
class PrometheusMetrics {
|
|
6
10
|
constructor(init) {
|
|
7
|
-
super(init);
|
|
8
11
|
if (init?.preserveExistingMetrics !== true) {
|
|
9
|
-
|
|
10
|
-
// existing metrics to make sure we don't error when setting up metrics
|
|
12
|
+
log('Clearing existing metrics');
|
|
11
13
|
register.clear();
|
|
12
14
|
}
|
|
13
15
|
if (init?.preserveExistingMetrics !== false) {
|
|
14
|
-
|
|
16
|
+
log('Collecting default metrics');
|
|
15
17
|
collectDefaultMetrics(init?.defaultMetrics);
|
|
16
18
|
}
|
|
17
|
-
|
|
19
|
+
// holds global and per-protocol sent/received stats
|
|
20
|
+
this.transferStats = new Map();
|
|
21
|
+
log('Collecting data transfer metrics');
|
|
22
|
+
this.registerCounterGroup('libp2p_data_transfer_bytes_total', {
|
|
18
23
|
label: 'protocol',
|
|
19
24
|
calculate: () => {
|
|
20
25
|
const output = {};
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
output['global received'] = Number(global.dataReceived);
|
|
24
|
-
for (const protocol of this.getProtocols()) {
|
|
25
|
-
const stats = this.forProtocol(protocol);
|
|
26
|
-
if (stats == null) {
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
const snapshot = stats.getSnapshot();
|
|
30
|
-
output[`${protocol} sent`] = Number(snapshot.dataSent);
|
|
31
|
-
output[`${protocol} received`] = Number(snapshot.dataReceived);
|
|
26
|
+
for (const [key, value] of this.transferStats.entries()) {
|
|
27
|
+
output[key] = value;
|
|
32
28
|
}
|
|
29
|
+
// reset counts for next time
|
|
30
|
+
this.transferStats = new Map();
|
|
33
31
|
return output;
|
|
34
32
|
}
|
|
35
33
|
});
|
|
34
|
+
log('Collecting memory metrics');
|
|
36
35
|
this.registerMetricGroup('nodejs_memory_usage_bytes', {
|
|
37
36
|
label: 'memory',
|
|
38
37
|
calculate: () => {
|
|
@@ -42,53 +41,81 @@ class PrometheusMetrics extends DefaultMetrics {
|
|
|
42
41
|
}
|
|
43
42
|
});
|
|
44
43
|
}
|
|
45
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Increment the transfer stat for the passed key, making sure
|
|
46
|
+
* it exists first
|
|
47
|
+
*/
|
|
48
|
+
_incrementValue(key, value) {
|
|
49
|
+
const existing = this.transferStats.get(key) ?? 0;
|
|
50
|
+
this.transferStats.set(key, existing + value);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Override the sink/source of the stream to count the bytes
|
|
54
|
+
* in and out
|
|
55
|
+
*/
|
|
56
|
+
_track(stream, name) {
|
|
57
|
+
const self = this;
|
|
58
|
+
const sink = stream.sink;
|
|
59
|
+
stream.sink = async function trackedSink(source) {
|
|
60
|
+
await sink(each(source, buf => {
|
|
61
|
+
self._incrementValue(`${name} sent`, buf.byteLength);
|
|
62
|
+
}));
|
|
63
|
+
};
|
|
64
|
+
const source = stream.source;
|
|
65
|
+
stream.source = each(source, buf => {
|
|
66
|
+
self._incrementValue(`${name} received`, buf.byteLength);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
trackMultiaddrConnection(maConn) {
|
|
70
|
+
this._track(maConn, 'global');
|
|
71
|
+
}
|
|
72
|
+
trackProtocolStream(stream, connection) {
|
|
73
|
+
if (stream.stat.protocol == null) {
|
|
74
|
+
// protocol not negotiated yet, should not happen as the upgrader
|
|
75
|
+
// calls this handler after protocol negotiation
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this._track(stream, stream.stat.protocol);
|
|
79
|
+
}
|
|
80
|
+
registerMetric(name, opts = {}) {
|
|
46
81
|
if (name == null ?? name.trim() === '') {
|
|
47
82
|
throw new Error('Metric name is required');
|
|
48
83
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const value = await calculate();
|
|
54
|
-
this.set(value);
|
|
55
|
-
};
|
|
56
|
-
// prom-client metrics are global
|
|
57
|
-
new Gauge({
|
|
58
|
-
name,
|
|
59
|
-
help: opts.help ?? name,
|
|
60
|
-
labelNames: [opts.label ?? name],
|
|
61
|
-
collect
|
|
62
|
-
});
|
|
63
|
-
return;
|
|
84
|
+
log('Register metric', name);
|
|
85
|
+
const metric = new PrometheusMetric(name, opts ?? {});
|
|
86
|
+
if (opts.calculate == null) {
|
|
87
|
+
return metric;
|
|
64
88
|
}
|
|
65
|
-
return new PrometheusMetric(name, opts ?? {});
|
|
66
89
|
}
|
|
67
|
-
registerMetricGroup(name, opts) {
|
|
90
|
+
registerMetricGroup(name, opts = {}) {
|
|
68
91
|
if (name == null ?? name.trim() === '') {
|
|
69
92
|
throw new Error('Metric name is required');
|
|
70
93
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
log('Register metric group', name);
|
|
95
|
+
const group = new PrometheusMetricGroup(name, opts ?? {});
|
|
96
|
+
if (opts.calculate == null) {
|
|
97
|
+
return group;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
registerCounter(name, opts = {}) {
|
|
101
|
+
if (name == null ?? name.trim() === '') {
|
|
102
|
+
throw new Error('Counter name is required');
|
|
103
|
+
}
|
|
104
|
+
log('Register counter', name);
|
|
105
|
+
const counter = new PrometheusCounter(name, opts);
|
|
106
|
+
if (opts.calculate == null) {
|
|
107
|
+
return counter;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
registerCounterGroup(name, opts = {}) {
|
|
111
|
+
if (name == null ?? name.trim() === '') {
|
|
112
|
+
throw new Error('Metric name is required');
|
|
113
|
+
}
|
|
114
|
+
log('Register counter group', name);
|
|
115
|
+
const group = new PrometheusCounterGroup(name, opts);
|
|
116
|
+
if (opts.calculate == null) {
|
|
117
|
+
return group;
|
|
90
118
|
}
|
|
91
|
-
return new PrometheusMetricGroup(name, opts ?? {});
|
|
92
119
|
}
|
|
93
120
|
}
|
|
94
121
|
export function prometheusMetrics(init) {
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CalculatedMetricOptions, MetricGroup, StopTimer } from '@libp2p/interface-metrics';
|
|
2
2
|
export declare class PrometheusMetricGroup implements MetricGroup {
|
|
3
3
|
private readonly gauge;
|
|
4
4
|
private readonly label;
|
|
5
|
-
constructor(name: string, opts:
|
|
5
|
+
constructor(name: string, opts: CalculatedMetricOptions<Record<string, number>>);
|
|
6
6
|
update(values: Record<string, number>): void;
|
|
7
7
|
increment(values: Record<string, number | unknown>): void;
|
|
8
8
|
decrement(values: Record<string, number | unknown>): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metric-group.d.ts","sourceRoot":"","sources":["../../src/metric-group.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"metric-group.d.ts","sourceRoot":"","sources":["../../src/metric-group.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAmB,WAAW,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAIjH,qBAAa,qBAAsB,YAAW,WAAW;IACvD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;gBAEjB,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IA2BhF,MAAM,CAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAM7C,SAAS,CAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI;IAQ1D,SAAS,CAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI;IAQ1D,KAAK,IAAK,IAAI;IAId,KAAK,CAAE,GAAG,EAAE,MAAM,GAAG,SAAS;CAK/B"}
|
package/dist/src/metric-group.js
CHANGED
|
@@ -4,11 +4,23 @@ export class PrometheusMetricGroup {
|
|
|
4
4
|
constructor(name, opts) {
|
|
5
5
|
name = normaliseString(name);
|
|
6
6
|
const help = normaliseString(opts.help ?? name);
|
|
7
|
-
this.label = normaliseString(opts.label ?? name);
|
|
7
|
+
const label = this.label = normaliseString(opts.label ?? name);
|
|
8
|
+
let collect;
|
|
9
|
+
// calculated metric
|
|
10
|
+
if (opts?.calculate != null) {
|
|
11
|
+
const calculate = opts.calculate;
|
|
12
|
+
collect = async function () {
|
|
13
|
+
const values = await calculate();
|
|
14
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
15
|
+
this.set({ [label]: key }, value);
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
}
|
|
8
19
|
this.gauge = new Gauge({
|
|
9
20
|
name,
|
|
10
21
|
help,
|
|
11
|
-
labelNames: [this.label]
|
|
22
|
+
labelNames: [this.label],
|
|
23
|
+
collect
|
|
12
24
|
});
|
|
13
25
|
}
|
|
14
26
|
update(values) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metric-group.js","sourceRoot":"","sources":["../../src/metric-group.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"metric-group.js","sourceRoot":"","sources":["../../src/metric-group.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE5C,MAAM,OAAO,qBAAqB;IAIhC,YAAa,IAAY,EAAE,IAAqD;QAC9E,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAA;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAA;QAC9D,IAAI,OAAgD,CAAA;QAEpD,oBAAoB;QACpB,IAAI,IAAI,EAAE,SAAS,IAAI,IAAI,EAAE;YAC3B,MAAM,SAAS,GAA4C,IAAI,CAAC,SAAS,CAAA;YAEzE,OAAO,GAAG,KAAK;gBACb,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;gBAEhC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;oBAC9C,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,CAAC,CAAA;gBACnC,CAAC,CAAC,CAAA;YACJ,CAAC,CAAA;SACF;QAED,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC;YACrB,IAAI;YACJ,IAAI;YACJ,UAAU,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;YACxB,OAAO;SACR,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,CAAE,MAA8B;QACpC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;YAC9C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,CAAC,CAAA;QAC9C,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,SAAS,CAAE,MAAwC;QACjD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;YAC9C,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;YAEjD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,CAAC,CAAA;QAC5C,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,SAAS,CAAE,MAAwC;QACjD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;YAC9C,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;YAEjD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,CAAC,CAAA;QAC5C,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC;IAED,KAAK,CAAE,GAAW;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;YAC3B,GAAG,EAAE,CAAC;SACP,CAAC,CAAA;IACJ,CAAC;CACF"}
|
package/dist/src/metric.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Metric,
|
|
1
|
+
import type { Metric, CalculatedMetricOptions, StopTimer } from '@libp2p/interface-metrics';
|
|
2
2
|
export declare class PrometheusMetric implements Metric {
|
|
3
3
|
private readonly gauge;
|
|
4
|
-
constructor(name: string, opts:
|
|
4
|
+
constructor(name: string, opts: CalculatedMetricOptions);
|
|
5
5
|
update(value: number): void;
|
|
6
6
|
increment(value?: number): void;
|
|
7
7
|
decrement(value?: number): void;
|
package/dist/src/metric.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metric.d.ts","sourceRoot":"","sources":["../../src/metric.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"metric.d.ts","sourceRoot":"","sources":["../../src/metric.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAI3F,qBAAa,gBAAiB,YAAW,MAAM;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAO;gBAEhB,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB;IAyBxD,MAAM,CAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAI5B,SAAS,CAAE,KAAK,GAAE,MAAU,GAAG,IAAI;IAInC,SAAS,CAAE,KAAK,GAAE,MAAU,GAAG,IAAI;IAInC,KAAK,IAAK,IAAI;IAId,KAAK,IAAK,SAAS;CAGpB"}
|
package/dist/src/metric.js
CHANGED
|
@@ -4,11 +4,21 @@ export class PrometheusMetric {
|
|
|
4
4
|
constructor(name, opts) {
|
|
5
5
|
name = normaliseString(name);
|
|
6
6
|
const help = normaliseString(opts.help ?? name);
|
|
7
|
-
const
|
|
7
|
+
const labels = opts.label != null ? [normaliseString(opts.label)] : [];
|
|
8
|
+
let collect;
|
|
9
|
+
// calculated metric
|
|
10
|
+
if (opts?.calculate != null) {
|
|
11
|
+
const calculate = opts.calculate;
|
|
12
|
+
collect = async function () {
|
|
13
|
+
const value = await calculate();
|
|
14
|
+
this.set(value);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
8
17
|
this.gauge = new Gauge({
|
|
9
18
|
name,
|
|
10
19
|
help,
|
|
11
|
-
labelNames:
|
|
20
|
+
labelNames: labels,
|
|
21
|
+
collect
|
|
12
22
|
});
|
|
13
23
|
}
|
|
14
24
|
update(value) {
|
package/dist/src/metric.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metric.js","sourceRoot":"","sources":["../../src/metric.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"metric.js","sourceRoot":"","sources":["../../src/metric.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE5C,MAAM,OAAO,gBAAgB;IAG3B,YAAa,IAAY,EAAE,IAA6B;QACtD,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACtE,IAAI,OAAgD,CAAA;QAEpD,oBAAoB;QACpB,IAAI,IAAI,EAAE,SAAS,IAAI,IAAI,EAAE;YAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;YAEhC,OAAO,GAAG,KAAK;gBACb,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAA;gBAE/B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACjB,CAAC,CAAA;SACF;QAED,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC;YACrB,IAAI;YACJ,IAAI;YACJ,UAAU,EAAE,MAAM;YAClB,OAAO;SACR,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,CAAE,KAAa;QACnB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAED,SAAS,CAAE,QAAgB,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAED,SAAS,CAAE,QAAgB,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAA;IAChC,CAAC;CACF"}
|
package/dist/src/utils.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export declare const ONE_SECOND = 1000;
|
|
2
2
|
export declare const ONE_MINUTE: number;
|
|
3
|
+
/**
|
|
4
|
+
* See https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
|
|
5
|
+
* for rules on valid naming
|
|
6
|
+
*/
|
|
3
7
|
export declare function normaliseString(str: string): string;
|
|
4
8
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/src/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,UAAU,OAAO,CAAA;AAC9B,eAAO,MAAM,UAAU,QAAkB,CAAA;AAEzC,wBAAgB,eAAe,CAAE,GAAG,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,UAAU,OAAO,CAAA;AAC9B,eAAO,MAAM,UAAU,QAAkB,CAAA;AAEzC;;;GAGG;AACH,wBAAgB,eAAe,CAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAIpD"}
|
package/dist/src/utils.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
export const ONE_SECOND = 1000;
|
|
2
2
|
export const ONE_MINUTE = 60 * ONE_SECOND;
|
|
3
|
+
/**
|
|
4
|
+
* See https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
|
|
5
|
+
* for rules on valid naming
|
|
6
|
+
*/
|
|
3
7
|
export function normaliseString(str) {
|
|
4
|
-
return str
|
|
8
|
+
return str
|
|
9
|
+
.replace(/[^a-zA-Z0-9_]/g, '_')
|
|
10
|
+
.replace(/_+/g, '_');
|
|
5
11
|
}
|
|
6
12
|
//# sourceMappingURL=utils.js.map
|
package/dist/src/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAA;AAC9B,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,GAAG,UAAU,CAAA;AAEzC,MAAM,UAAU,eAAe,CAAE,GAAW;IAC1C,OAAO,GAAG,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAA;AAC9B,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,GAAG,UAAU,CAAA;AAEzC;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAE,GAAW;IAC1C,OAAO,GAAG;SACP,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC;SAC9B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;AACxB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libp2p/prometheus-metrics",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Collect libp2p metrics for scraping by Prometheus",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Collect libp2p metrics for scraping by Prometheus or Graphana",
|
|
5
5
|
"author": "",
|
|
6
6
|
"license": "Apache-2.0 OR MIT",
|
|
7
7
|
"homepage": "https://github.com/libp2p/js-libp2p-prometheus-metrics#readme",
|
|
@@ -132,24 +132,25 @@
|
|
|
132
132
|
"release": "aegir release"
|
|
133
133
|
},
|
|
134
134
|
"dependencies": {
|
|
135
|
-
"@libp2p/interface-
|
|
136
|
-
"@libp2p/metrics": "^
|
|
137
|
-
"
|
|
138
|
-
"it-
|
|
139
|
-
|
|
140
|
-
"peerDependencies": {
|
|
141
|
-
"prom-client": "^14.1.0"
|
|
135
|
+
"@libp2p/interface-connection": "^3.0.2",
|
|
136
|
+
"@libp2p/interface-metrics": "^4.0.2",
|
|
137
|
+
"@libp2p/logger": "^2.0.2",
|
|
138
|
+
"it-foreach": "^1.0.0",
|
|
139
|
+
"it-stream-types": "^1.0.4"
|
|
142
140
|
},
|
|
143
141
|
"devDependencies": {
|
|
144
|
-
"@libp2p/interface-connection": "^3.0.2",
|
|
145
142
|
"@libp2p/interface-mocks": "^7.0.3",
|
|
146
143
|
"@libp2p/peer-id-factory": "^1.0.19",
|
|
147
144
|
"@multiformats/multiaddr": "^11.0.7",
|
|
148
145
|
"aegir": "^37.5.6",
|
|
146
|
+
"it-drain": "^2.0.0",
|
|
149
147
|
"it-pair": "^2.0.3",
|
|
150
|
-
"it-
|
|
148
|
+
"it-pipe": "^2.0.4",
|
|
151
149
|
"p-defer": "^4.0.0",
|
|
152
150
|
"prom-client": "^14.1.0",
|
|
153
151
|
"uint8arraylist": "^2.3.3"
|
|
152
|
+
},
|
|
153
|
+
"peerDependencies": {
|
|
154
|
+
"prom-client": "^14.1.0"
|
|
154
155
|
}
|
|
155
156
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { CounterGroup, CalculatedMetricOptions, CalculateMetric } from '@libp2p/interface-metrics'
|
|
2
|
+
import { Counter as PromCounter, CollectFunction } from 'prom-client'
|
|
3
|
+
import { normaliseString } from './utils.js'
|
|
4
|
+
|
|
5
|
+
export class PrometheusCounterGroup implements CounterGroup {
|
|
6
|
+
private readonly counter: PromCounter
|
|
7
|
+
private readonly label: string
|
|
8
|
+
|
|
9
|
+
constructor (name: string, opts: CalculatedMetricOptions<Record<string, number>>) {
|
|
10
|
+
name = normaliseString(name)
|
|
11
|
+
const help = normaliseString(opts.help ?? name)
|
|
12
|
+
const label = this.label = normaliseString(opts.label ?? name)
|
|
13
|
+
let collect: CollectFunction<PromCounter<any>> | undefined
|
|
14
|
+
|
|
15
|
+
// calculated metric
|
|
16
|
+
if (opts?.calculate != null) {
|
|
17
|
+
const calculate: CalculateMetric<Record<string, number>> = opts.calculate
|
|
18
|
+
|
|
19
|
+
collect = async function () {
|
|
20
|
+
const values = await calculate()
|
|
21
|
+
|
|
22
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
23
|
+
this.inc({ [label]: key }, value)
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.counter = new PromCounter({
|
|
29
|
+
name,
|
|
30
|
+
help,
|
|
31
|
+
labelNames: [this.label],
|
|
32
|
+
collect
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
increment (values: Record<string, number | unknown>): void {
|
|
37
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
38
|
+
const inc = typeof value === 'number' ? value : 1
|
|
39
|
+
|
|
40
|
+
this.counter.inc({ [this.label]: key }, inc)
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
reset (): void {
|
|
45
|
+
this.counter.reset()
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/counter.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Counter, CalculatedMetricOptions } from '@libp2p/interface-metrics'
|
|
2
|
+
import { CollectFunction, Counter as PromCounter } from 'prom-client'
|
|
3
|
+
import { normaliseString } from './utils.js'
|
|
4
|
+
|
|
5
|
+
export class PrometheusCounter implements Counter {
|
|
6
|
+
private readonly counter: PromCounter
|
|
7
|
+
|
|
8
|
+
constructor (name: string, opts: CalculatedMetricOptions) {
|
|
9
|
+
name = normaliseString(name)
|
|
10
|
+
const help = normaliseString(opts.help ?? name)
|
|
11
|
+
const labels = opts.label != null ? [normaliseString(opts.label)] : []
|
|
12
|
+
let collect: CollectFunction<PromCounter<any>> | undefined
|
|
13
|
+
|
|
14
|
+
// calculated metric
|
|
15
|
+
if (opts?.calculate != null) {
|
|
16
|
+
const calculate = opts.calculate
|
|
17
|
+
|
|
18
|
+
collect = async function () {
|
|
19
|
+
const value = await calculate()
|
|
20
|
+
|
|
21
|
+
this.inc(value)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
this.counter = new PromCounter({
|
|
26
|
+
name,
|
|
27
|
+
help,
|
|
28
|
+
labelNames: labels,
|
|
29
|
+
collect
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
increment (value: number = 1): void {
|
|
34
|
+
this.counter.inc(value)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
reset (): void {
|
|
38
|
+
this.counter.reset()
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,56 +1,71 @@
|
|
|
1
|
-
import type { CalculatedMetricOptions,
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import type { CalculatedMetricOptions, Counter, CounterGroup, Metric, MetricGroup, MetricOptions, Metrics } from '@libp2p/interface-metrics'
|
|
2
|
+
import { collectDefaultMetrics, DefaultMetricsCollectorConfiguration, register } from 'prom-client'
|
|
3
|
+
import type { MultiaddrConnection, Stream, Connection } from '@libp2p/interface-connection'
|
|
4
|
+
import type { Duplex } from 'it-stream-types'
|
|
5
|
+
import each from 'it-foreach'
|
|
4
6
|
import { PrometheusMetric } from './metric.js'
|
|
5
7
|
import { PrometheusMetricGroup } from './metric-group.js'
|
|
6
|
-
import {
|
|
8
|
+
import { PrometheusCounter } from './counter.js'
|
|
9
|
+
import { PrometheusCounterGroup } from './counter-group.js'
|
|
10
|
+
import { logger } from '@libp2p/logger'
|
|
7
11
|
|
|
8
|
-
|
|
12
|
+
const log = logger('libp2p:prometheus-metrics')
|
|
13
|
+
|
|
14
|
+
export interface PrometheusMetricsInit {
|
|
15
|
+
/**
|
|
16
|
+
* By default we collect default metrics - CPU, memory etc, to not do
|
|
17
|
+
* this, pass true here
|
|
18
|
+
*/
|
|
19
|
+
collectDefaultMetrics?: boolean
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* prom-client options to pass to the `collectDefaultMetrics` function
|
|
23
|
+
*/
|
|
9
24
|
defaultMetrics?: DefaultMetricsCollectorConfiguration
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* All metrics in prometheus are global so to prevent clashes in naming
|
|
28
|
+
* we reset the global metrics registry on creation - to not do this,
|
|
29
|
+
* pass true here
|
|
30
|
+
*/
|
|
10
31
|
preserveExistingMetrics?: boolean
|
|
11
|
-
collectDefaultMetrics?: boolean
|
|
12
32
|
}
|
|
13
33
|
|
|
14
|
-
class PrometheusMetrics
|
|
15
|
-
|
|
16
|
-
super(init)
|
|
34
|
+
class PrometheusMetrics implements Metrics {
|
|
35
|
+
private transferStats: Map<string, number>
|
|
17
36
|
|
|
37
|
+
constructor (init?: Partial<PrometheusMetricsInit>) {
|
|
18
38
|
if (init?.preserveExistingMetrics !== true) {
|
|
19
|
-
|
|
20
|
-
// existing metrics to make sure we don't error when setting up metrics
|
|
39
|
+
log('Clearing existing metrics')
|
|
21
40
|
register.clear()
|
|
22
41
|
}
|
|
23
42
|
|
|
24
43
|
if (init?.preserveExistingMetrics !== false) {
|
|
25
|
-
|
|
44
|
+
log('Collecting default metrics')
|
|
26
45
|
collectDefaultMetrics(init?.defaultMetrics)
|
|
27
46
|
}
|
|
28
47
|
|
|
29
|
-
|
|
48
|
+
// holds global and per-protocol sent/received stats
|
|
49
|
+
this.transferStats = new Map()
|
|
50
|
+
|
|
51
|
+
log('Collecting data transfer metrics')
|
|
52
|
+
this.registerCounterGroup('libp2p_data_transfer_bytes_total', {
|
|
30
53
|
label: 'protocol',
|
|
31
54
|
calculate: () => {
|
|
32
55
|
const output: Record<string, number> = {}
|
|
33
56
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
output['global received'] = Number(global.dataReceived)
|
|
37
|
-
|
|
38
|
-
for (const protocol of this.getProtocols()) {
|
|
39
|
-
const stats = this.forProtocol(protocol)
|
|
40
|
-
|
|
41
|
-
if (stats == null) {
|
|
42
|
-
continue
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const snapshot = stats.getSnapshot()
|
|
46
|
-
output[`${protocol} sent`] = Number(snapshot.dataSent)
|
|
47
|
-
output[`${protocol} received`] = Number(snapshot.dataReceived)
|
|
57
|
+
for (const [key, value] of this.transferStats.entries()) {
|
|
58
|
+
output[key] = value
|
|
48
59
|
}
|
|
49
60
|
|
|
61
|
+
// reset counts for next time
|
|
62
|
+
this.transferStats = new Map()
|
|
63
|
+
|
|
50
64
|
return output
|
|
51
65
|
}
|
|
52
66
|
})
|
|
53
67
|
|
|
68
|
+
log('Collecting memory metrics')
|
|
54
69
|
this.registerMetricGroup('nodejs_memory_usage_bytes', {
|
|
55
70
|
label: 'memory',
|
|
56
71
|
calculate: () => {
|
|
@@ -61,70 +76,108 @@ class PrometheusMetrics extends DefaultMetrics implements Metrics, Startable {
|
|
|
61
76
|
})
|
|
62
77
|
}
|
|
63
78
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Increment the transfer stat for the passed key, making sure
|
|
81
|
+
* it exists first
|
|
82
|
+
*/
|
|
83
|
+
_incrementValue (key: string, value: number) {
|
|
84
|
+
const existing = this.transferStats.get(key) ?? 0
|
|
70
85
|
|
|
71
|
-
|
|
72
|
-
|
|
86
|
+
this.transferStats.set(key, existing + value)
|
|
87
|
+
}
|
|
73
88
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Override the sink/source of the stream to count the bytes
|
|
91
|
+
* in and out
|
|
92
|
+
*/
|
|
93
|
+
_track (stream: Duplex<any>, name: string) {
|
|
94
|
+
const self = this
|
|
95
|
+
|
|
96
|
+
const sink = stream.sink
|
|
97
|
+
stream.sink = async function trackedSink (source) {
|
|
98
|
+
await sink(each(source, buf => {
|
|
99
|
+
self._incrementValue(`${name} sent`, buf.byteLength)
|
|
100
|
+
}))
|
|
101
|
+
}
|
|
77
102
|
|
|
78
|
-
|
|
79
|
-
|
|
103
|
+
const source = stream.source
|
|
104
|
+
stream.source = each(source, buf => {
|
|
105
|
+
self._incrementValue(`${name} received`, buf.byteLength)
|
|
106
|
+
})
|
|
107
|
+
}
|
|
80
108
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
help: opts.help ?? name,
|
|
85
|
-
labelNames: [opts.label ?? name],
|
|
86
|
-
collect
|
|
87
|
-
})
|
|
109
|
+
trackMultiaddrConnection (maConn: MultiaddrConnection): void {
|
|
110
|
+
this._track(maConn, 'global')
|
|
111
|
+
}
|
|
88
112
|
|
|
113
|
+
trackProtocolStream (stream: Stream, connection: Connection): void {
|
|
114
|
+
if (stream.stat.protocol == null) {
|
|
115
|
+
// protocol not negotiated yet, should not happen as the upgrader
|
|
116
|
+
// calls this handler after protocol negotiation
|
|
89
117
|
return
|
|
90
118
|
}
|
|
91
119
|
|
|
92
|
-
|
|
120
|
+
this._track(stream, stream.stat.protocol)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
registerMetric (name: string, opts: CalculatedMetricOptions): void
|
|
124
|
+
registerMetric (name: string, opts?: MetricOptions): Metric
|
|
125
|
+
registerMetric (name: string, opts: any = {}): any {
|
|
126
|
+
if (name == null ?? name.trim() === '') {
|
|
127
|
+
throw new Error('Metric name is required')
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
log('Register metric', name)
|
|
131
|
+
const metric = new PrometheusMetric(name, opts ?? {})
|
|
132
|
+
|
|
133
|
+
if (opts.calculate == null) {
|
|
134
|
+
return metric
|
|
135
|
+
}
|
|
93
136
|
}
|
|
94
137
|
|
|
95
138
|
registerMetricGroup (name: string, opts: CalculatedMetricOptions<Record<string, number>>): void
|
|
96
139
|
registerMetricGroup (name: string, opts?: MetricOptions): MetricGroup
|
|
97
|
-
registerMetricGroup (name: string, opts: any): any {
|
|
140
|
+
registerMetricGroup (name: string, opts: any = {}): any {
|
|
98
141
|
if (name == null ?? name.trim() === '') {
|
|
99
142
|
throw new Error('Metric name is required')
|
|
100
143
|
}
|
|
101
144
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const calculate: CalculateMetric<Record<string, number>> = opts.calculate
|
|
105
|
-
const label = opts.label ?? name
|
|
145
|
+
log('Register metric group', name)
|
|
146
|
+
const group = new PrometheusMetricGroup(name, opts ?? {})
|
|
106
147
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
148
|
+
if (opts.calculate == null) {
|
|
149
|
+
return group
|
|
150
|
+
}
|
|
151
|
+
}
|
|
110
152
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
153
|
+
registerCounter (name: string, opts: CalculatedMetricOptions): void
|
|
154
|
+
registerCounter (name: string, opts?: MetricOptions): Counter
|
|
155
|
+
registerCounter (name: string, opts: any = {}): any {
|
|
156
|
+
if (name == null ?? name.trim() === '') {
|
|
157
|
+
throw new Error('Counter name is required')
|
|
158
|
+
}
|
|
115
159
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
name,
|
|
119
|
-
help: opts.help ?? name,
|
|
120
|
-
labelNames: [opts.label ?? name],
|
|
121
|
-
collect
|
|
122
|
-
})
|
|
160
|
+
log('Register counter', name)
|
|
161
|
+
const counter = new PrometheusCounter(name, opts)
|
|
123
162
|
|
|
124
|
-
|
|
163
|
+
if (opts.calculate == null) {
|
|
164
|
+
return counter
|
|
125
165
|
}
|
|
166
|
+
}
|
|
126
167
|
|
|
127
|
-
|
|
168
|
+
registerCounterGroup (name: string, opts: CalculatedMetricOptions<Record<string, number>>): void
|
|
169
|
+
registerCounterGroup (name: string, opts?: MetricOptions): CounterGroup
|
|
170
|
+
registerCounterGroup (name: string, opts: any = {}): any {
|
|
171
|
+
if (name == null ?? name.trim() === '') {
|
|
172
|
+
throw new Error('Metric name is required')
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
log('Register counter group', name)
|
|
176
|
+
const group = new PrometheusCounterGroup(name, opts)
|
|
177
|
+
|
|
178
|
+
if (opts.calculate == null) {
|
|
179
|
+
return group
|
|
180
|
+
}
|
|
128
181
|
}
|
|
129
182
|
}
|
|
130
183
|
|
package/src/metric-group.ts
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { Gauge } from 'prom-client'
|
|
1
|
+
import type { CalculatedMetricOptions, CalculateMetric, MetricGroup, StopTimer } from '@libp2p/interface-metrics'
|
|
2
|
+
import { CollectFunction, Gauge } from 'prom-client'
|
|
3
3
|
import { normaliseString } from './utils.js'
|
|
4
4
|
|
|
5
5
|
export class PrometheusMetricGroup implements MetricGroup {
|
|
6
6
|
private readonly gauge: Gauge
|
|
7
7
|
private readonly label: string
|
|
8
8
|
|
|
9
|
-
constructor (name: string, opts:
|
|
9
|
+
constructor (name: string, opts: CalculatedMetricOptions<Record<string, number>>) {
|
|
10
10
|
name = normaliseString(name)
|
|
11
11
|
const help = normaliseString(opts.help ?? name)
|
|
12
|
-
this.label = normaliseString(opts.label ?? name)
|
|
12
|
+
const label = this.label = normaliseString(opts.label ?? name)
|
|
13
|
+
let collect: CollectFunction<Gauge<any>> | undefined
|
|
14
|
+
|
|
15
|
+
// calculated metric
|
|
16
|
+
if (opts?.calculate != null) {
|
|
17
|
+
const calculate: CalculateMetric<Record<string, number>> = opts.calculate
|
|
18
|
+
|
|
19
|
+
collect = async function () {
|
|
20
|
+
const values = await calculate()
|
|
21
|
+
|
|
22
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
23
|
+
this.set({ [label]: key }, value)
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
}
|
|
13
27
|
|
|
14
28
|
this.gauge = new Gauge({
|
|
15
29
|
name,
|
|
16
30
|
help,
|
|
17
|
-
labelNames: [this.label]
|
|
31
|
+
labelNames: [this.label],
|
|
32
|
+
collect
|
|
18
33
|
})
|
|
19
34
|
}
|
|
20
35
|
|
package/src/metric.ts
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
|
-
import type { Metric,
|
|
2
|
-
import { Gauge } from 'prom-client'
|
|
1
|
+
import type { Metric, CalculatedMetricOptions, StopTimer } from '@libp2p/interface-metrics'
|
|
2
|
+
import { CollectFunction, Gauge } from 'prom-client'
|
|
3
3
|
import { normaliseString } from './utils.js'
|
|
4
4
|
|
|
5
5
|
export class PrometheusMetric implements Metric {
|
|
6
6
|
private readonly gauge: Gauge
|
|
7
7
|
|
|
8
|
-
constructor (name: string, opts:
|
|
8
|
+
constructor (name: string, opts: CalculatedMetricOptions) {
|
|
9
9
|
name = normaliseString(name)
|
|
10
10
|
const help = normaliseString(opts.help ?? name)
|
|
11
|
-
const
|
|
11
|
+
const labels = opts.label != null ? [normaliseString(opts.label)] : []
|
|
12
|
+
let collect: CollectFunction<Gauge<any>> | undefined
|
|
13
|
+
|
|
14
|
+
// calculated metric
|
|
15
|
+
if (opts?.calculate != null) {
|
|
16
|
+
const calculate = opts.calculate
|
|
17
|
+
|
|
18
|
+
collect = async function () {
|
|
19
|
+
const value = await calculate()
|
|
20
|
+
|
|
21
|
+
this.set(value)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
12
24
|
|
|
13
25
|
this.gauge = new Gauge({
|
|
14
26
|
name,
|
|
15
27
|
help,
|
|
16
|
-
labelNames:
|
|
28
|
+
labelNames: labels,
|
|
29
|
+
collect
|
|
17
30
|
})
|
|
18
31
|
}
|
|
19
32
|
|
|
@@ -21,11 +34,11 @@ export class PrometheusMetric implements Metric {
|
|
|
21
34
|
this.gauge.set(value)
|
|
22
35
|
}
|
|
23
36
|
|
|
24
|
-
increment (value = 1): void {
|
|
37
|
+
increment (value: number = 1): void {
|
|
25
38
|
this.gauge.inc(value)
|
|
26
39
|
}
|
|
27
40
|
|
|
28
|
-
decrement (value = 1): void {
|
|
41
|
+
decrement (value: number = 1): void {
|
|
29
42
|
this.gauge.dec(value)
|
|
30
43
|
}
|
|
31
44
|
|
package/src/utils.ts
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
export const ONE_SECOND = 1000
|
|
3
3
|
export const ONE_MINUTE = 60 * ONE_SECOND
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* See https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
|
|
7
|
+
* for rules on valid naming
|
|
8
|
+
*/
|
|
5
9
|
export function normaliseString (str: string): string {
|
|
6
|
-
return str
|
|
10
|
+
return str
|
|
11
|
+
.replace(/[^a-zA-Z0-9_]/g, '_')
|
|
12
|
+
.replace(/_+/g, '_')
|
|
7
13
|
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export interface MovingAverage {
|
|
2
|
-
variance: number;
|
|
3
|
-
movingAverage: number;
|
|
4
|
-
deviation: number;
|
|
5
|
-
forecast: number;
|
|
6
|
-
push: (time: number, value: number) => void;
|
|
7
|
-
}
|
|
8
|
-
export declare class DefaultMovingAverage {
|
|
9
|
-
movingAverage: number;
|
|
10
|
-
variance: number;
|
|
11
|
-
deviation: number;
|
|
12
|
-
forecast: number;
|
|
13
|
-
private readonly timespan;
|
|
14
|
-
private previousTime?;
|
|
15
|
-
constructor(timespan: number);
|
|
16
|
-
alpha(t: number, pt: number): number;
|
|
17
|
-
push(time: number, value: number): void;
|
|
18
|
-
}
|
|
19
|
-
export declare function createMovingAverage(timespan: number): MovingAverage;
|
|
20
|
-
//# sourceMappingURL=moving-average.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"moving-average.d.ts","sourceRoot":"","sources":["../../src/moving-average.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAEhB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAC5C;AAED,qBAAa,oBAAoB;IACxB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,YAAY,CAAC,CAAQ;gBAEhB,QAAQ,EAAE,MAAM;IAgB7B,KAAK,CAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAI5B,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAkBlC;AAED,wBAAgB,mBAAmB,CAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAEpE"}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
export class DefaultMovingAverage {
|
|
2
|
-
constructor(timespan) {
|
|
3
|
-
if (typeof timespan !== 'number') {
|
|
4
|
-
throw new Error('must provide a timespan to the moving average constructor');
|
|
5
|
-
}
|
|
6
|
-
if (timespan <= 0) {
|
|
7
|
-
throw new Error('must provide a timespan > 0 to the moving average constructor');
|
|
8
|
-
}
|
|
9
|
-
this.timespan = timespan;
|
|
10
|
-
this.movingAverage = 0;
|
|
11
|
-
this.variance = 0;
|
|
12
|
-
this.deviation = 0;
|
|
13
|
-
this.forecast = 0;
|
|
14
|
-
}
|
|
15
|
-
alpha(t, pt) {
|
|
16
|
-
return 1 - (Math.exp(-(t - pt) / this.timespan));
|
|
17
|
-
}
|
|
18
|
-
push(time, value) {
|
|
19
|
-
if (this.previousTime != null) {
|
|
20
|
-
// calculate moving average
|
|
21
|
-
const a = this.alpha(time, this.previousTime);
|
|
22
|
-
const diff = value - this.movingAverage;
|
|
23
|
-
const incr = a * diff;
|
|
24
|
-
this.movingAverage = a * value + (1 - a) * this.movingAverage;
|
|
25
|
-
// calculate variance & deviation
|
|
26
|
-
this.variance = (1 - a) * (this.variance + diff * incr);
|
|
27
|
-
this.deviation = Math.sqrt(this.variance);
|
|
28
|
-
// calculate forecast
|
|
29
|
-
this.forecast = this.movingAverage + a * diff;
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
this.movingAverage = value;
|
|
33
|
-
}
|
|
34
|
-
this.previousTime = time;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
export function createMovingAverage(timespan) {
|
|
38
|
-
return new DefaultMovingAverage(timespan);
|
|
39
|
-
}
|
|
40
|
-
//# sourceMappingURL=moving-average.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"moving-average.js","sourceRoot":"","sources":["../../src/moving-average.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,oBAAoB;IAQ/B,YAAa,QAAgB;QAC3B,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE;YAChC,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAA;SAC7E;QAED,IAAI,QAAQ,IAAI,CAAC,EAAE;YACjB,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAA;SACjF;QAED,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;QACtB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;QACjB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAA;QAClB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;IACnB,CAAC;IAED,KAAK,CAAE,CAAS,EAAE,EAAU;QAC1B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;IAClD,CAAC;IAED,IAAI,CAAE,IAAY,EAAE,KAAa;QAC/B,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,EAAE;YAC7B,2BAA2B;YAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,CAAA;YAC7C,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,aAAa,CAAA;YACvC,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAA;YACrB,IAAI,CAAC,aAAa,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,aAAa,CAAA;YAC7D,iCAAiC;YACjC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC,CAAA;YACvD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACzC,qBAAqB;YACrB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,GAAG,CAAC,GAAG,IAAI,CAAA;SAC9C;aAAM;YACL,IAAI,CAAC,aAAa,GAAG,KAAK,CAAA;SAC3B;QAED,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;IAC1B,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB,CAAE,QAAgB;IACnD,OAAO,IAAI,oBAAoB,CAAC,QAAQ,CAAC,CAAA;AAC3C,CAAC"}
|