@tramvai/module-metrics 5.9.2 → 5.14.9
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 +1 -200
- package/lib/browser.js +2 -3
- package/lib/constants.es.js +3 -1
- package/lib/constants.js +3 -1
- package/lib/instantMetrics/server.es.js +1 -1
- package/lib/instantMetrics/server.js +1 -1
- package/lib/request/MetricsServicesRegistry.es.js +3 -4
- package/lib/request/MetricsServicesRegistry.js +3 -4
- package/lib/request/createRequestWithMetrics.es.js +1 -1
- package/lib/request/createRequestWithMetrics.js +1 -1
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -1,202 +1,3 @@
|
|
|
1
1
|
# @tramvai/module-metrics
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
More details about metrics type, parameters and how to use it see in [docs to `prom-client`](https://github.com/siimon/prom-client).
|
|
6
|
-
|
|
7
|
-
## Explanation
|
|
8
|
-
|
|
9
|
-
### Monitoring outgoing requests
|
|
10
|
-
|
|
11
|
-
To monitor the state of the outgoing requests (like number of requests, number of error, time execution) the module monkey-patches `request` and `get` methods of the standard modules `http` and `https`. To make it work just add metrics module to the app.
|
|
12
|
-
|
|
13
|
-
Next labels are added to metrics:
|
|
14
|
-
|
|
15
|
-
- http method
|
|
16
|
-
- http response code
|
|
17
|
-
- service name
|
|
18
|
-
|
|
19
|
-
#### Make service names showed in metrics instead of hostnames
|
|
20
|
-
|
|
21
|
-
Name of the service calculates by comparing request urls with values in `MetricsServicesRegistry`. Initially the register is bootstrapped with the inverted content of env variables. For example if some url from env is a substring of the request url, then the name of the env become the service name. If several envs matches this logic then the env with the longest url is used. If none of envs matches then **domain** used as service name label.
|
|
22
|
-
|
|
23
|
-
It is possible to give a hint to module about the service name in case url is dynamic. To do that:
|
|
24
|
-
|
|
25
|
-
- use token `METRICS_SERVICES_REGISTRY_TOKEN`;
|
|
26
|
-
- call `metricsServicesRegistry.register("Part of the url or the whole url", "Name of service")`
|
|
27
|
-
|
|
28
|
-
To explicitly associate the service name label with request, you should provide the `x-tramvai-service-name` header. This header will be consumed by the metrics module and then removed.
|
|
29
|
-
|
|
30
|
-
### Event Loop Lag
|
|
31
|
-
|
|
32
|
-
This module has their own implementation of Event Loop Lag metric - `nodejs_eventloop_setinterval_lag_seconds` histogram, this metric implemented with `setTimeout`.
|
|
33
|
-
|
|
34
|
-
### Client metrics
|
|
35
|
-
|
|
36
|
-
Module implements feature to collect metrics from the clients and share it with Prometheus by sending metrics from the client to server papi-route.
|
|
37
|
-
|
|
38
|
-
Metrics module can help in implementing this functionality in common cases. To create metric register provider for the token `REGISTER_INSTANT_METRIC_TOKEN`. Your provider should return list of two entities - first is a slug of papi-route and second is an instance of Counter. E.g.:
|
|
39
|
-
|
|
40
|
-
```javascript
|
|
41
|
-
import { provide } from '@tramvai/core';
|
|
42
|
-
|
|
43
|
-
provide({
|
|
44
|
-
provide: REGISTER_INSTANT_METRIC_TOKEN,
|
|
45
|
-
scope: Scope.SINGLETON,
|
|
46
|
-
multi: true,
|
|
47
|
-
deps: {
|
|
48
|
-
metrics: METRICS_MODULE_TOKEN,
|
|
49
|
-
},
|
|
50
|
-
useFactory({ metrics }) {
|
|
51
|
-
return ['page-load', new Counter({ name: 'client_page_load_total', help: 'Client page load' })];
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
After that to increment metric `client_page_load_total` you can call papi-route `/metrics/page-load`.
|
|
57
|
-
|
|
58
|
-
#### instantMetricsReporter
|
|
59
|
-
|
|
60
|
-
In practice it become clear that besides metric collection it often needed to collect logs with details. This can be implemented with `instantMetricsReporter`. When calling logger module will check that any metric with the slug equal to the event of the log is exist. If so module will send request to the corresponding papi-route.
|
|
61
|
-
|
|
62
|
-
Next way you can log event and increment server metric:
|
|
63
|
-
|
|
64
|
-
```javascript
|
|
65
|
-
import { provide } from '@tramvai/core';
|
|
66
|
-
provide({
|
|
67
|
-
provide: commandLineListTokens.init,
|
|
68
|
-
multi: true,
|
|
69
|
-
deps: {
|
|
70
|
-
logger: LOGGER_TOKEN,
|
|
71
|
-
},
|
|
72
|
-
useFactory({ logger }) {
|
|
73
|
-
return () => {
|
|
74
|
-
window.on('load', () => {
|
|
75
|
-
logger.info({ event: 'page-load' });
|
|
76
|
-
})
|
|
77
|
-
};
|
|
78
|
-
},
|
|
79
|
-
}),
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Metrics list
|
|
83
|
-
|
|
84
|
-
### Application metrics
|
|
85
|
-
|
|
86
|
-
- `http_requests_total` counter - application response count by status code
|
|
87
|
-
- `http_requests_execution_time` histogram - application response time
|
|
88
|
-
- `command_line_runner_execution_time` histogram - (measure application lifecycle)[03-features/06-app-lifecycle.md]
|
|
89
|
-
|
|
90
|
-
### Outgoing requests
|
|
91
|
-
|
|
92
|
-
- `http_sent_requests_total` counter - request count from application to external APIs
|
|
93
|
-
- `http_sent_requests_duration` histogram - request time from application to external APIs
|
|
94
|
-
- `http_sent_requests_errors` counter - request from application to external APIs errors count
|
|
95
|
-
- `dns_resolve_duration` histogram - DNS resolve time
|
|
96
|
-
- `tcp_connect_duration` histogram - TCP connect time
|
|
97
|
-
- `tls_handshake_duration` histogram - TLS handshake time
|
|
98
|
-
|
|
99
|
-
### Node.js metrics
|
|
100
|
-
|
|
101
|
-
- `nodejs_eventloop_lag_p90_seconds` gauge - event loop lag in 90 percentile from `prom-client`
|
|
102
|
-
- `nodejs_eventloop_setinterval_lag_seconds` histogram - event loop lag from custom `setTimeout` measurement
|
|
103
|
-
- `nodejs_heap_space_size_used_bytes` gauge - used memory size from `prom-client`
|
|
104
|
-
- `nodejs_gc_duration_seconds` histogram - GC duration from `prom-client`
|
|
105
|
-
- `nodejs_active_handles` gauge - total number of active handles from `prom-client`
|
|
106
|
-
- `nodejs_active_requests` gauge - total number of active requests from `prom-client`
|
|
107
|
-
|
|
108
|
-
## How to
|
|
109
|
-
|
|
110
|
-
### Usage Example
|
|
111
|
-
|
|
112
|
-
```tsx
|
|
113
|
-
import { createToken } from '@tinkoff/dippy';
|
|
114
|
-
import { Module, provide } from '@tramvai/core';
|
|
115
|
-
import { Counter, Metrics, METRICS_MODULE_TOKEN } from '@tramvai/tokens-metrics';
|
|
116
|
-
|
|
117
|
-
interface SomeModuleOptions {
|
|
118
|
-
metrics: Metrics;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
class SomeModule {
|
|
122
|
-
private metricActionCounter: Counter;
|
|
123
|
-
|
|
124
|
-
constructor(options: SomeModuleOptions) {
|
|
125
|
-
this.metricActionCounter = options.metrics.counter({
|
|
126
|
-
name: 'some_actions_total',
|
|
127
|
-
help: 'Total count of some actions',
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
public action(): void {
|
|
132
|
-
this.metricActionCounter.inc();
|
|
133
|
-
|
|
134
|
-
// Do some meaningful action
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export const SOME_MODULE = createToken<SomeModule>('someModule');
|
|
139
|
-
|
|
140
|
-
@Module({
|
|
141
|
-
providers: [
|
|
142
|
-
provide({
|
|
143
|
-
provide: SOME_MODULE,
|
|
144
|
-
useFactory: (deps) => new SomeModule(deps),
|
|
145
|
-
deps: {
|
|
146
|
-
metrics: METRICS_MODULE_TOKEN,
|
|
147
|
-
},
|
|
148
|
-
}),
|
|
149
|
-
],
|
|
150
|
-
})
|
|
151
|
-
export class SomeModuleContainer {}
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Use metrics to profile performance in browser
|
|
155
|
-
|
|
156
|
-
To measure length of the events you must use method `startTimer` of classes Gauge, Histogram, Summary. In dev-mode these classes are patched and methods to work with timers will use [PerformanceApi](https://developer.mozilla.org/en-US/docs/Web/API/Performance).
|
|
157
|
-
|
|
158
|
-
Example without additional fields:
|
|
159
|
-
|
|
160
|
-
```ts
|
|
161
|
-
const metric = metrics.gauge({
|
|
162
|
-
name: 'request_measure',
|
|
163
|
-
help: 'Request duration measure',
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
const endTimer = metric.startTimer();
|
|
167
|
-
|
|
168
|
-
fetch(url).then(() => {
|
|
169
|
-
endTimer();
|
|
170
|
-
|
|
171
|
-
// output the result - performance.getEntriesByName('request_measure');
|
|
172
|
-
});
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
Example with adding dynamic fields:
|
|
176
|
-
|
|
177
|
-
```ts
|
|
178
|
-
const metric = metrics.gauge({
|
|
179
|
-
name: 'request_measure',
|
|
180
|
-
help: 'Request duration measure',
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
const endTimer = metric.startTimer({ method: 'GET' });
|
|
184
|
-
|
|
185
|
-
fetch(url).then(() => {
|
|
186
|
-
endTimer({ status: 200 });
|
|
187
|
-
|
|
188
|
-
// output the result - performance.getEntriesByName('request_measure{method="GET",status="200"}');
|
|
189
|
-
});
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### Use custom port for metrics endpoint
|
|
193
|
-
|
|
194
|
-
It can be done with token `UTILITY_SERVER_PORT_TOKEN` as it works for any [utility path](./server.md#specify-port-for-utility-paths):
|
|
195
|
-
|
|
196
|
-
## Debug
|
|
197
|
-
|
|
198
|
-
The module uses loggers with the next ids: `metrics:perf`, `metrics:papi`
|
|
199
|
-
|
|
200
|
-
## Exported tokens
|
|
201
|
-
|
|
202
|
-
[link](references/tokens/metrics.md)
|
|
3
|
+
[Actual documentation](03-features/014-monitoring/02-metrics.md)
|
package/lib/browser.js
CHANGED
|
@@ -41,7 +41,6 @@ MetricsModule = __decorate([
|
|
|
41
41
|
useFactory: ({ logger, pageService }) => () => {
|
|
42
42
|
window.addEventListener('load', () => {
|
|
43
43
|
setTimeout(() => {
|
|
44
|
-
var _a, _b;
|
|
45
44
|
const timings = browserTimings();
|
|
46
45
|
const log = logger({
|
|
47
46
|
name: 'metrics:perf',
|
|
@@ -56,8 +55,8 @@ MetricsModule = __decorate([
|
|
|
56
55
|
log.info({
|
|
57
56
|
...timings,
|
|
58
57
|
event: 'perf-timings',
|
|
59
|
-
deviceType:
|
|
60
|
-
urlMask:
|
|
58
|
+
deviceType: navigator.userAgent?.indexOf('Mobi') !== -1 ? 'mobile' : 'desktop',
|
|
59
|
+
urlMask: pageService.getCurrentRoute()?.path,
|
|
61
60
|
});
|
|
62
61
|
}, 0);
|
|
63
62
|
});
|
package/lib/constants.es.js
CHANGED
package/lib/constants.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
const DEFAULT_BUCKETS = [
|
|
5
|
+
const DEFAULT_BUCKETS = [
|
|
6
|
+
0.005, 0.007, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 20, 40, 60,
|
|
7
|
+
];
|
|
6
8
|
|
|
7
9
|
exports.DEFAULT_BUCKETS = DEFAULT_BUCKETS;
|
|
@@ -40,20 +40,19 @@ class MetricsServicesRegistry {
|
|
|
40
40
|
}));
|
|
41
41
|
}
|
|
42
42
|
getServiceName(url, options) {
|
|
43
|
-
var _a, _b, _c;
|
|
44
43
|
if (!url) {
|
|
45
44
|
return undefined;
|
|
46
45
|
}
|
|
47
|
-
const serviceFromHeaders = typeof
|
|
46
|
+
const serviceFromHeaders = typeof options?.headers?.get === 'function'
|
|
48
47
|
? options.headers.get(SERVICE_NAME_HEADER)
|
|
49
|
-
:
|
|
48
|
+
: options?.headers?.[SERVICE_NAME_HEADER];
|
|
50
49
|
if (serviceFromHeaders) {
|
|
51
50
|
if (typeof options.headers.delete === 'function') {
|
|
52
51
|
options.headers.delete(SERVICE_NAME_HEADER);
|
|
53
52
|
}
|
|
54
53
|
else {
|
|
55
54
|
// eslint-disable-next-line no-param-reassign
|
|
56
|
-
|
|
55
|
+
delete options?.headers?.[SERVICE_NAME_HEADER];
|
|
57
56
|
}
|
|
58
57
|
return serviceFromHeaders;
|
|
59
58
|
}
|
|
@@ -48,20 +48,19 @@ class MetricsServicesRegistry {
|
|
|
48
48
|
}));
|
|
49
49
|
}
|
|
50
50
|
getServiceName(url, options) {
|
|
51
|
-
var _a, _b, _c;
|
|
52
51
|
if (!url) {
|
|
53
52
|
return undefined;
|
|
54
53
|
}
|
|
55
|
-
const serviceFromHeaders = typeof
|
|
54
|
+
const serviceFromHeaders = typeof options?.headers?.get === 'function'
|
|
56
55
|
? options.headers.get(SERVICE_NAME_HEADER)
|
|
57
|
-
:
|
|
56
|
+
: options?.headers?.[SERVICE_NAME_HEADER];
|
|
58
57
|
if (serviceFromHeaders) {
|
|
59
58
|
if (typeof options.headers.delete === 'function') {
|
|
60
59
|
options.headers.delete(SERVICE_NAME_HEADER);
|
|
61
60
|
}
|
|
62
61
|
else {
|
|
63
62
|
// eslint-disable-next-line no-param-reassign
|
|
64
|
-
|
|
63
|
+
delete options?.headers?.[SERVICE_NAME_HEADER];
|
|
65
64
|
}
|
|
66
65
|
return serviceFromHeaders;
|
|
67
66
|
}
|
|
@@ -78,7 +78,7 @@ const createRequestWithMetrics = ({ metricsInstances: { requestsTotal, requestsE
|
|
|
78
78
|
timerDone(labelsValues);
|
|
79
79
|
});
|
|
80
80
|
req.on('error', (e) => {
|
|
81
|
-
if (POSSIBLE_ERRORS.includes(e
|
|
81
|
+
if (POSSIBLE_ERRORS.includes(e?.code)) {
|
|
82
82
|
labelsValues.status = req.aborted ? 'aborted' : e.code;
|
|
83
83
|
}
|
|
84
84
|
requestsTotal.inc(labelsValues);
|
|
@@ -82,7 +82,7 @@ const createRequestWithMetrics = ({ metricsInstances: { requestsTotal, requestsE
|
|
|
82
82
|
timerDone(labelsValues);
|
|
83
83
|
});
|
|
84
84
|
req.on('error', (e) => {
|
|
85
|
-
if (POSSIBLE_ERRORS.includes(e
|
|
85
|
+
if (POSSIBLE_ERRORS.includes(e?.code)) {
|
|
86
86
|
labelsValues.status = req.aborted ? 'aborted' : e.code;
|
|
87
87
|
}
|
|
88
88
|
requestsTotal.inc(labelsValues);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-metrics",
|
|
3
|
-
"version": "5.9
|
|
3
|
+
"version": "5.14.9",
|
|
4
4
|
"description": "",
|
|
5
5
|
"browser": "lib/browser.js",
|
|
6
6
|
"main": "lib/server.js",
|
|
@@ -18,22 +18,22 @@
|
|
|
18
18
|
"watch": "tsc -w"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@tramvai/core": "5.9
|
|
22
|
-
"@tramvai/tokens-common": "5.9
|
|
23
|
-
"@tramvai/tokens-core-private": "5.9
|
|
24
|
-
"@tramvai/tokens-server": "5.9
|
|
25
|
-
"@tramvai/tokens-server-private": "5.9
|
|
26
|
-
"@tramvai/tokens-metrics": "5.9
|
|
27
|
-
"@tramvai/tokens-router": "5.9
|
|
28
|
-
"@tramvai/tokens-http-client": "5.9
|
|
29
|
-
"@tramvai/state": "5.9
|
|
30
|
-
"@tramvai/papi": "5.9
|
|
21
|
+
"@tramvai/core": "5.14.9",
|
|
22
|
+
"@tramvai/tokens-common": "5.14.9",
|
|
23
|
+
"@tramvai/tokens-core-private": "5.14.9",
|
|
24
|
+
"@tramvai/tokens-server": "5.14.9",
|
|
25
|
+
"@tramvai/tokens-server-private": "5.14.9",
|
|
26
|
+
"@tramvai/tokens-metrics": "5.14.9",
|
|
27
|
+
"@tramvai/tokens-router": "5.14.9",
|
|
28
|
+
"@tramvai/tokens-http-client": "5.14.9",
|
|
29
|
+
"@tramvai/state": "5.14.9",
|
|
30
|
+
"@tramvai/papi": "5.14.9",
|
|
31
31
|
"@tinkoff/measure-fastify-requests": "0.4.2",
|
|
32
32
|
"@tinkoff/monkeypatch": "5.0.2",
|
|
33
33
|
"@tinkoff/url": "0.11.2",
|
|
34
34
|
"@tinkoff/utils": "^2.1.2",
|
|
35
35
|
"prom-client": "^14.2.0",
|
|
36
|
-
"@tinkoff/logger": "0.10.
|
|
36
|
+
"@tinkoff/logger": "0.10.505",
|
|
37
37
|
"@tinkoff/metrics-noop": "5.0.2",
|
|
38
38
|
"@tinkoff/browser-timings": "0.13.2"
|
|
39
39
|
},
|