-
Notifications
You must be signed in to change notification settings - Fork 378
/
counter.js
146 lines (130 loc) · 3.76 KB
/
counter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* Counter metric
*/
'use strict';
const util = require('util');
const {
hashObject,
isObject,
getLabels,
removeLabels,
nowTimestamp,
} = require('./util');
const { validateLabel } = require('./validation');
const { Metric } = require('./metric');
const Exemplar = require('./exemplar');
class Counter extends Metric {
constructor(config) {
super(config);
this.type = 'counter';
this.defaultLabels = {};
this.defaultValue = 1;
this.defaultExemplarLabelSet = {};
if (config.enableExemplars) {
this.enableExemplars = true;
this.inc = this.incWithExemplar;
} else {
this.inc = this.incWithoutExemplar;
}
}
/**
* Increment counter
* @param {object} labels - What label you want to be incremented
* @param {Number} value - Value to increment, if omitted increment with 1
* @returns {object} results - object with information about the inc operation
* @returns {string} results.labelHash - hash representation of the labels
*/
incWithoutExemplar(labels, value) {
let hash = '';
if (isObject(labels)) {
hash = hashObject(labels, this.sortedLabelNames);
validateLabel(this.labelNames, labels);
} else {
value = labels;
labels = {};
}
if (value && !Number.isFinite(value)) {
throw new TypeError(`Value is not a valid number: ${util.format(value)}`);
}
if (value < 0) {
throw new Error('It is not possible to decrease a counter');
}
if (value === null || value === undefined) value = 1;
setValue(this.hashMap, value, labels, hash);
return { labelHash: hash };
}
/**
* Increment counter with exemplar, same as inc but accepts labels for an
* exemplar.
* If no label is provided the current exemplar labels are kept unchanged
* (defaults to empty set).
*
* @param {object} incOpts - Object with options about what metric to increase
* @param {object} incOpts.labels - What label you want to be incremented,
* defaults to null (metric with no labels)
* @param {Number} incOpts.value - Value to increment, defaults to 1
* @param {object} incOpts.exemplarLabels - Key-value labels for the
* exemplar, defaults to empty set {}
* @returns {void}
*/
incWithExemplar({
labels = this.defaultLabels,
value = this.defaultValue,
exemplarLabels = this.defaultExemplarLabelSet,
} = {}) {
const res = this.incWithoutExemplar(labels, value);
this.updateExemplar(exemplarLabels, value, res.labelHash);
}
updateExemplar(exemplarLabels, value, hash) {
if (!isObject(this.hashMap[hash].exemplar)) {
this.hashMap[hash].exemplar = new Exemplar();
}
this.hashMap[hash].exemplar.validateExemplarLabelSet(exemplarLabels);
this.hashMap[hash].exemplar.labelSet = exemplarLabels;
this.hashMap[hash].exemplar.value = value ? value : 1;
this.hashMap[hash].exemplar.timestamp = nowTimestamp();
}
/**
* Reset counter
* @returns {void}
*/
reset() {
this.hashMap = {};
if (this.labelNames.length === 0) {
setValue(this.hashMap, 0);
}
}
async get() {
if (this.collect) {
const v = this.collect();
if (v instanceof Promise) await v;
}
return {
help: this.help,
name: this.name,
type: this.type,
values: Object.values(this.hashMap),
aggregator: this.aggregator,
};
}
labels(...args) {
const labels = getLabels(this.labelNames, args) || {};
return {
inc: this.inc.bind(this, labels),
};
}
remove(...args) {
const labels = getLabels(this.labelNames, args) || {};
validateLabel(this.labelNames, labels);
return removeLabels.call(this, this.hashMap, labels, this.sortedLabelNames);
}
}
function setValue(hashMap, value, labels = {}, hash = '') {
if (hashMap[hash]) {
hashMap[hash].value += value;
} else {
hashMap[hash] = { value, labels };
}
return hashMap;
}
module.exports = Counter;