@tramvai/module-metrics 1.61.0 → 1.64.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/lib/request/types.d.ts +3 -1
- package/lib/server.es.js +81 -35
- package/lib/server.js +81 -35
- package/package.json +9 -9
package/lib/request/types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type httpsType from 'https';
|
|
|
5
5
|
import type { Counter, Histogram } from 'prom-client';
|
|
6
6
|
import type { METRICS_MODULE_TOKEN, METRICS_SERVICES_REGISTRY_TOKEN } from '@tramvai/tokens-metrics';
|
|
7
7
|
export declare type ModuleConfig = {
|
|
8
|
-
|
|
8
|
+
enableConnectionResolveMetrics: boolean;
|
|
9
9
|
};
|
|
10
10
|
export declare type MetricsModule = typeof METRICS_MODULE_TOKEN;
|
|
11
11
|
export declare type HttpModule = typeof httpType;
|
|
@@ -16,6 +16,8 @@ export declare type MetricsInstances = {
|
|
|
16
16
|
requestsErrors: Counter<'status' | 'method' | 'service'>;
|
|
17
17
|
requestsDuration: Histogram<'status' | 'method' | 'service'>;
|
|
18
18
|
dnsResolveDuration: Histogram<'service'>;
|
|
19
|
+
tcpConnectDuration: Histogram<'service'>;
|
|
20
|
+
tlsHandshakeDuration: Histogram<'service'>;
|
|
19
21
|
};
|
|
20
22
|
export declare type GetServiceName = typeof METRICS_SERVICES_REGISTRY_TOKEN['getServiceName'];
|
|
21
23
|
export declare type Args = [RequestOptions | string | URL, (res: IncomingMessage) => void] | [string | URL, RequestOptions, (res: IncomingMessage) => void];
|
package/lib/server.es.js
CHANGED
|
@@ -68,43 +68,75 @@ const getUrlAndOptions = (args) => {
|
|
|
68
68
|
const urlWOQuery = parsedUrl.origin + parsedUrl.pathname;
|
|
69
69
|
return [urlWOQuery, options || {}];
|
|
70
70
|
};
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
labelsValues
|
|
83
|
-
|
|
71
|
+
// in seconds
|
|
72
|
+
const getDuration = (current, prev) =>
|
|
73
|
+
// max to avoid negative values and turn that into zero
|
|
74
|
+
prev === 0 ? 0 : Math.max((current - prev) / 1000, 0);
|
|
75
|
+
const createRequestWithMetrics = ({ metricsInstances: { requestsTotal, requestsErrors, requestsDuration, dnsResolveDuration, tcpConnectDuration, tlsHandshakeDuration, }, getServiceName, config, }) => {
|
|
76
|
+
const socketSet = new WeakSet();
|
|
77
|
+
return function requestWithMetrics(originalRequest, ...args) {
|
|
78
|
+
const [url, options] = getUrlAndOptions(args);
|
|
79
|
+
const serviceName = getServiceName(url);
|
|
80
|
+
const req = originalRequest.apply(this, args);
|
|
81
|
+
const timerDone = requestsDuration.startTimer();
|
|
82
|
+
const labelsValues = {
|
|
83
|
+
method: options.method || 'unknown',
|
|
84
|
+
service: serviceName || new URL(url).origin || 'unknown',
|
|
85
|
+
status: 'unknown',
|
|
86
|
+
};
|
|
87
|
+
req.on('response', (res) => {
|
|
88
|
+
labelsValues.status = res.statusCode.toString();
|
|
89
|
+
if (res.statusCode >= 400) {
|
|
90
|
+
requestsErrors.inc(labelsValues);
|
|
91
|
+
}
|
|
92
|
+
requestsTotal.inc(labelsValues);
|
|
93
|
+
timerDone(labelsValues);
|
|
94
|
+
});
|
|
95
|
+
req.on('error', (e) => {
|
|
96
|
+
if (POSSIBLE_ERRORS.includes(e === null || e === void 0 ? void 0 : e.code)) {
|
|
97
|
+
labelsValues.status = e.code;
|
|
98
|
+
}
|
|
99
|
+
requestsTotal.inc(labelsValues);
|
|
84
100
|
requestsErrors.inc(labelsValues);
|
|
85
|
-
|
|
86
|
-
requestsTotal.inc(labelsValues);
|
|
87
|
-
timerDone(labelsValues);
|
|
88
|
-
});
|
|
89
|
-
req.on('error', (e) => {
|
|
90
|
-
if (POSSIBLE_ERRORS.includes(e === null || e === void 0 ? void 0 : e.code)) {
|
|
91
|
-
labelsValues.status = e.code;
|
|
92
|
-
}
|
|
93
|
-
requestsTotal.inc(labelsValues);
|
|
94
|
-
requestsErrors.inc(labelsValues);
|
|
95
|
-
timerDone(labelsValues);
|
|
96
|
-
});
|
|
97
|
-
if (config.enableDnsResolveMetric) {
|
|
98
|
-
req.on('socket', (socket) => {
|
|
99
|
-
const dnsTimerDone = dnsResolveDuration.startTimer();
|
|
100
|
-
socket.on('lookup', () => {
|
|
101
|
-
dnsTimerDone({ service: labelsValues.service });
|
|
102
|
-
});
|
|
101
|
+
timerDone(labelsValues);
|
|
103
102
|
});
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
if (config.enableConnectionResolveMetrics) {
|
|
104
|
+
req.on('socket', (socket) => {
|
|
105
|
+
// due to keep-alive tcp option sockets might be reused
|
|
106
|
+
// ignore them because they have already emitted events we are interested in
|
|
107
|
+
if (socketSet.has(socket)) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
socketSet.add(socket);
|
|
111
|
+
const timings = {
|
|
112
|
+
start: Date.now(),
|
|
113
|
+
lookupEnd: 0,
|
|
114
|
+
connectEnd: 0,
|
|
115
|
+
secureConnectEnd: 0,
|
|
116
|
+
};
|
|
117
|
+
const { service } = labelsValues;
|
|
118
|
+
socket.on('lookup', () => {
|
|
119
|
+
timings.lookupEnd = Date.now();
|
|
120
|
+
dnsResolveDuration.observe({ service }, getDuration(timings.lookupEnd, timings.start));
|
|
121
|
+
});
|
|
122
|
+
socket.on('connect', () => {
|
|
123
|
+
timings.connectEnd = Date.now();
|
|
124
|
+
tcpConnectDuration.observe({ service }, getDuration(timings.connectEnd, timings.lookupEnd));
|
|
125
|
+
});
|
|
126
|
+
socket.on('secureConnect', () => {
|
|
127
|
+
timings.secureConnectEnd = Date.now();
|
|
128
|
+
tlsHandshakeDuration.observe({ service }, getDuration(timings.secureConnectEnd, timings.connectEnd));
|
|
129
|
+
});
|
|
130
|
+
socket.on('close', () => {
|
|
131
|
+
socketSet.delete(socket);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return req;
|
|
136
|
+
};
|
|
106
137
|
};
|
|
107
138
|
|
|
139
|
+
const DEFAULT_BUCKETS = [0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 20, 40, 60];
|
|
108
140
|
const initRequestsMetrics = ({ metrics, getServiceName, http, https, createRequestWithMetrics, config, }) => {
|
|
109
141
|
const metricsInstances = {
|
|
110
142
|
requestsTotal: metrics.counter({
|
|
@@ -121,11 +153,25 @@ const initRequestsMetrics = ({ metrics, getServiceName, http, https, createReque
|
|
|
121
153
|
name: 'http_sent_requests_duration',
|
|
122
154
|
help: 'Execution time of the sent requests',
|
|
123
155
|
labelNames: ['status', 'method', 'service'],
|
|
156
|
+
buckets: DEFAULT_BUCKETS,
|
|
124
157
|
}),
|
|
125
158
|
dnsResolveDuration: metrics.histogram({
|
|
126
159
|
name: 'dns_resolve_duration',
|
|
127
160
|
help: 'Time for dns resolve of the outhgoing requests',
|
|
128
161
|
labelNames: ['service'],
|
|
162
|
+
buckets: DEFAULT_BUCKETS,
|
|
163
|
+
}),
|
|
164
|
+
tcpConnectDuration: metrics.histogram({
|
|
165
|
+
name: 'tcp_connect_duration',
|
|
166
|
+
help: 'Duration of tcp connect of the outgoing requests',
|
|
167
|
+
labelNames: ['service'],
|
|
168
|
+
buckets: DEFAULT_BUCKETS,
|
|
169
|
+
}),
|
|
170
|
+
tlsHandshakeDuration: metrics.histogram({
|
|
171
|
+
name: 'tls_handshake_duration',
|
|
172
|
+
help: 'Duration of tls handshake of the outgoing requests',
|
|
173
|
+
labelNames: ['service'],
|
|
174
|
+
buckets: DEFAULT_BUCKETS,
|
|
129
175
|
}),
|
|
130
176
|
};
|
|
131
177
|
monkeypatch({
|
|
@@ -402,7 +448,7 @@ const eventLoopMetrics = (metrics) => {
|
|
|
402
448
|
const histogram = metrics.histogram({
|
|
403
449
|
name: NODEJS_EVENTLOOP_LAG,
|
|
404
450
|
help: 'Lag of event loop in seconds (setInterval based).',
|
|
405
|
-
buckets: [0.02, 0.1, 0.2, 0.5, 1, 3, 5],
|
|
451
|
+
buckets: [0.02, 0.1, 0.2, 0.5, 1, 3, 5, 7.5, 10],
|
|
406
452
|
});
|
|
407
453
|
startEventLoopLagMeasure(histogram);
|
|
408
454
|
};
|
|
@@ -416,7 +462,7 @@ MetricsModule = __decorate([
|
|
|
416
462
|
provide({
|
|
417
463
|
provide: METRICS_MODULE_CONFIG_TOKEN,
|
|
418
464
|
useValue: {
|
|
419
|
-
|
|
465
|
+
enableConnectionResolveMetrics: false,
|
|
420
466
|
},
|
|
421
467
|
}),
|
|
422
468
|
provide({
|
package/lib/server.js
CHANGED
|
@@ -82,43 +82,75 @@ const getUrlAndOptions = (args) => {
|
|
|
82
82
|
const urlWOQuery = parsedUrl.origin + parsedUrl.pathname;
|
|
83
83
|
return [urlWOQuery, options || {}];
|
|
84
84
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
labelsValues
|
|
97
|
-
|
|
85
|
+
// in seconds
|
|
86
|
+
const getDuration = (current, prev) =>
|
|
87
|
+
// max to avoid negative values and turn that into zero
|
|
88
|
+
prev === 0 ? 0 : Math.max((current - prev) / 1000, 0);
|
|
89
|
+
const createRequestWithMetrics = ({ metricsInstances: { requestsTotal, requestsErrors, requestsDuration, dnsResolveDuration, tcpConnectDuration, tlsHandshakeDuration, }, getServiceName, config, }) => {
|
|
90
|
+
const socketSet = new WeakSet();
|
|
91
|
+
return function requestWithMetrics(originalRequest, ...args) {
|
|
92
|
+
const [url, options] = getUrlAndOptions(args);
|
|
93
|
+
const serviceName = getServiceName(url);
|
|
94
|
+
const req = originalRequest.apply(this, args);
|
|
95
|
+
const timerDone = requestsDuration.startTimer();
|
|
96
|
+
const labelsValues = {
|
|
97
|
+
method: options.method || 'unknown',
|
|
98
|
+
service: serviceName || new URL(url).origin || 'unknown',
|
|
99
|
+
status: 'unknown',
|
|
100
|
+
};
|
|
101
|
+
req.on('response', (res) => {
|
|
102
|
+
labelsValues.status = res.statusCode.toString();
|
|
103
|
+
if (res.statusCode >= 400) {
|
|
104
|
+
requestsErrors.inc(labelsValues);
|
|
105
|
+
}
|
|
106
|
+
requestsTotal.inc(labelsValues);
|
|
107
|
+
timerDone(labelsValues);
|
|
108
|
+
});
|
|
109
|
+
req.on('error', (e) => {
|
|
110
|
+
if (POSSIBLE_ERRORS.includes(e === null || e === void 0 ? void 0 : e.code)) {
|
|
111
|
+
labelsValues.status = e.code;
|
|
112
|
+
}
|
|
113
|
+
requestsTotal.inc(labelsValues);
|
|
98
114
|
requestsErrors.inc(labelsValues);
|
|
99
|
-
|
|
100
|
-
requestsTotal.inc(labelsValues);
|
|
101
|
-
timerDone(labelsValues);
|
|
102
|
-
});
|
|
103
|
-
req.on('error', (e) => {
|
|
104
|
-
if (POSSIBLE_ERRORS.includes(e === null || e === void 0 ? void 0 : e.code)) {
|
|
105
|
-
labelsValues.status = e.code;
|
|
106
|
-
}
|
|
107
|
-
requestsTotal.inc(labelsValues);
|
|
108
|
-
requestsErrors.inc(labelsValues);
|
|
109
|
-
timerDone(labelsValues);
|
|
110
|
-
});
|
|
111
|
-
if (config.enableDnsResolveMetric) {
|
|
112
|
-
req.on('socket', (socket) => {
|
|
113
|
-
const dnsTimerDone = dnsResolveDuration.startTimer();
|
|
114
|
-
socket.on('lookup', () => {
|
|
115
|
-
dnsTimerDone({ service: labelsValues.service });
|
|
116
|
-
});
|
|
115
|
+
timerDone(labelsValues);
|
|
117
116
|
});
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
if (config.enableConnectionResolveMetrics) {
|
|
118
|
+
req.on('socket', (socket) => {
|
|
119
|
+
// due to keep-alive tcp option sockets might be reused
|
|
120
|
+
// ignore them because they have already emitted events we are interested in
|
|
121
|
+
if (socketSet.has(socket)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
socketSet.add(socket);
|
|
125
|
+
const timings = {
|
|
126
|
+
start: Date.now(),
|
|
127
|
+
lookupEnd: 0,
|
|
128
|
+
connectEnd: 0,
|
|
129
|
+
secureConnectEnd: 0,
|
|
130
|
+
};
|
|
131
|
+
const { service } = labelsValues;
|
|
132
|
+
socket.on('lookup', () => {
|
|
133
|
+
timings.lookupEnd = Date.now();
|
|
134
|
+
dnsResolveDuration.observe({ service }, getDuration(timings.lookupEnd, timings.start));
|
|
135
|
+
});
|
|
136
|
+
socket.on('connect', () => {
|
|
137
|
+
timings.connectEnd = Date.now();
|
|
138
|
+
tcpConnectDuration.observe({ service }, getDuration(timings.connectEnd, timings.lookupEnd));
|
|
139
|
+
});
|
|
140
|
+
socket.on('secureConnect', () => {
|
|
141
|
+
timings.secureConnectEnd = Date.now();
|
|
142
|
+
tlsHandshakeDuration.observe({ service }, getDuration(timings.secureConnectEnd, timings.connectEnd));
|
|
143
|
+
});
|
|
144
|
+
socket.on('close', () => {
|
|
145
|
+
socketSet.delete(socket);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return req;
|
|
150
|
+
};
|
|
120
151
|
};
|
|
121
152
|
|
|
153
|
+
const DEFAULT_BUCKETS = [0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 20, 40, 60];
|
|
122
154
|
const initRequestsMetrics = ({ metrics, getServiceName, http, https, createRequestWithMetrics, config, }) => {
|
|
123
155
|
const metricsInstances = {
|
|
124
156
|
requestsTotal: metrics.counter({
|
|
@@ -135,11 +167,25 @@ const initRequestsMetrics = ({ metrics, getServiceName, http, https, createReque
|
|
|
135
167
|
name: 'http_sent_requests_duration',
|
|
136
168
|
help: 'Execution time of the sent requests',
|
|
137
169
|
labelNames: ['status', 'method', 'service'],
|
|
170
|
+
buckets: DEFAULT_BUCKETS,
|
|
138
171
|
}),
|
|
139
172
|
dnsResolveDuration: metrics.histogram({
|
|
140
173
|
name: 'dns_resolve_duration',
|
|
141
174
|
help: 'Time for dns resolve of the outhgoing requests',
|
|
142
175
|
labelNames: ['service'],
|
|
176
|
+
buckets: DEFAULT_BUCKETS,
|
|
177
|
+
}),
|
|
178
|
+
tcpConnectDuration: metrics.histogram({
|
|
179
|
+
name: 'tcp_connect_duration',
|
|
180
|
+
help: 'Duration of tcp connect of the outgoing requests',
|
|
181
|
+
labelNames: ['service'],
|
|
182
|
+
buckets: DEFAULT_BUCKETS,
|
|
183
|
+
}),
|
|
184
|
+
tlsHandshakeDuration: metrics.histogram({
|
|
185
|
+
name: 'tls_handshake_duration',
|
|
186
|
+
help: 'Duration of tls handshake of the outgoing requests',
|
|
187
|
+
labelNames: ['service'],
|
|
188
|
+
buckets: DEFAULT_BUCKETS,
|
|
143
189
|
}),
|
|
144
190
|
};
|
|
145
191
|
monkeypatch__default["default"]({
|
|
@@ -416,7 +462,7 @@ const eventLoopMetrics = (metrics) => {
|
|
|
416
462
|
const histogram = metrics.histogram({
|
|
417
463
|
name: NODEJS_EVENTLOOP_LAG,
|
|
418
464
|
help: 'Lag of event loop in seconds (setInterval based).',
|
|
419
|
-
buckets: [0.02, 0.1, 0.2, 0.5, 1, 3, 5],
|
|
465
|
+
buckets: [0.02, 0.1, 0.2, 0.5, 1, 3, 5, 7.5, 10],
|
|
420
466
|
});
|
|
421
467
|
startEventLoopLagMeasure(histogram);
|
|
422
468
|
};
|
|
@@ -430,7 +476,7 @@ exports.MetricsModule = tslib.__decorate([
|
|
|
430
476
|
core.provide({
|
|
431
477
|
provide: METRICS_MODULE_CONFIG_TOKEN,
|
|
432
478
|
useValue: {
|
|
433
|
-
|
|
479
|
+
enableConnectionResolveMetrics: false,
|
|
434
480
|
},
|
|
435
481
|
}),
|
|
436
482
|
core.provide({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-metrics",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.64.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"browser": "lib/browser.js",
|
|
6
6
|
"main": "lib/server.js",
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
"build-for-publish": "true"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@tramvai/core": "1.
|
|
23
|
-
"@tramvai/tokens-server": "1.
|
|
24
|
-
"@tramvai/tokens-metrics": "1.
|
|
25
|
-
"@tramvai/module-common": "1.
|
|
26
|
-
"@tramvai/tokens-http-client": "1.
|
|
27
|
-
"@tramvai/state": "1.
|
|
28
|
-
"@tramvai/papi": "1.
|
|
29
|
-
"@tinkoff/measure-express-requests": "1.4.
|
|
22
|
+
"@tramvai/core": "1.64.0",
|
|
23
|
+
"@tramvai/tokens-server": "1.64.0",
|
|
24
|
+
"@tramvai/tokens-metrics": "1.64.0",
|
|
25
|
+
"@tramvai/module-common": "1.64.0",
|
|
26
|
+
"@tramvai/tokens-http-client": "1.64.0",
|
|
27
|
+
"@tramvai/state": "1.64.0",
|
|
28
|
+
"@tramvai/papi": "1.64.0",
|
|
29
|
+
"@tinkoff/measure-express-requests": "1.4.3",
|
|
30
30
|
"@tinkoff/monkeypatch": "1.3.3",
|
|
31
31
|
"@tinkoff/url": "0.7.37",
|
|
32
32
|
"@tinkoff/utils": "^2.1.2",
|