@emartech/aggregate-metric-logger 5.2.1 → 6.0.0
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 +9 -47
- package/package.json +3 -5
- package/renovate.json +6 -0
- package/src/gcp-metric-collector/gcp-metric-collector.js +2 -6
- package/src/gcp-metric-collector/gcp-metric-collector.spec.js +1 -1
- package/src/gcp-time-series-builder/gcp-time-series-builder.js +2 -2
- package/src/gcp-time-series-publisher/gcp-time-series-publisher.js +2 -2
- package/src/index.js +7 -27
- package/src/laas-metric-logger/laas-metric-logger.js +0 -124
- package/src/laas-metric-logger/laas-metric-logger.spec.js +0 -271
package/README.md
CHANGED
|
@@ -1,42 +1,28 @@
|
|
|
1
1
|
# aggregate-metric-logger
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
Aggregate metrics in memory and send them to GCP them every minute.
|
|
3
4
|
|
|
4
5
|
## Setup
|
|
5
6
|
|
|
6
7
|
Set `METRIC_LOGGER_ENABLED` env variable to `true` for aggregate-metric-logger to
|
|
7
8
|
start collecting and logging measurements.
|
|
8
9
|
|
|
9
|
-
To change the default `aggregate-metric-logger` namespace used for logs, set
|
|
10
|
-
`METRIC_LOGGER_NAMESPACE` to a custom value.
|
|
11
|
-
|
|
12
|
-
## Setup to send metrics to GCP monitoring
|
|
13
|
-
|
|
14
|
-
(currently only the `metricLogger.count` and `metricLogger.measureGcp` methods send metrics to GCP)
|
|
15
|
-
|
|
16
|
-
Set `METRIC_LOGGER_ENABLED` just us for LaaS based metrics.
|
|
17
|
-
|
|
18
10
|
Set `MONITORING_PROJECT_ID` and `GCP_CREDENTIALS` env variables. `HOSTNAME` env variable also has to be
|
|
19
11
|
set, but for a pod running on kubernetes this should already be set.
|
|
20
12
|
|
|
21
13
|
Add `Monitoring Metrics Writer` Role to the service account in the GCP project.
|
|
22
14
|
|
|
23
|
-
|
|
24
15
|
## Usage
|
|
25
16
|
|
|
26
|
-
|
|
27
|
-
`trace`, `debug`, `info`, `warn`, `error` and `fatal`.
|
|
28
|
-
|
|
29
|
-
When these are called, it will aggregate logs with the same parameters withing a minute, add
|
|
30
|
-
an extra `count` property to the logs and log them at the end of the minute with
|
|
31
|
-
`@emartech/json-logger`.
|
|
17
|
+
### Count occurrences
|
|
32
18
|
|
|
33
19
|
```js
|
|
34
20
|
const metricLogger = require('@emartech/aggregate-metric-logger')
|
|
35
21
|
|
|
36
|
-
metricLogger.
|
|
37
|
-
metricLogger.
|
|
22
|
+
metricLogger.count('etwas-went-wrong', { customer_id: 11 });
|
|
23
|
+
metricLogger.count('etwas-went-wrong', { customer_id: 11 });
|
|
38
24
|
|
|
39
|
-
// will aggregate these to a single
|
|
25
|
+
// will aggregate these to a single metric
|
|
40
26
|
```
|
|
41
27
|
|
|
42
28
|
### Measure values
|
|
@@ -47,13 +33,10 @@ for each value:
|
|
|
47
33
|
```js
|
|
48
34
|
const metricLogger = require('@emartech/aggregate-metric-logger')
|
|
49
35
|
|
|
50
|
-
metricLogger.measure('thing-to-measure', 14)
|
|
51
|
-
metricLogger.measure('thing-to-measure', 20)
|
|
36
|
+
metricLogger.measure('thing-to-measure', 14, { customer_id: 12 })
|
|
37
|
+
metricLogger.measure('thing-to-measure', 20, { customer_id: 44 })
|
|
52
38
|
```
|
|
53
39
|
|
|
54
|
-
Every minute metric logger will log `min`, `max`, `sum`, `count` and `average` aggregated metrics
|
|
55
|
-
for each measured tags. (Uses `@emartech/json-logger` behind the scenes for logging).
|
|
56
|
-
|
|
57
40
|
### Measuring durations
|
|
58
41
|
|
|
59
42
|
For duration measurements, there are two convenient methods: `start`, and `stop`;
|
|
@@ -63,30 +46,9 @@ between this `start` and the matching `stop` call;
|
|
|
63
46
|
|
|
64
47
|
```js
|
|
65
48
|
function exampleIOHeavyFunction() {
|
|
66
|
-
const measurement = metricLogger.start('tag-for-the-measuement');
|
|
49
|
+
const measurement = metricLogger.start('tag-for-the-measuement', { customer_id: 23 });
|
|
67
50
|
const result = db.findItems();
|
|
68
51
|
metricLogger.stop(measurement);
|
|
69
52
|
return result;
|
|
70
53
|
}
|
|
71
54
|
```
|
|
72
|
-
|
|
73
|
-
### Group by extra parameters
|
|
74
|
-
|
|
75
|
-
If you want to group by additional parameters inside a tag, you can pass down these extra
|
|
76
|
-
params in an object to `measure` and `start` as the last optional argument:
|
|
77
|
-
|
|
78
|
-
```js
|
|
79
|
-
metricLogger.measure('thing-to-count', 14, { customer_id: 12 });
|
|
80
|
-
|
|
81
|
-
const measurement = metricLogger.start(
|
|
82
|
-
'tag-for-the-measuement',
|
|
83
|
-
{ event_type: 'nyul', account: 3 }
|
|
84
|
-
);
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
A separate log entry will be created for each seen value combinations seen in the extra params
|
|
88
|
-
and these extra params will be appended to the log entry.
|
|
89
|
-
|
|
90
|
-
Be very careful when using extra params, and only include information you really need.
|
|
91
|
-
If you include too many parameters, you could lose the advantage you gain by aggregating your logs
|
|
92
|
-
with this package.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emartech/aggregate-metric-logger",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "aggregate metrics in memory for logging",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -31,18 +31,16 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@emartech/json-logger": "^8.0.3",
|
|
33
33
|
"@google-cloud/monitoring": "^4.1.0",
|
|
34
|
-
"date-fns": "^3.6.0",
|
|
35
34
|
"json-stable-stringify": "^1.1.1",
|
|
36
35
|
"lodash": "^4.17.15",
|
|
37
36
|
"ms": "^2.1.3"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
40
|
-
"@emartech/rti-server-tools": "^
|
|
41
|
-
"@sinonjs/fake-timers": "^11.2.2",
|
|
39
|
+
"@emartech/rti-server-tools": "^7.9.5",
|
|
42
40
|
"@types/jest": "^29.5.12",
|
|
43
41
|
"dotenv-haphap": "^3.1.2",
|
|
44
42
|
"eslint": "^9.7.0",
|
|
45
|
-
"globals": "
|
|
43
|
+
"globals": "16.0.0",
|
|
46
44
|
"jest": "^29.2.2",
|
|
47
45
|
"semantic-release": "^24.0.0"
|
|
48
46
|
}
|
package/renovate.json
ADDED
|
@@ -79,13 +79,9 @@ class GcpMetricCollector {
|
|
|
79
79
|
await createGcpTimeSeriesPublisher(this.projectId).publishTimeSeries(timeSeries);
|
|
80
80
|
this.setupNextFlush();
|
|
81
81
|
}
|
|
82
|
-
|
|
83
|
-
createGcpMetricsCollector(projectId) {
|
|
84
|
-
return new GcpMetricCollector(projectId);
|
|
85
|
-
}
|
|
86
82
|
}
|
|
87
83
|
|
|
88
|
-
const collector = new GcpMetricCollector()
|
|
84
|
+
const collector = new GcpMetricCollector();
|
|
89
85
|
|
|
90
86
|
exports.count = (metricName, labels = {}, value = 1) =>
|
|
91
87
|
collector.count(metricName, labels, value);
|
|
@@ -99,4 +95,4 @@ exports.stop = measurement => collector.stop(measurement);
|
|
|
99
95
|
|
|
100
96
|
exports.reset = () => collector.reset();
|
|
101
97
|
|
|
102
|
-
exports.createGcpMetricsCollector = projectId => new GcpMetricCollector(projectId)
|
|
98
|
+
exports.createGcpMetricsCollector = projectId => new GcpMetricCollector(projectId);
|
|
@@ -36,9 +36,9 @@ class GcpTimeSeriesBuilder {
|
|
|
36
36
|
|
|
37
37
|
exports.createGcpTimeSeriesBuilder = projectId => {
|
|
38
38
|
return new GcpTimeSeriesBuilder(projectId);
|
|
39
|
-
}
|
|
39
|
+
};
|
|
40
40
|
|
|
41
41
|
exports.buildTimeSeries = metrics => {
|
|
42
42
|
const builder = new GcpTimeSeriesBuilder();
|
|
43
43
|
return builder.buildTimeSeries(metrics);
|
|
44
|
-
}
|
|
44
|
+
};
|
|
@@ -47,9 +47,9 @@ class GcpTimeSeriesPublisher {
|
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
exports.createGcpTimeSeriesPublisher = projectId => new GcpTimeSeriesPublisher(projectId)
|
|
50
|
+
exports.createGcpTimeSeriesPublisher = projectId => new GcpTimeSeriesPublisher(projectId);
|
|
51
51
|
|
|
52
52
|
exports.publishTimeSeries = async timeSeries => {
|
|
53
|
-
const publisher = new GcpTimeSeriesPublisher()
|
|
53
|
+
const publisher = new GcpTimeSeriesPublisher();
|
|
54
54
|
await publisher.publishTimeSeries(timeSeries);
|
|
55
55
|
};
|
package/src/index.js
CHANGED
|
@@ -1,31 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const metricLoggerFactory = require('./laas-metric-logger/laas-metric-logger');
|
|
4
3
|
const gcpMetricCollector = require('./gcp-metric-collector/gcp-metric-collector');
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
exposedFactoryInstanceHybrid.setThresholds = exposedInstance.setThresholds;
|
|
15
|
-
exposedFactoryInstanceHybrid.measure = exposedInstance.measure;
|
|
16
|
-
exposedFactoryInstanceHybrid.trace = exposedInstance.trace;
|
|
17
|
-
exposedFactoryInstanceHybrid.debug = exposedInstance.debug;
|
|
18
|
-
exposedFactoryInstanceHybrid.info = exposedInstance.info;
|
|
19
|
-
exposedFactoryInstanceHybrid.warn = exposedInstance.warn;
|
|
20
|
-
exposedFactoryInstanceHybrid.error = exposedInstance.error;
|
|
21
|
-
exposedFactoryInstanceHybrid.fatal = exposedInstance.fatal;
|
|
22
|
-
exposedFactoryInstanceHybrid.start = exposedInstance.start;
|
|
23
|
-
exposedFactoryInstanceHybrid.stop = exposedInstance.stop;
|
|
24
|
-
|
|
25
|
-
exposedFactoryInstanceHybrid.count = gcpMetricCollector.count;
|
|
26
|
-
exposedFactoryInstanceHybrid.measureGcp = gcpMetricCollector.measure;
|
|
27
|
-
exposedFactoryInstanceHybrid.startGcp = gcpMetricCollector.start;
|
|
28
|
-
exposedFactoryInstanceHybrid.stopGcp = gcpMetricCollector.stop;
|
|
29
|
-
exposedFactoryInstanceHybrid.createGcpMetricsCollector = gcpMetricCollector.createGcpMetricsCollector;
|
|
30
|
-
|
|
31
|
-
module.exports = exposedFactoryInstanceHybrid;
|
|
5
|
+
module.exports = {
|
|
6
|
+
count: gcpMetricCollector.count,
|
|
7
|
+
measure: gcpMetricCollector.measure,
|
|
8
|
+
start: gcpMetricCollector.start,
|
|
9
|
+
stop: gcpMetricCollector.stop,
|
|
10
|
+
createGcpMetricsCollector: gcpMetricCollector.createGcpMetricsCollector
|
|
11
|
+
};
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { createLogger } = require('@emartech/json-logger');
|
|
4
|
-
const { getSeconds, startOfMinute, addSeconds } = require('date-fns');
|
|
5
|
-
const { omit, pick, fromPairs, toPairs } = require('lodash');
|
|
6
|
-
const stringify = require('json-stable-stringify');
|
|
7
|
-
|
|
8
|
-
module.exports = ({
|
|
9
|
-
enabled = true,
|
|
10
|
-
namespace = 'aggregate-metric-logger'
|
|
11
|
-
} = {}) => {
|
|
12
|
-
const logger = createLogger(namespace);
|
|
13
|
-
|
|
14
|
-
const thresholdsByTag = {};
|
|
15
|
-
let metrics = {};
|
|
16
|
-
let initialized = false;
|
|
17
|
-
|
|
18
|
-
const flush = () => {
|
|
19
|
-
logMetrics();
|
|
20
|
-
metrics = {};
|
|
21
|
-
setupNextFlush();
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const setupNextFlush = () => {
|
|
25
|
-
const secondsInCurrentMinute = getSeconds(new Date());
|
|
26
|
-
const flushOffset = secondsInCurrentMinute >= 30 ? 90 : 30;
|
|
27
|
-
const targetFlushtime = addSeconds(startOfMinute(new Date()), flushOffset);
|
|
28
|
-
const timeout = targetFlushtime - Date.now();
|
|
29
|
-
setTimeout(flush, timeout);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const incrementThresholdCount = (tag, value, countsSoFar) => {
|
|
33
|
-
const thresholds = thresholdsByTag[tag];
|
|
34
|
-
if (!thresholds) return countsSoFar;
|
|
35
|
-
|
|
36
|
-
return fromPairs(thresholds.map(threshold => {
|
|
37
|
-
const previousCount = countsSoFar[threshold] || 0;
|
|
38
|
-
const newCount = value > threshold ? previousCount + 1 : previousCount;
|
|
39
|
-
return [threshold, newCount];
|
|
40
|
-
}));
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const addMeasurement = ({ tag, value, params, method = 'info', countOnly = false }) => {
|
|
44
|
-
if (!enabled) return;
|
|
45
|
-
|
|
46
|
-
if (!initialized) {
|
|
47
|
-
setupNextFlush();
|
|
48
|
-
initialized = true;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const key = `${tag}_${stringify(params)}`;
|
|
52
|
-
if (!metrics[key]) {
|
|
53
|
-
const metricForKey = { method, tag, ...params, count: 1 };
|
|
54
|
-
if (!countOnly) {
|
|
55
|
-
metricForKey.min = metricForKey.max = metricForKey.sum = metricForKey.average = value;
|
|
56
|
-
metricForKey.thresholdCounts = incrementThresholdCount(tag, value, {});
|
|
57
|
-
}
|
|
58
|
-
metrics[key] = metricForKey;
|
|
59
|
-
} else {
|
|
60
|
-
const metricsSoFar = metrics[key];
|
|
61
|
-
metrics[key].count = metricsSoFar.count + 1;
|
|
62
|
-
if (!countOnly) {
|
|
63
|
-
metrics[key].min = Math.min(metricsSoFar.min, value);
|
|
64
|
-
metrics[key].max = Math.max(metricsSoFar.max, value);
|
|
65
|
-
metrics[key].sum = metricsSoFar.sum + value;
|
|
66
|
-
metrics[key].average = metrics[key].sum / metrics[key].count;
|
|
67
|
-
metrics[key].thresholdCounts = incrementThresholdCount(
|
|
68
|
-
tag,
|
|
69
|
-
value,
|
|
70
|
-
metricsSoFar.thresholdCounts
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const logMetrics = () => {
|
|
77
|
-
Object.values(metrics).forEach(metrics => {
|
|
78
|
-
const params = {
|
|
79
|
-
is_metric: true,
|
|
80
|
-
...omit(metrics, ['tag', 'method', 'thresholdCounts']),
|
|
81
|
-
...fromPairs(
|
|
82
|
-
toPairs(metrics.thresholdCounts).map(([limit, count]) => [`above_${limit}`, count])
|
|
83
|
-
)
|
|
84
|
-
};
|
|
85
|
-
logger[metrics.method](metrics.tag, params);
|
|
86
|
-
});
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
setThresholds(tag, thresholds) {
|
|
91
|
-
thresholdsByTag[tag] = thresholds;
|
|
92
|
-
},
|
|
93
|
-
measure(tag, value, params = {}) {
|
|
94
|
-
addMeasurement({ tag, value, params });
|
|
95
|
-
},
|
|
96
|
-
trace(tag, params = {}) {
|
|
97
|
-
addMeasurement({ method: 'trace', tag, params, value: 1, countOnly: true });
|
|
98
|
-
},
|
|
99
|
-
debug(tag, params = {}) {
|
|
100
|
-
addMeasurement({ method: 'debug', tag, params, value: 1, countOnly: true });
|
|
101
|
-
},
|
|
102
|
-
info(tag, params = {}) {
|
|
103
|
-
addMeasurement({ method: 'info', tag, params, value: 1, countOnly: true });
|
|
104
|
-
},
|
|
105
|
-
warn(tag, params = {}) {
|
|
106
|
-
addMeasurement({ method: 'warn', tag, params, value: 1, countOnly: true });
|
|
107
|
-
},
|
|
108
|
-
error(tag, params = {}) {
|
|
109
|
-
addMeasurement({ method: 'error', tag, params, value: 1, countOnly: true });
|
|
110
|
-
},
|
|
111
|
-
fatal(tag, params = {}) {
|
|
112
|
-
addMeasurement({ method: 'fatal', tag, params, value: 1, countOnly: true });
|
|
113
|
-
},
|
|
114
|
-
start(tag, params = {}) {
|
|
115
|
-
return { tag, params, start: Date.now() };
|
|
116
|
-
},
|
|
117
|
-
stop(measurement) {
|
|
118
|
-
addMeasurement({
|
|
119
|
-
...pick(measurement, ['tag', 'params']),
|
|
120
|
-
value: Date.now() - measurement.start
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
};
|
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { Logger } = require('@emartech/json-logger');
|
|
4
|
-
const fakeTimers = require('@sinonjs/fake-timers');
|
|
5
|
-
const metricLoggerFactory = require('./laas-metric-logger');
|
|
6
|
-
|
|
7
|
-
let metricLogger;
|
|
8
|
-
let clock;
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
jest.spyOn(Logger.prototype, 'info');
|
|
11
|
-
metricLogger = metricLoggerFactory();
|
|
12
|
-
clock = fakeTimers.install();
|
|
13
|
-
});
|
|
14
|
-
afterEach(() => clock.uninstall());
|
|
15
|
-
|
|
16
|
-
describe('metricLogger', () => {
|
|
17
|
-
describe('#measure', () => {
|
|
18
|
-
it('should log a single measurement at the next flush period', () => {
|
|
19
|
-
metricLogger.measure('elfogyasztot-tap', 4);
|
|
20
|
-
|
|
21
|
-
clock.tick(60 * 1000 + 1);
|
|
22
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('elfogyasztot-tap', {
|
|
23
|
-
min: 4,
|
|
24
|
-
max: 4,
|
|
25
|
-
count: 1,
|
|
26
|
-
sum: 4,
|
|
27
|
-
average: 4,
|
|
28
|
-
is_metric: true
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should aggregate measurements withing a flush period', () => {
|
|
33
|
-
metricLogger.measure('elfogyasztot-tap', 4);
|
|
34
|
-
metricLogger.measure('elfogyasztot-tap', 8);
|
|
35
|
-
metricLogger.measure('kacsa-cucc', 18);
|
|
36
|
-
|
|
37
|
-
clock.tick(60 * 1000 + 1);
|
|
38
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('elfogyasztot-tap', {
|
|
39
|
-
min: 4,
|
|
40
|
-
max: 8,
|
|
41
|
-
count: 2,
|
|
42
|
-
sum: 12,
|
|
43
|
-
average: 6,
|
|
44
|
-
is_metric: true
|
|
45
|
-
});
|
|
46
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('kacsa-cucc', {
|
|
47
|
-
min: 18,
|
|
48
|
-
max: 18,
|
|
49
|
-
count: 1,
|
|
50
|
-
sum: 18,
|
|
51
|
-
average: 18,
|
|
52
|
-
is_metric: true
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should log counts for each combination of extra params provedid within a tag', () => {
|
|
57
|
-
metricLogger.measure('elfogyasztot-tap', 4, { emberke: 'bela' });
|
|
58
|
-
metricLogger.measure('elfogyasztot-tap', 8, { emberke: 'bela' });
|
|
59
|
-
metricLogger.measure('elfogyasztot-tap', 18, { emberke: 'jano' });
|
|
60
|
-
|
|
61
|
-
clock.tick(60 * 1000 + 1);
|
|
62
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('elfogyasztot-tap', {
|
|
63
|
-
min: 4,
|
|
64
|
-
max: 8,
|
|
65
|
-
count: 2,
|
|
66
|
-
sum: 12,
|
|
67
|
-
average: 6,
|
|
68
|
-
emberke: 'bela',
|
|
69
|
-
is_metric: true
|
|
70
|
-
});
|
|
71
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('elfogyasztot-tap', {
|
|
72
|
-
min: 18,
|
|
73
|
-
max: 18,
|
|
74
|
-
count: 1,
|
|
75
|
-
sum: 18,
|
|
76
|
-
average: 18,
|
|
77
|
-
emberke: 'jano',
|
|
78
|
-
is_metric: true
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('should group logs with same tag and deeply equal params together', () => {
|
|
83
|
-
metricLogger.measure('elfogyasztot-tap', 4, { a: 1, b: 2 });
|
|
84
|
-
metricLogger.measure('elfogyasztot-tap', 8, { b: 2, a: 1 });
|
|
85
|
-
|
|
86
|
-
clock.tick(60 * 1000 + 1);
|
|
87
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('elfogyasztot-tap', {
|
|
88
|
-
min: 4,
|
|
89
|
-
max: 8,
|
|
90
|
-
count: 2,
|
|
91
|
-
sum: 12,
|
|
92
|
-
average: 6,
|
|
93
|
-
a: 1,
|
|
94
|
-
b: 2,
|
|
95
|
-
is_metric: true
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('should count event distribution within specified thresholds', () => {
|
|
100
|
-
metricLogger.setThresholds('etwas', [5, 10, 20, 1000]);
|
|
101
|
-
|
|
102
|
-
metricLogger.measure('etwas', 2);
|
|
103
|
-
metricLogger.measure('etwas', 3);
|
|
104
|
-
metricLogger.measure('etwas', 4);
|
|
105
|
-
metricLogger.measure('etwas', 6);
|
|
106
|
-
metricLogger.measure('etwas', 11);
|
|
107
|
-
metricLogger.measure('etwas', 12);
|
|
108
|
-
metricLogger.measure('etwas', 816);
|
|
109
|
-
|
|
110
|
-
clock.tick(60 * 1000 + 1);
|
|
111
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('etwas', {
|
|
112
|
-
min: 2,
|
|
113
|
-
max: 816,
|
|
114
|
-
count: 7,
|
|
115
|
-
sum: 854,
|
|
116
|
-
average: 122,
|
|
117
|
-
above_5: 4,
|
|
118
|
-
above_10: 3,
|
|
119
|
-
above_20: 1,
|
|
120
|
-
above_1000: 0,
|
|
121
|
-
is_metric: true
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
describe('#start', () => {
|
|
127
|
-
it('should return a measurement object with the given tag, params and start time', () => {
|
|
128
|
-
const fakeCurrentTimestamp = 2323434543;
|
|
129
|
-
clock.setSystemTime(fakeCurrentTimestamp);
|
|
130
|
-
|
|
131
|
-
const measurement = metricLogger.start('test-tag', { foo: 'bar' });
|
|
132
|
-
|
|
133
|
-
expect(measurement).toEqual({ tag: 'test-tag', params: { foo: 'bar' }, start: fakeCurrentTimestamp });
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
describe('start/stop', () => {
|
|
138
|
-
it('should log min, max, count and sum when log was called only once', () => {
|
|
139
|
-
const measurement = metricLogger.start('utlegeles');
|
|
140
|
-
clock.tick(50);
|
|
141
|
-
metricLogger.stop(measurement);
|
|
142
|
-
|
|
143
|
-
clock.tick(60 * 1000);
|
|
144
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('utlegeles', {
|
|
145
|
-
min: 50,
|
|
146
|
-
max: 50,
|
|
147
|
-
count: 1,
|
|
148
|
-
sum: 50,
|
|
149
|
-
average: 50,
|
|
150
|
-
is_metric: true
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('should aggregate metrics for two measurements and log after a timeout', () => {
|
|
155
|
-
const measurement1 = metricLogger.start('utlegeles');
|
|
156
|
-
const measurement2 = metricLogger.start('utlegeles');
|
|
157
|
-
clock.tick(50);
|
|
158
|
-
metricLogger.stop(measurement1);
|
|
159
|
-
clock.tick(20);
|
|
160
|
-
metricLogger.stop(measurement2);
|
|
161
|
-
|
|
162
|
-
clock.tick(60 * 1000);
|
|
163
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('utlegeles', {
|
|
164
|
-
min: 50,
|
|
165
|
-
max: 70,
|
|
166
|
-
sum: 120,
|
|
167
|
-
count: 2,
|
|
168
|
-
average: 60,
|
|
169
|
-
is_metric: true
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it('should flush results at the closes minute:30', () => {
|
|
174
|
-
const measurement = metricLogger.start('utlegeles');
|
|
175
|
-
metricLogger.stop(measurement);
|
|
176
|
-
|
|
177
|
-
clock.tick(29 * 1000 + 999);
|
|
178
|
-
expect(Logger.prototype.info).not.toHaveBeenCalled();
|
|
179
|
-
clock.tick(1 * 1000);
|
|
180
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('utlegeles', expect.anything());
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it('should flush at next minute:30 if we are after 30 in current minute', () => {
|
|
184
|
-
clock.tick(45 * 1000);
|
|
185
|
-
const measurement = metricLogger.start('utlegeles');
|
|
186
|
-
metricLogger.stop(measurement);
|
|
187
|
-
|
|
188
|
-
clock.tick(44 * 1000);
|
|
189
|
-
expect(Logger.prototype.info).not.toHaveBeenCalled();
|
|
190
|
-
clock.tick(1 * 1000);
|
|
191
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('utlegeles', expect.anything());
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should periodically log measuerments', () => {
|
|
195
|
-
const measurement1 = metricLogger.start('utlegeles');
|
|
196
|
-
const measurement2 = metricLogger.start('utlegeles');
|
|
197
|
-
clock.tick(10 * 1000);
|
|
198
|
-
const measurement3 = metricLogger.start('utlegeles');
|
|
199
|
-
metricLogger.stop(measurement1);
|
|
200
|
-
|
|
201
|
-
clock.tick(21 * 1000);
|
|
202
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('utlegeles', {
|
|
203
|
-
count: 1,
|
|
204
|
-
max: 10000,
|
|
205
|
-
min: 10000,
|
|
206
|
-
sum: 10000,
|
|
207
|
-
average: 10000,
|
|
208
|
-
is_metric: true
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
metricLogger.stop(measurement2);
|
|
212
|
-
metricLogger.stop(measurement3);
|
|
213
|
-
clock.tick(60 * 1000);
|
|
214
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('utlegeles', {
|
|
215
|
-
count: 2,
|
|
216
|
-
max: 31000,
|
|
217
|
-
min: 21000,
|
|
218
|
-
sum: 52000,
|
|
219
|
-
average: 26000,
|
|
220
|
-
is_metric: true
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
it('should log measurements for multiple tags and include extra parameters', () => {
|
|
225
|
-
const measurement1 = metricLogger.start('utlegeles', { a: 21 });
|
|
226
|
-
const measurement2 = metricLogger.start('nyavogas');
|
|
227
|
-
clock.tick(10 * 1000);
|
|
228
|
-
metricLogger.stop(measurement1);
|
|
229
|
-
clock.tick(5 * 1000);
|
|
230
|
-
metricLogger.stop(measurement2);
|
|
231
|
-
clock.tick(15 * 1000);
|
|
232
|
-
|
|
233
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('utlegeles', {
|
|
234
|
-
count: 1,
|
|
235
|
-
max: 10000,
|
|
236
|
-
min: 10000,
|
|
237
|
-
sum: 10000,
|
|
238
|
-
average: 10000,
|
|
239
|
-
a: 21,
|
|
240
|
-
is_metric: true
|
|
241
|
-
});
|
|
242
|
-
expect(Logger.prototype.info).toHaveBeenCalledWith('nyavogas', {
|
|
243
|
-
count: 1,
|
|
244
|
-
max: 15000,
|
|
245
|
-
min: 15000,
|
|
246
|
-
sum: 15000,
|
|
247
|
-
average: 15000,
|
|
248
|
-
is_metric: true
|
|
249
|
-
});
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
describe('simple count one log methods', () => {
|
|
254
|
-
it.each(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])(
|
|
255
|
-
'should log a only the count when %s method is called',
|
|
256
|
-
method => {
|
|
257
|
-
jest.spyOn(Logger.prototype, method);
|
|
258
|
-
|
|
259
|
-
metricLogger[method]('elfogyasztot-tap', { alma: 2 });
|
|
260
|
-
metricLogger[method]('elfogyasztot-tap', { alma: 2 });
|
|
261
|
-
|
|
262
|
-
clock.tick(60 * 1000 + 11500);
|
|
263
|
-
expect(Logger.prototype[method]).toHaveBeenCalledWith('elfogyasztot-tap', {
|
|
264
|
-
count: 2,
|
|
265
|
-
alma: 2,
|
|
266
|
-
is_metric: true
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
);
|
|
270
|
-
});
|
|
271
|
-
});
|