-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
122 lines (106 loc) · 3.34 KB
/
index.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
const urlParse = require('url').parse;
const onHeaders = require('on-headers');
const { v4: uuidv4 } = require('uuid');
const { parse } = require('regexparam');
const prettyTime = require('pretty-time');
const { hrTimeToMs } = require('./utils');
function initMiddleware(opts = {}) {
const stats = {
uuid: uuidv4(),
pid: process.pid,
totalTime: 0,
averageTime: 0,
count: 0,
};
const statusCodes = {};
const endpointStats = {};
const complexEndpoints =
(opts.complexEndpoints &&
opts.complexEndpoints.map((path) => ({ ...parse(path), path }))) ||
[];
const customStats = {};
function getStats() {
const result = {
uptime: process.uptime() * 1e3, // convert to ms
uptimeHumanReadable: prettyTime(Math.floor(process.uptime() * 1e9)),
statusCodes,
...stats,
};
if (opts.endpointStats) {
result.endpointStats = endpointStats;
}
if (opts.customStats) {
result.customStats = customStats;
}
return result;
}
function startMeasurement(name) {
if (!customStats[name]) {
customStats[name] = {
totalTime: 0,
averageTime: 0,
started: 0,
count: 0,
};
}
customStats[name].started++;
return { start: process.hrtime(), name };
}
function finishMeasurement({ name, start }) {
const time = hrTimeToMs(process.hrtime(start));
customStats[name].totalTime += time;
customStats[name].count++;
customStats[name].averageTime =
customStats[name].totalTime / customStats[name].count;
}
function statsMiddleware(req, res, next) {
const requestStart = process.hrtime();
if (opts.customStats) {
req.startMeasurement = startMeasurement;
req.finishMeasurement = finishMeasurement;
}
onHeaders(res, () => {
const time = hrTimeToMs(process.hrtime(requestStart));
if (opts.addHeader) {
if (!res.getHeader('X-Response-Time')) {
res.setHeader('X-Response-Time', `${time.toFixed(0)}ms`);
}
}
stats.totalTime += time;
stats.count++;
stats.averageTime = stats.totalTime / stats.count;
statusCodes[res.statusCode] = statusCodes[res.statusCode]
? statusCodes[res.statusCode] + 1
: 1;
if (opts.endpointStats) {
// prefer using `req.originalUrl` as some frameworks replace `req.url`
const url = req.originalUrl || req.url;
let path = urlParse(url).pathname;
const complexPath = complexEndpoints.find((endpoint) =>
endpoint.pattern.test(path)
);
path = complexPath ? complexPath.path : path;
const endpoint = `${req.method} ${path}`;
if (!endpointStats[endpoint]) {
endpointStats[endpoint] = {
totalTime: 0,
averageTime: 0,
count: 0,
statusCodes: {},
};
}
endpointStats[endpoint].totalTime += time;
endpointStats[endpoint].count++;
endpointStats[endpoint].averageTime =
endpointStats[endpoint].totalTime / endpointStats[endpoint].count;
const eStatusCodes = endpointStats[endpoint].statusCodes;
eStatusCodes[res.statusCode] = eStatusCodes[res.statusCode]
? eStatusCodes[res.statusCode] + 1
: 1;
}
});
return next();
}
return { getStats, statsMiddleware };
}
module.exports = initMiddleware;