Skip to content

Commit 25de71b

Browse files
committed
feat: add histogram metric
1 parent 1f01462 commit 25de71b

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed

src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import PullTransport from './transport/PullTransport';
44
import PushTransport from './transport/PushTransport';
55
import Metric from './metric/Metric';
66
import GaugeMetric from './metric/GaugeMetric';
7+
import HistogramMetric from './metric/HistogramMetric';
78

89
export {
910
UMetrics,
@@ -12,4 +13,5 @@ export {
1213
PullTransport,
1314
GaugeMetric,
1415
Metric,
16+
HistogramMetric,
1517
};

src/metric/HistogramMetric.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import promClient from 'prom-client';
2+
import Metric from './Metric';
3+
4+
class HistogramMetric extends Metric {
5+
constructor(name, buckets = [], options = {}) {
6+
super(name, options);
7+
8+
this.promMetric = new promClient.Histogram({
9+
name: this.name,
10+
help: options.help || `${this.name}_help`,
11+
labelNames: Object.keys(this._labels),
12+
buckets,
13+
});
14+
}
15+
16+
/**
17+
* @param {string} action
18+
* @param {number} value
19+
* @param {Object.<string, string | number>} [_labels]
20+
* @return {HistogramMetric}
21+
* @private
22+
*/
23+
_proxyCall(action, value, _labels) {
24+
const labels = { ...this._labels, ..._labels };
25+
if (!labels) {
26+
this.promMetric[action](value);
27+
return this;
28+
}
29+
30+
this.promMetric[action](labels, value);
31+
return this;
32+
}
33+
34+
/**
35+
* @param {number} value
36+
* @param {Object.<string, string | number>} [labels]
37+
* @returns {HistogramMetric}
38+
*/
39+
observe(value, labels) {
40+
return this._proxyCall('observe', value, labels);
41+
}
42+
}
43+
44+
export default HistogramMetric;
+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { expect } from 'chai';
2+
import promClient from 'prom-client';
3+
import HistogramMetric from './HistogramMetric';
4+
5+
/**
6+
* @param {string} metricName
7+
* @return {number}
8+
*/
9+
const getMetricValues = metricName =>
10+
promClient.register.getSingleMetric(metricName).get().values;
11+
12+
/**
13+
* @param {string} metricName
14+
* @param {string} labelName
15+
* @return {string|number}
16+
*/
17+
const getLabelValue = (metricName, labelName) =>
18+
promClient.register.getSingleMetric(metricName).get().values[0].labels[
19+
labelName
20+
];
21+
22+
describe('HistogramMetric', () => {
23+
// Чтобы не ебалось при --watch
24+
afterEach(() => {
25+
promClient.register.clear();
26+
});
27+
28+
it('Can observe value without labels', () => {
29+
const metricName = 'test';
30+
31+
const metric = new HistogramMetric(metricName, [5, 100, 1000]);
32+
33+
metric.observe(5);
34+
metric.observe(50);
35+
metric.observe(100);
36+
metric.observe(1001);
37+
38+
const metricValues = getMetricValues(metricName);
39+
40+
expect(metricValues[0].labels.le).to.be.equal(5);
41+
expect(metricValues[0].value).to.be.equal(1);
42+
expect(metricValues[0].metricName).to.be.equal(`${metricName}_bucket`);
43+
44+
expect(metricValues[1].labels.le).to.be.equal(100);
45+
expect(metricValues[1].value).to.be.equal(3);
46+
47+
expect(metricValues[2].labels.le).to.be.equal(1000);
48+
expect(metricValues[2].value).to.be.equal(3);
49+
50+
expect(metricValues[3].labels.le).to.be.equal('+Inf');
51+
expect(metricValues[3].value).to.be.equal(4);
52+
53+
expect(metricValues[4].value).to.be.equal(1156);
54+
expect(metricValues[4].metricName).to.be.equal(`${metricName}_sum`);
55+
});
56+
57+
it('Can observe value with labels', () => {
58+
const metricName = 'test';
59+
const labelName = 'testLabel';
60+
61+
const metric = new HistogramMetric(metricName, [100], {
62+
labels: { testLabel: null },
63+
});
64+
65+
metric.observe(50, { [labelName]: 'testLabel' });
66+
metric.observe(150, { [labelName]: 'testLabel' });
67+
68+
const labelValue = getLabelValue(metricName, labelName);
69+
expect(labelValue).to.be.equal(labelName);
70+
71+
const metricValues = getMetricValues(metricName);
72+
expect(metricValues[0].labels.le).to.be.equal(100);
73+
expect(metricValues[0].value).to.be.equal(1);
74+
expect(metricValues[0].metricName).to.be.equal(`${metricName}_bucket`);
75+
76+
expect(metricValues[1].labels.le).to.be.equal('+Inf');
77+
expect(metricValues[1].value).to.be.equal(2);
78+
79+
expect(metricValues[2].value).to.be.equal(200);
80+
expect(metricValues[2].metricName).to.be.equal(`${metricName}_sum`);
81+
});
82+
83+
it('Can observe value without buckets', () => {
84+
const metricName = 'test';
85+
86+
const metric = new HistogramMetric(metricName);
87+
88+
metric.observe(50);
89+
metric.observe(150);
90+
91+
const metricValues = getMetricValues(metricName);
92+
93+
expect(metricValues[0].labels.le).to.be.equal('+Inf');
94+
expect(metricValues[0].value).to.be.equal(2);
95+
96+
expect(metricValues[1].value).to.be.equal(200);
97+
expect(metricValues[1].metricName).to.be.equal(`${metricName}_sum`);
98+
});
99+
});

0 commit comments

Comments
 (0)