@emartech/aggregate-metric-logger 1.0.1 → 2.0.2
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 +12 -12
- package/package.json +2 -3
- package/src/metric-logger.js +3 -19
- package/src/metric-logger.spec.js +20 -36
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ metricLogger.warn('etwas-went-wrong', { customer_id: 11 });
|
|
|
29
29
|
|
|
30
30
|
### Measure values
|
|
31
31
|
|
|
32
|
-
If you want aggregate
|
|
32
|
+
If you want aggregate measurements about something you need to simply call the `measure` method
|
|
33
33
|
for each value:
|
|
34
34
|
|
|
35
35
|
```js
|
|
@@ -44,16 +44,16 @@ for each measured tags. (Uses `@emartech/json-logger` behind the scenes for logg
|
|
|
44
44
|
|
|
45
45
|
### Measuring durations
|
|
46
46
|
|
|
47
|
-
For duration
|
|
47
|
+
For duration measurements, there are two convenient methods: `start`, and `stop`;
|
|
48
48
|
|
|
49
49
|
You start the measurement with `start`, the counted value for aggregation will be the duration
|
|
50
|
-
between this `start` and the
|
|
50
|
+
between this `start` and the matching `stop` call;
|
|
51
51
|
|
|
52
52
|
```js
|
|
53
53
|
function exampleIOHeavyFunction() {
|
|
54
|
-
const
|
|
54
|
+
const measurement = metricLogger.start('tag-for-the-measuement');
|
|
55
55
|
const result = db.findItems();
|
|
56
|
-
metricLogger.stop(
|
|
56
|
+
metricLogger.stop(measurement);
|
|
57
57
|
return result;
|
|
58
58
|
}
|
|
59
59
|
```
|
|
@@ -61,20 +61,20 @@ function exampleIOHeavyFunction() {
|
|
|
61
61
|
### Group by extra parameters
|
|
62
62
|
|
|
63
63
|
If you want to group by additional parameters inside a tag, you can pass down these extra
|
|
64
|
-
params in an object to `
|
|
64
|
+
params in an object to `measure` and `start` as the last optional argument:
|
|
65
65
|
|
|
66
66
|
```js
|
|
67
|
-
metricLogger.
|
|
67
|
+
metricLogger.measure('thing-to-count', 14, { customer_id: 12 });
|
|
68
68
|
|
|
69
|
-
const
|
|
69
|
+
const measurement = metricLogger.start(
|
|
70
70
|
'tag-for-the-measuement',
|
|
71
71
|
{ event_type: 'nyul', account: 3 }
|
|
72
72
|
);
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
A
|
|
76
|
-
and these extra params will appended to the log entry.
|
|
75
|
+
A separate log entry will be created for each seen value combinations seen in the extra params
|
|
76
|
+
and these extra params will be appended to the log entry.
|
|
77
77
|
|
|
78
|
-
Be very
|
|
79
|
-
If you include too many parameters, you could
|
|
78
|
+
Be very careful when using extra params, and only include information you really need.
|
|
79
|
+
If you include too many parameters, you could lose the advantage you gain by aggregating your logs
|
|
80
80
|
with this package.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emartech/aggregate-metric-logger",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "aggregate metrics in memory for logging",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -32,8 +32,7 @@
|
|
|
32
32
|
"@emartech/json-logger": "^3.1.0",
|
|
33
33
|
"date-fns": "^2.3.0",
|
|
34
34
|
"json-stable-stringify": "^1.0.1",
|
|
35
|
-
"lodash": "^4.17.15"
|
|
36
|
-
"uuid": "8.3.2"
|
|
35
|
+
"lodash": "^4.17.15"
|
|
37
36
|
},
|
|
38
37
|
"devDependencies": {
|
|
39
38
|
"@sinonjs/fake-timers": "9.1.1",
|
package/src/metric-logger.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { v4: uuid } = require('uuid');
|
|
4
3
|
const loggerFactory = require('@emartech/json-logger');
|
|
5
4
|
const { getSeconds, startOfMinute, addSeconds } = require('date-fns');
|
|
6
5
|
const { omit, pick, fromPairs, toPairs } = require('lodash');
|
|
@@ -9,22 +8,16 @@ const util = require('util');
|
|
|
9
8
|
|
|
10
9
|
module.exports = ({
|
|
11
10
|
enabled = true,
|
|
12
|
-
namespace = 'aggregate-metric-logger'
|
|
13
|
-
inProgressMeasurementWarningLimit = 10000
|
|
11
|
+
namespace = 'aggregate-metric-logger'
|
|
14
12
|
} = {}) => {
|
|
15
13
|
const logger = loggerFactory(namespace);
|
|
16
14
|
|
|
17
15
|
const thresholdsByTag = {};
|
|
18
|
-
let measurements = {};
|
|
19
16
|
let metrics = {};
|
|
20
17
|
let initialized = false;
|
|
21
18
|
|
|
22
19
|
const flush = () => {
|
|
23
20
|
logMetrics();
|
|
24
|
-
const inProgressMeasurementCount = Object.keys(measurements).length;
|
|
25
|
-
if (inProgressMeasurementCount > inProgressMeasurementWarningLimit) {
|
|
26
|
-
logger.warn('too-many-in-progress-metric-log-measurements', { count: inProgressMeasurementCount });
|
|
27
|
-
}
|
|
28
21
|
metrics = {};
|
|
29
22
|
setupNextFlush();
|
|
30
23
|
};
|
|
@@ -124,22 +117,13 @@ module.exports = ({
|
|
|
124
117
|
addMeasurement({ method: 'fatal', tag, params, value: 1, countOnly: true });
|
|
125
118
|
},
|
|
126
119
|
start(tag, params = {}) {
|
|
127
|
-
|
|
128
|
-
measurements[id] = { tag, params, start: Date.now() };
|
|
129
|
-
return id;
|
|
120
|
+
return { tag, params, start: Date.now() };
|
|
130
121
|
},
|
|
131
|
-
stop(
|
|
132
|
-
const measurement = measurements[measurementId];
|
|
133
|
-
if (!measurement) return;
|
|
134
|
-
|
|
122
|
+
stop(measurement) {
|
|
135
123
|
addMeasurement({
|
|
136
124
|
...pick(measurement, ['tag', 'params']),
|
|
137
125
|
value: Date.now() - measurement.start
|
|
138
126
|
});
|
|
139
|
-
delete measurements[measurementId];
|
|
140
|
-
},
|
|
141
|
-
cancel(measurementId) {
|
|
142
|
-
delete measurements[measurementId];
|
|
143
127
|
}
|
|
144
128
|
};
|
|
145
129
|
};
|
|
@@ -15,7 +15,7 @@ beforeEach(() => {
|
|
|
15
15
|
afterEach(() => clock.uninstall());
|
|
16
16
|
|
|
17
17
|
describe('metricLogger', () => {
|
|
18
|
-
describe('measure', () => {
|
|
18
|
+
describe('#measure', () => {
|
|
19
19
|
it('should log a single measurement at the next flush period', () => {
|
|
20
20
|
metricLogger.measure('elfogyasztot-tap', 4);
|
|
21
21
|
|
|
@@ -124,6 +124,17 @@ describe('metricLogger', () => {
|
|
|
124
124
|
});
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
+
describe('#start', () => {
|
|
128
|
+
it('should return a measurement object with the given tag, params and start time', () => {
|
|
129
|
+
const fakeCurrentTimestamp = 2323434543;
|
|
130
|
+
clock.setSystemTime(fakeCurrentTimestamp);
|
|
131
|
+
|
|
132
|
+
const measurement = metricLogger.start('test-tag', { foo: 'bar' });
|
|
133
|
+
|
|
134
|
+
expect(measurement).toEqual({ tag: 'test-tag', params: { foo: 'bar' }, start: fakeCurrentTimestamp });
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
127
138
|
describe('start/stop', () => {
|
|
128
139
|
it('should log min, max, count and sum when log was called only once', () => {
|
|
129
140
|
const measurementId = metricLogger.start('utlegeles');
|
|
@@ -142,12 +153,12 @@ describe('metricLogger', () => {
|
|
|
142
153
|
});
|
|
143
154
|
|
|
144
155
|
it('should aggregate metrics for two measurements and log after a timeout', () => {
|
|
145
|
-
const
|
|
146
|
-
const
|
|
156
|
+
const measurement1 = metricLogger.start('utlegeles');
|
|
157
|
+
const measurement2 = metricLogger.start('utlegeles');
|
|
147
158
|
clock.tick(50);
|
|
148
|
-
metricLogger.stop(
|
|
159
|
+
metricLogger.stop(measurement1);
|
|
149
160
|
clock.tick(20);
|
|
150
|
-
metricLogger.stop(
|
|
161
|
+
metricLogger.stop(measurement2);
|
|
151
162
|
|
|
152
163
|
clock.tick(60 * 1000);
|
|
153
164
|
expect(Logger.prototype.info).toBeCalledWith('utlegeles', {
|
|
@@ -160,24 +171,9 @@ describe('metricLogger', () => {
|
|
|
160
171
|
});
|
|
161
172
|
});
|
|
162
173
|
|
|
163
|
-
it('should not count a measurment if it is cancelled with cancel', () => {
|
|
164
|
-
const measurement1Id = metricLogger.start('utlegeles');
|
|
165
|
-
const measurement2Id = metricLogger.start('utlegeles');
|
|
166
|
-
clock.tick(50);
|
|
167
|
-
metricLogger.stop(measurement1Id);
|
|
168
|
-
clock.tick(20);
|
|
169
|
-
metricLogger.cancel(measurement2Id);
|
|
170
|
-
metricLogger.stop(measurement2Id);
|
|
171
|
-
|
|
172
|
-
clock.tick(60 * 1000);
|
|
173
|
-
expect(Logger.prototype.info).toBeCalledWith('utlegeles', expect.objectContaining({
|
|
174
|
-
count: 1
|
|
175
|
-
}));
|
|
176
|
-
});
|
|
177
|
-
|
|
178
174
|
it('should flush results at the closes minute:30', () => {
|
|
179
|
-
const
|
|
180
|
-
metricLogger.stop(
|
|
175
|
+
const measurement = metricLogger.start('utlegeles');
|
|
176
|
+
metricLogger.stop(measurement);
|
|
181
177
|
|
|
182
178
|
clock.tick(29 * 1000 + 999);
|
|
183
179
|
expect(Logger.prototype.info).not.toBeCalled();
|
|
@@ -187,8 +183,8 @@ describe('metricLogger', () => {
|
|
|
187
183
|
|
|
188
184
|
it('should flush at next minute:30 if we are after 30 in current minute', () => {
|
|
189
185
|
clock.tick(45 * 1000);
|
|
190
|
-
const
|
|
191
|
-
metricLogger.stop(
|
|
186
|
+
const measurement = metricLogger.start('utlegeles');
|
|
187
|
+
metricLogger.stop(measurement);
|
|
192
188
|
|
|
193
189
|
clock.tick(44 * 1000);
|
|
194
190
|
expect(Logger.prototype.info).not.toBeCalled();
|
|
@@ -253,18 +249,6 @@ describe('metricLogger', () => {
|
|
|
253
249
|
is_metric: true
|
|
254
250
|
});
|
|
255
251
|
});
|
|
256
|
-
|
|
257
|
-
it('should log warning if there are too many measurements in progress', () => {
|
|
258
|
-
jest.spyOn(Logger.prototype, 'warn');
|
|
259
|
-
const metricLogger = metricLoggerFactory({ inProgressMeasurementWarningLimit: 1 });
|
|
260
|
-
|
|
261
|
-
metricLogger.measure('kacsa');
|
|
262
|
-
metricLogger.start('nyavogas');
|
|
263
|
-
metricLogger.start('nyavogas');
|
|
264
|
-
clock.tick(60 * 1000);
|
|
265
|
-
|
|
266
|
-
expect(Logger.prototype.warn).toBeCalledWith('too-many-in-progress-metric-log-measurements', { count: 2 });
|
|
267
|
-
});
|
|
268
252
|
});
|
|
269
253
|
|
|
270
254
|
describe('simple count one log methods', () => {
|