-
Notifications
You must be signed in to change notification settings - Fork 3
/
metrics.js
116 lines (99 loc) · 3.11 KB
/
metrics.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
'use strict';
const http = require('http');
const url = require('url');
const fs = require('fs');
const stream = require('stream');
const blocked = require('blocked');
const pidusage = require('pidusage');
const path = require('path');
if (process.env.NODE_ENV === 'dev') {
require('dotenv').config({
path: path.resolve(__dirname, '.env')
});
}
const INFLUXDB_URL = process.env.INFLUXDB_URL;
const METRICS_DATABASE = process.env.METRICS_DB;
const REGION = process.env.REGION;
function streamify(text) {
const s = new stream.Readable();
s.push(text);
s.push(null);
return s;
}
function pushMetric(metricName, value) {
const influxURL = new url.URL(INFLUXDB_URL);
const options = {
protocol: influxURL.protocol,
host: influxURL.hostname,
port: influxURL.port,
path: `${influxURL.pathname}${influxURL.search}`,
method: 'POST'
};
streamify(`${metricName},host=${process.pid},region=${REGION} value=${value} ${Date.now() * 1000000}\n`)
.pipe(http.request(options)).on('error', () => {});
}
let blockedTimer;
let generalMetricsTimer;
const enableEventLoopMetric = () => {
blockedTimer = blocked(ms => pushMetric('event_loop', ms), { threshold: 1 });
};
const clear = () => {
clearInterval(blockedTimer);
clearInterval(generalMetricsTimer);
};
const toggle = () => {
if (process.debugMode === true) {
process.debugMode = false;
clear();
console.log('[debug] stopped metrics collection');
} else {
process.debugMode = true;
enableEventLoopMetric();
enableGenericMetrics();
console.log('[debug] enabled metrics collection');
}
};
const getMaximumFileDescriptors = () => {
return new Promise((resolve, reject) => {
fs.readFile('/proc/sys/fs/file-max', 'utf8', (err, maxFds) => {
if (err) {
return reject(err);
}
resolve(Number(maxFds));
});
});
};
const getOpenFileDescriptors = () => {
return new Promise((resolve, reject) => {
fs.readdir('/proc/self/fd', (err, list) => {
if (err) {
return reject(err);
}
// Minus 1, as this invocation created one
resolve(list.length - 1);
});
});
};
const metricsInterval = process.env.METRICS_INTERVAL || 3000;
const enableGenericMetrics = () => {
generalMetricsTimer = setInterval(() => {
pushMetric('uptime', process.uptime());
pushMetric('active_requests', process._getActiveRequests().length);
pushMetric('active_handlles', process._getActiveHandles().length);
const mem = process.memoryUsage();
pushMetric('memory_rss', mem.rss);
pushMetric('memory_heapTotal', mem.heapTotal);
pushMetric('memory_heapUsed', mem.heapUsed);
pushMetric('memory_external', mem.external);
pidusage(process.pid, (err, stats) => {
if (err) return err;
pushMetric('cpu_usage', stats.cpu);
});
pushMetric('nodejs_version', `\"${process.versions.node}\"`);
pushMetric('v8_version', `\"${process.versions.v8}\"`);
getMaximumFileDescriptors().then(res => pushMetric('max_fds', res));
getOpenFileDescriptors().then(res => pushMetric('open_fds', res));
}, metricsInterval);
};
toggle();
process.on('SIGUSR2', toggle);