@lakutata/monitor 3.0.0-beta.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/LICENSE +23 -0
- package/README.md +114 -0
- package/dist/cjs/exports/Monitor.d.ts +9 -0
- package/dist/cjs/exports/Monitor.js +28 -0
- package/dist/cjs/monitor/CpuMonitor.d.ts +60 -0
- package/dist/cjs/monitor/CpuMonitor.js +96 -0
- package/dist/cjs/monitor/EventLoopMonitor.d.ts +65 -0
- package/dist/cjs/monitor/EventLoopMonitor.js +92 -0
- package/dist/cjs/monitor/HttpRequestMonitor.d.ts +61 -0
- package/dist/cjs/monitor/HttpRequestMonitor.js +92 -0
- package/dist/cjs/monitor/MemoryMonitor.d.ts +61 -0
- package/dist/cjs/monitor/MemoryMonitor.js +152 -0
- package/dist/cjs/monitor/interfaces/ICpuMonitorStatistics.d.ts +40 -0
- package/dist/cjs/monitor/interfaces/ICpuMonitorStatistics.js +2 -0
- package/dist/cjs/monitor/interfaces/IEventLoopMonitorStatistics.d.ts +45 -0
- package/dist/cjs/monitor/interfaces/IEventLoopMonitorStatistics.js +2 -0
- package/dist/cjs/monitor/interfaces/IHttpRequestMonitorStatistics.d.ts +43 -0
- package/dist/cjs/monitor/interfaces/IHttpRequestMonitorStatistics.js +2 -0
- package/dist/cjs/monitor/interfaces/IMemoryMonitorStatistics.d.ts +124 -0
- package/dist/cjs/monitor/interfaces/IMemoryMonitorStatistics.js +2 -0
- package/dist/cjs/monitor/interfaces/IMonitor.d.ts +10 -0
- package/dist/cjs/monitor/interfaces/IMonitor.js +2 -0
- package/dist/cjs/monitor/lib/Samples.d.ts +57 -0
- package/dist/cjs/monitor/lib/Samples.js +119 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/exports/Monitor.js +9 -0
- package/dist/esm/monitor/CpuMonitor.js +92 -0
- package/dist/esm/monitor/EventLoopMonitor.js +88 -0
- package/dist/esm/monitor/HttpRequestMonitor.js +88 -0
- package/dist/esm/monitor/MemoryMonitor.js +115 -0
- package/dist/esm/monitor/interfaces/ICpuMonitorStatistics.js +1 -0
- package/dist/esm/monitor/interfaces/IEventLoopMonitorStatistics.js +1 -0
- package/dist/esm/monitor/interfaces/IHttpRequestMonitorStatistics.js +1 -0
- package/dist/esm/monitor/interfaces/IMemoryMonitorStatistics.js +1 -0
- package/dist/esm/monitor/interfaces/IMonitor.js +1 -0
- package/dist/esm/monitor/lib/Samples.js +114 -0
- package/dist/types/exports/Monitor.d.ts +9 -0
- package/dist/types/monitor/CpuMonitor.d.ts +60 -0
- package/dist/types/monitor/EventLoopMonitor.d.ts +65 -0
- package/dist/types/monitor/HttpRequestMonitor.d.ts +61 -0
- package/dist/types/monitor/MemoryMonitor.d.ts +61 -0
- package/dist/types/monitor/interfaces/ICpuMonitorStatistics.d.ts +40 -0
- package/dist/types/monitor/interfaces/IEventLoopMonitorStatistics.d.ts +45 -0
- package/dist/types/monitor/interfaces/IHttpRequestMonitorStatistics.d.ts +43 -0
- package/dist/types/monitor/interfaces/IMemoryMonitorStatistics.d.ts +124 -0
- package/dist/types/monitor/interfaces/IMonitor.d.ts +10 -0
- package/dist/types/monitor/lib/Samples.d.ts +57 -0
- package/package.json +44 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Component } from '@lakutata/core';
|
|
2
|
+
import { IMonitor } from './interfaces/IMonitor.js';
|
|
3
|
+
import { IMemoryMonitorStatistics } from './interfaces/IMemoryMonitorStatistics.js';
|
|
4
|
+
/**
|
|
5
|
+
* The memory monitor: measures the memory of the process, in bytes, with `process.memoryUsage()`: its resident set
|
|
6
|
+
* (the physical memory it occupies, `rss`), its V8 heap (`heapTotal` reserved, `heapUsed` occupied by the JavaScript
|
|
7
|
+
* objects) and its external memory (the C++ objects bound to JavaScript ones, the `Buffer`s included). It takes a
|
|
8
|
+
* sample when it is created then every second, and keeps the statistics of every sample since it was created or last
|
|
9
|
+
* {@link MemoryMonitor.reset}: the minimum, the maximum, the mean and percentiles, in constant memory.
|
|
10
|
+
*
|
|
11
|
+
* Declare it in the `components` of the application (`{class: MemoryMonitor}`) and get it with `@Inject` or
|
|
12
|
+
* `getObject()`; it is a singleton. It starts sampling when it is created: list it in `bootstrap` to measure from the
|
|
13
|
+
* launch. Its timer does not keep the process alive, and stops when the component is destroyed.
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import {Application} from 'lakutata'
|
|
17
|
+
* import {MemoryMonitor, type IMemoryMonitorStatistics} from 'lakutata/com/monitor'
|
|
18
|
+
*
|
|
19
|
+
* Application
|
|
20
|
+
* .run(() => ({
|
|
21
|
+
* id: 'memory.app',
|
|
22
|
+
* name: 'Memory',
|
|
23
|
+
* components: {
|
|
24
|
+
* memory: {class: MemoryMonitor}
|
|
25
|
+
* },
|
|
26
|
+
* bootstrap: ['memory']
|
|
27
|
+
* }))
|
|
28
|
+
* .onLaunched(async (app: Application): Promise<void> => {
|
|
29
|
+
* const memory: MemoryMonitor = await app.getObject('memory')
|
|
30
|
+
* setInterval((): void => {
|
|
31
|
+
* const statistics: IMemoryMonitorStatistics = memory.statistics
|
|
32
|
+
* const megabytes = (bytes: number): string => (bytes / 1048576).toFixed(1)
|
|
33
|
+
* console.log(`RSS ${megabytes(statistics.physicalUsed)} MB (${statistics.physicalUsage}% of the host), heap ${statistics.heapUsage}% used`)
|
|
34
|
+
* }, 60000)
|
|
35
|
+
* })
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare class MemoryMonitor extends Component implements IMonitor<IMemoryMonitorStatistics> {
|
|
39
|
+
#private;
|
|
40
|
+
/**
|
|
41
|
+
* The memory statistics, computed at each read: the latest sample (`physicalUsed`, `heapTotal`, `heapUsed`,
|
|
42
|
+
* `externalUsed`, in bytes, and the percentages `physicalUsage` and `heapUsage`, rounded to 2 decimals), the host's
|
|
43
|
+
* total memory, and the minimum, maximum, mean (rounded to 2 decimals) and percentiles of the samples since the
|
|
44
|
+
* monitor was created or reset. The percentiles are approximate (3 significant digits). The statistics of the
|
|
45
|
+
* samples are 0 after a reset until the next sample.
|
|
46
|
+
*/
|
|
47
|
+
get statistics(): IMemoryMonitorStatistics;
|
|
48
|
+
/**
|
|
49
|
+
* Take a sample of the memory of the process: it becomes the latest usage and is added to the statistics. Called
|
|
50
|
+
* when the monitor is created, then every second.
|
|
51
|
+
* @protected
|
|
52
|
+
*/
|
|
53
|
+
protected sampleMemoryUsage(): void;
|
|
54
|
+
protected init(): Promise<void>;
|
|
55
|
+
protected destroy(): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Forget the samples: the minimum, maximum, mean and percentiles are 0 until the next sample, then cover the samples
|
|
58
|
+
* taken since. The latest usage is kept.
|
|
59
|
+
*/
|
|
60
|
+
reset(): void;
|
|
61
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.MemoryMonitor = void 0;
|
|
37
|
+
const os = __importStar(require("node:os"));
|
|
38
|
+
const core_1 = require("@lakutata/core");
|
|
39
|
+
const Samples_js_1 = require("./lib/Samples.js");
|
|
40
|
+
/**
|
|
41
|
+
* The memory monitor: measures the memory of the process, in bytes, with `process.memoryUsage()`: its resident set
|
|
42
|
+
* (the physical memory it occupies, `rss`), its V8 heap (`heapTotal` reserved, `heapUsed` occupied by the JavaScript
|
|
43
|
+
* objects) and its external memory (the C++ objects bound to JavaScript ones, the `Buffer`s included). It takes a
|
|
44
|
+
* sample when it is created then every second, and keeps the statistics of every sample since it was created or last
|
|
45
|
+
* {@link MemoryMonitor.reset}: the minimum, the maximum, the mean and percentiles, in constant memory.
|
|
46
|
+
*
|
|
47
|
+
* Declare it in the `components` of the application (`{class: MemoryMonitor}`) and get it with `@Inject` or
|
|
48
|
+
* `getObject()`; it is a singleton. It starts sampling when it is created: list it in `bootstrap` to measure from the
|
|
49
|
+
* launch. Its timer does not keep the process alive, and stops when the component is destroyed.
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* import {Application} from 'lakutata'
|
|
53
|
+
* import {MemoryMonitor, type IMemoryMonitorStatistics} from 'lakutata/com/monitor'
|
|
54
|
+
*
|
|
55
|
+
* Application
|
|
56
|
+
* .run(() => ({
|
|
57
|
+
* id: 'memory.app',
|
|
58
|
+
* name: 'Memory',
|
|
59
|
+
* components: {
|
|
60
|
+
* memory: {class: MemoryMonitor}
|
|
61
|
+
* },
|
|
62
|
+
* bootstrap: ['memory']
|
|
63
|
+
* }))
|
|
64
|
+
* .onLaunched(async (app: Application): Promise<void> => {
|
|
65
|
+
* const memory: MemoryMonitor = await app.getObject('memory')
|
|
66
|
+
* setInterval((): void => {
|
|
67
|
+
* const statistics: IMemoryMonitorStatistics = memory.statistics
|
|
68
|
+
* const megabytes = (bytes: number): string => (bytes / 1048576).toFixed(1)
|
|
69
|
+
* console.log(`RSS ${megabytes(statistics.physicalUsed)} MB (${statistics.physicalUsage}% of the host), heap ${statistics.heapUsage}% used`)
|
|
70
|
+
* }, 60000)
|
|
71
|
+
* })
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
class MemoryMonitor extends core_1.Component {
|
|
75
|
+
#fractionDigits = 2;
|
|
76
|
+
#intervalDelay = 1000;
|
|
77
|
+
#totalMemorySize = os.totalmem();
|
|
78
|
+
#physical = new Samples_js_1.Samples();
|
|
79
|
+
#heap = new Samples_js_1.Samples();
|
|
80
|
+
#external = new Samples_js_1.Samples();
|
|
81
|
+
#latest = process.memoryUsage();
|
|
82
|
+
#sampleInterval;
|
|
83
|
+
/**
|
|
84
|
+
* The memory statistics, computed at each read: the latest sample (`physicalUsed`, `heapTotal`, `heapUsed`,
|
|
85
|
+
* `externalUsed`, in bytes, and the percentages `physicalUsage` and `heapUsage`, rounded to 2 decimals), the host's
|
|
86
|
+
* total memory, and the minimum, maximum, mean (rounded to 2 decimals) and percentiles of the samples since the
|
|
87
|
+
* monitor was created or reset. The percentiles are approximate (3 significant digits). The statistics of the
|
|
88
|
+
* samples are 0 after a reset until the next sample.
|
|
89
|
+
*/
|
|
90
|
+
get statistics() {
|
|
91
|
+
const latest = this.#latest;
|
|
92
|
+
return {
|
|
93
|
+
physicalTotal: this.#totalMemorySize,
|
|
94
|
+
physicalUsed: latest.rss,
|
|
95
|
+
physicalUsage: (0, Samples_js_1.round)(latest.rss / this.#totalMemorySize * 100, this.#fractionDigits),
|
|
96
|
+
physicalUsedMin: this.#physical.min,
|
|
97
|
+
physicalUsedMax: this.#physical.max,
|
|
98
|
+
physicalUsedAvg: (0, Samples_js_1.round)(this.#physical.mean, this.#fractionDigits),
|
|
99
|
+
physicalUsedP50: this.#physical.percentile(50),
|
|
100
|
+
physicalUsedP90: this.#physical.percentile(90),
|
|
101
|
+
physicalUsedP95: this.#physical.percentile(95),
|
|
102
|
+
physicalUsedP99: this.#physical.percentile(99),
|
|
103
|
+
heapTotal: latest.heapTotal,
|
|
104
|
+
heapUsed: latest.heapUsed,
|
|
105
|
+
heapUsage: (0, Samples_js_1.round)(latest.heapTotal ? latest.heapUsed / latest.heapTotal * 100 : 0, this.#fractionDigits),
|
|
106
|
+
heapUsedMin: this.#heap.min,
|
|
107
|
+
heapUsedMax: this.#heap.max,
|
|
108
|
+
heapUsedAvg: (0, Samples_js_1.round)(this.#heap.mean, this.#fractionDigits),
|
|
109
|
+
heapUsedP50: this.#heap.percentile(50),
|
|
110
|
+
heapUsedP90: this.#heap.percentile(90),
|
|
111
|
+
heapUsedP95: this.#heap.percentile(95),
|
|
112
|
+
heapUsedP99: this.#heap.percentile(99),
|
|
113
|
+
externalUsed: latest.external,
|
|
114
|
+
externalUsedMin: this.#external.min,
|
|
115
|
+
externalUsedMax: this.#external.max,
|
|
116
|
+
externalUsedAvg: (0, Samples_js_1.round)(this.#external.mean, this.#fractionDigits),
|
|
117
|
+
externalUsedP50: this.#external.percentile(50),
|
|
118
|
+
externalUsedP90: this.#external.percentile(90),
|
|
119
|
+
externalUsedP95: this.#external.percentile(95),
|
|
120
|
+
externalUsedP99: this.#external.percentile(99)
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Take a sample of the memory of the process: it becomes the latest usage and is added to the statistics. Called
|
|
125
|
+
* when the monitor is created, then every second.
|
|
126
|
+
* @protected
|
|
127
|
+
*/
|
|
128
|
+
sampleMemoryUsage() {
|
|
129
|
+
const usage = process.memoryUsage();
|
|
130
|
+
this.#latest = usage;
|
|
131
|
+
this.#physical.record(usage.rss);
|
|
132
|
+
this.#heap.record(usage.heapUsed);
|
|
133
|
+
this.#external.record(usage.external);
|
|
134
|
+
}
|
|
135
|
+
async init() {
|
|
136
|
+
this.sampleMemoryUsage();
|
|
137
|
+
this.#sampleInterval = setInterval(() => this.sampleMemoryUsage(), this.#intervalDelay).unref();
|
|
138
|
+
}
|
|
139
|
+
async destroy() {
|
|
140
|
+
clearInterval(this.#sampleInterval);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Forget the samples: the minimum, maximum, mean and percentiles are 0 until the next sample, then cover the samples
|
|
144
|
+
* taken since. The latest usage is kept.
|
|
145
|
+
*/
|
|
146
|
+
reset() {
|
|
147
|
+
this.#physical.reset();
|
|
148
|
+
this.#heap.reset();
|
|
149
|
+
this.#external.reset();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
exports.MemoryMonitor = MemoryMonitor;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The statistics of a {@link CpuMonitor}: the CPU usage of the process in percent of one core (100 is one core fully
|
|
3
|
+
* busy; above 100 with several cores busy), each sample the average over one second, rounded to 5 decimals. The
|
|
4
|
+
* minimum, maximum, mean and percentiles cover the samples since the monitor was created or reset; the percentiles are
|
|
5
|
+
* approximate (3 significant digits). All 0 before the first sample.
|
|
6
|
+
*/
|
|
7
|
+
export interface ICpuMonitorStatistics {
|
|
8
|
+
/**
|
|
9
|
+
* The CPU usage over the latest second (the latest sample), in percent of one core.
|
|
10
|
+
*/
|
|
11
|
+
usage: number;
|
|
12
|
+
/**
|
|
13
|
+
* The lowest sample, in percent of one core.
|
|
14
|
+
*/
|
|
15
|
+
usageMin: number;
|
|
16
|
+
/**
|
|
17
|
+
* The highest sample, in percent of one core.
|
|
18
|
+
*/
|
|
19
|
+
usageMax: number;
|
|
20
|
+
/**
|
|
21
|
+
* The mean of the samples, in percent of one core.
|
|
22
|
+
*/
|
|
23
|
+
usageAvg: number;
|
|
24
|
+
/**
|
|
25
|
+
* The median sample (50% of the seconds used less), in percent of one core.
|
|
26
|
+
*/
|
|
27
|
+
usageP50: number;
|
|
28
|
+
/**
|
|
29
|
+
* The 90th percentile of the samples (90% of the seconds used less), in percent of one core.
|
|
30
|
+
*/
|
|
31
|
+
usageP90: number;
|
|
32
|
+
/**
|
|
33
|
+
* The 95th percentile of the samples, in percent of one core.
|
|
34
|
+
*/
|
|
35
|
+
usageP95: number;
|
|
36
|
+
/**
|
|
37
|
+
* The 99th percentile of the samples, in percent of one core.
|
|
38
|
+
*/
|
|
39
|
+
usageP99: number;
|
|
40
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The statistics of an {@link EventLoopMonitor} since it was created or reset: the event loop delays, in milliseconds
|
|
3
|
+
* (measured by a timer due every millisecond: about 1 ms when the loop is idle, more while synchronous work blocks
|
|
4
|
+
* it; all 0 before the first measure), and the loop utilization, in percent. The percentiles
|
|
5
|
+
* come from Node's histogram.
|
|
6
|
+
*/
|
|
7
|
+
export interface IEventLoopMonitorStatistics {
|
|
8
|
+
/**
|
|
9
|
+
* The shortest delay, in milliseconds.
|
|
10
|
+
*/
|
|
11
|
+
min: number;
|
|
12
|
+
/**
|
|
13
|
+
* The longest delay, in milliseconds: the longest the loop was blocked.
|
|
14
|
+
*/
|
|
15
|
+
max: number;
|
|
16
|
+
/**
|
|
17
|
+
* The mean delay, in milliseconds.
|
|
18
|
+
*/
|
|
19
|
+
avg: number;
|
|
20
|
+
/**
|
|
21
|
+
* The standard deviation of the delays, in milliseconds.
|
|
22
|
+
*/
|
|
23
|
+
stdDev: number;
|
|
24
|
+
/**
|
|
25
|
+
* The median delay, in milliseconds.
|
|
26
|
+
*/
|
|
27
|
+
p50: number;
|
|
28
|
+
/**
|
|
29
|
+
* The 90th percentile of the delays (90% were shorter), in milliseconds.
|
|
30
|
+
*/
|
|
31
|
+
p90: number;
|
|
32
|
+
/**
|
|
33
|
+
* The 95th percentile of the delays, in milliseconds.
|
|
34
|
+
*/
|
|
35
|
+
p95: number;
|
|
36
|
+
/**
|
|
37
|
+
* The 99th percentile of the delays, in milliseconds: the usual pick for an alert.
|
|
38
|
+
*/
|
|
39
|
+
p99: number;
|
|
40
|
+
/**
|
|
41
|
+
* The share of the time the event loop was busy running code rather than waiting for I/O, in percent (0 to
|
|
42
|
+
* 100), since the monitor was created or reset. Not rounded.
|
|
43
|
+
*/
|
|
44
|
+
utilRate: number;
|
|
45
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The statistics of an {@link HttpRequestMonitor} since it was created or reset: the number of HTTP requests received
|
|
3
|
+
* and their durations, from their arrival to the end of their response, in milliseconds rounded to 2 decimals. The
|
|
4
|
+
* percentiles are approximate (3 significant digits). All 0 before the first request.
|
|
5
|
+
*/
|
|
6
|
+
export interface IHttpRequestMonitorStatistics {
|
|
7
|
+
/**
|
|
8
|
+
* The number of requests received whose response ended.
|
|
9
|
+
*/
|
|
10
|
+
count: number;
|
|
11
|
+
/**
|
|
12
|
+
* The shortest request, in milliseconds.
|
|
13
|
+
*/
|
|
14
|
+
min: number;
|
|
15
|
+
/**
|
|
16
|
+
* The longest request, in milliseconds.
|
|
17
|
+
*/
|
|
18
|
+
max: number;
|
|
19
|
+
/**
|
|
20
|
+
* The mean duration, in milliseconds.
|
|
21
|
+
*/
|
|
22
|
+
avg: number;
|
|
23
|
+
/**
|
|
24
|
+
* The standard deviation of the durations, in milliseconds.
|
|
25
|
+
*/
|
|
26
|
+
stdDev: number;
|
|
27
|
+
/**
|
|
28
|
+
* The median duration, in milliseconds.
|
|
29
|
+
*/
|
|
30
|
+
p50: number;
|
|
31
|
+
/**
|
|
32
|
+
* The 90th percentile of the durations (90% of the requests were faster), in milliseconds.
|
|
33
|
+
*/
|
|
34
|
+
p90: number;
|
|
35
|
+
/**
|
|
36
|
+
* The 95th percentile of the durations, in milliseconds.
|
|
37
|
+
*/
|
|
38
|
+
p95: number;
|
|
39
|
+
/**
|
|
40
|
+
* The 99th percentile of the durations, in milliseconds.
|
|
41
|
+
*/
|
|
42
|
+
p99: number;
|
|
43
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The statistics of a {@link MemoryMonitor}, in bytes unless stated: the latest sample of the process memory
|
|
3
|
+
* (`process.memoryUsage()`), and the minimum, maximum, mean and percentiles of the samples taken every second since
|
|
4
|
+
* the monitor was created or reset (0 after a reset until the next sample). The percentiles are approximate (3
|
|
5
|
+
* significant digits).
|
|
6
|
+
*/
|
|
7
|
+
export interface IMemoryMonitorStatistics {
|
|
8
|
+
/**
|
|
9
|
+
* The total physical memory of the host (`os.totalmem()`), in bytes; under a container, the host's,
|
|
10
|
+
* not the container's limit.
|
|
11
|
+
*/
|
|
12
|
+
physicalTotal: number;
|
|
13
|
+
/**
|
|
14
|
+
* The resident set size of the process (`rss`) at the latest sample: the physical memory it occupies, in
|
|
15
|
+
* bytes.
|
|
16
|
+
*/
|
|
17
|
+
physicalUsed: number;
|
|
18
|
+
/**
|
|
19
|
+
* `physicalUsed` as a percentage of `physicalTotal`, rounded to 2 decimals.
|
|
20
|
+
*/
|
|
21
|
+
physicalUsage: number;
|
|
22
|
+
/**
|
|
23
|
+
* The lowest resident set size sampled, in bytes.
|
|
24
|
+
*/
|
|
25
|
+
physicalUsedMin: number;
|
|
26
|
+
/**
|
|
27
|
+
* The highest resident set size sampled, in bytes.
|
|
28
|
+
*/
|
|
29
|
+
physicalUsedMax: number;
|
|
30
|
+
/**
|
|
31
|
+
* The mean resident set size of the samples, in bytes, rounded to 2 decimals.
|
|
32
|
+
*/
|
|
33
|
+
physicalUsedAvg: number;
|
|
34
|
+
/**
|
|
35
|
+
* The median resident set size of the samples, in bytes.
|
|
36
|
+
*/
|
|
37
|
+
physicalUsedP50: number;
|
|
38
|
+
/**
|
|
39
|
+
* The 90th percentile of the resident set size samples, in bytes.
|
|
40
|
+
*/
|
|
41
|
+
physicalUsedP90: number;
|
|
42
|
+
/**
|
|
43
|
+
* The 95th percentile of the resident set size samples, in bytes.
|
|
44
|
+
*/
|
|
45
|
+
physicalUsedP95: number;
|
|
46
|
+
/**
|
|
47
|
+
* The 99th percentile of the resident set size samples, in bytes.
|
|
48
|
+
*/
|
|
49
|
+
physicalUsedP99: number;
|
|
50
|
+
/**
|
|
51
|
+
* The size of the V8 heap reserved by the process at the latest sample, in bytes.
|
|
52
|
+
*/
|
|
53
|
+
heapTotal: number;
|
|
54
|
+
/**
|
|
55
|
+
* The part of the V8 heap occupied by JavaScript objects at the latest sample, in bytes.
|
|
56
|
+
*/
|
|
57
|
+
heapUsed: number;
|
|
58
|
+
/**
|
|
59
|
+
* `heapUsed` as a percentage of `heapTotal`, rounded to 2 decimals. V8 grows the heap as needed, so a
|
|
60
|
+
* high value alone is not a leak: a leak shows as `heapUsedMin` rising from one reset period to the next.
|
|
61
|
+
*/
|
|
62
|
+
heapUsage: number;
|
|
63
|
+
/**
|
|
64
|
+
* The lowest used heap sampled, in bytes.
|
|
65
|
+
*/
|
|
66
|
+
heapUsedMin: number;
|
|
67
|
+
/**
|
|
68
|
+
* The highest used heap sampled, in bytes.
|
|
69
|
+
*/
|
|
70
|
+
heapUsedMax: number;
|
|
71
|
+
/**
|
|
72
|
+
* The mean used heap of the samples, in bytes, rounded to 2 decimals.
|
|
73
|
+
*/
|
|
74
|
+
heapUsedAvg: number;
|
|
75
|
+
/**
|
|
76
|
+
* The median used heap of the samples, in bytes.
|
|
77
|
+
*/
|
|
78
|
+
heapUsedP50: number;
|
|
79
|
+
/**
|
|
80
|
+
* The 90th percentile of the used heap samples, in bytes.
|
|
81
|
+
*/
|
|
82
|
+
heapUsedP90: number;
|
|
83
|
+
/**
|
|
84
|
+
* The 95th percentile of the used heap samples, in bytes.
|
|
85
|
+
*/
|
|
86
|
+
heapUsedP95: number;
|
|
87
|
+
/**
|
|
88
|
+
* The 99th percentile of the used heap samples, in bytes.
|
|
89
|
+
*/
|
|
90
|
+
heapUsedP99: number;
|
|
91
|
+
/**
|
|
92
|
+
* The memory of the C++ objects bound to JavaScript objects (the `Buffer`s included) at the latest
|
|
93
|
+
* sample, in bytes.
|
|
94
|
+
*/
|
|
95
|
+
externalUsed: number;
|
|
96
|
+
/**
|
|
97
|
+
* The lowest external memory sampled, in bytes.
|
|
98
|
+
*/
|
|
99
|
+
externalUsedMin: number;
|
|
100
|
+
/**
|
|
101
|
+
* The highest external memory sampled, in bytes.
|
|
102
|
+
*/
|
|
103
|
+
externalUsedMax: number;
|
|
104
|
+
/**
|
|
105
|
+
* The mean external memory of the samples, in bytes, rounded to 2 decimals.
|
|
106
|
+
*/
|
|
107
|
+
externalUsedAvg: number;
|
|
108
|
+
/**
|
|
109
|
+
* The median external memory of the samples, in bytes.
|
|
110
|
+
*/
|
|
111
|
+
externalUsedP50: number;
|
|
112
|
+
/**
|
|
113
|
+
* The 90th percentile of the external memory samples, in bytes.
|
|
114
|
+
*/
|
|
115
|
+
externalUsedP90: number;
|
|
116
|
+
/**
|
|
117
|
+
* The 95th percentile of the external memory samples, in bytes.
|
|
118
|
+
*/
|
|
119
|
+
externalUsedP95: number;
|
|
120
|
+
/**
|
|
121
|
+
* The 99th percentile of the external memory samples, in bytes.
|
|
122
|
+
*/
|
|
123
|
+
externalUsedP99: number;
|
|
124
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The statistics of the samples of a measure, in a constant memory: the latest value, the minimum, the maximum, the
|
|
3
|
+
* mean and the standard deviation are exact, the percentiles come from a histogram (3 significant digits)
|
|
4
|
+
*/
|
|
5
|
+
export declare class Samples {
|
|
6
|
+
#private;
|
|
7
|
+
protected readonly scale: number;
|
|
8
|
+
/**
|
|
9
|
+
* @param scale the factor of the precision of the percentiles (100 keeps 2 decimals)
|
|
10
|
+
*/
|
|
11
|
+
constructor(scale?: number);
|
|
12
|
+
/**
|
|
13
|
+
* Record a sample (a negative value is recorded as 0)
|
|
14
|
+
* @param value
|
|
15
|
+
*/
|
|
16
|
+
record(value: number): void;
|
|
17
|
+
/**
|
|
18
|
+
* The number of samples
|
|
19
|
+
*/
|
|
20
|
+
get count(): number;
|
|
21
|
+
/**
|
|
22
|
+
* The latest sample, 0 without sample
|
|
23
|
+
*/
|
|
24
|
+
get latest(): number;
|
|
25
|
+
/**
|
|
26
|
+
* The minimum, 0 without sample
|
|
27
|
+
*/
|
|
28
|
+
get min(): number;
|
|
29
|
+
/**
|
|
30
|
+
* The maximum, 0 without sample
|
|
31
|
+
*/
|
|
32
|
+
get max(): number;
|
|
33
|
+
/**
|
|
34
|
+
* The mean, 0 without sample
|
|
35
|
+
*/
|
|
36
|
+
get mean(): number;
|
|
37
|
+
/**
|
|
38
|
+
* The (population) standard deviation, 0 without sample
|
|
39
|
+
*/
|
|
40
|
+
get stdDev(): number;
|
|
41
|
+
/**
|
|
42
|
+
* A percentile, 0 without sample
|
|
43
|
+
* @param percentile from 0 to 100
|
|
44
|
+
*/
|
|
45
|
+
percentile(percentile: number): number;
|
|
46
|
+
/**
|
|
47
|
+
* Forget the samples
|
|
48
|
+
*/
|
|
49
|
+
reset(): void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Round a number to a number of decimals
|
|
53
|
+
* @param value
|
|
54
|
+
* @param fractionDigits
|
|
55
|
+
* @constructor
|
|
56
|
+
*/
|
|
57
|
+
export declare function round(value: number, fractionDigits: number): number;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Samples = void 0;
|
|
4
|
+
exports.round = round;
|
|
5
|
+
const node_perf_hooks_1 = require("node:perf_hooks");
|
|
6
|
+
/**
|
|
7
|
+
* The statistics of the samples of a measure, in a constant memory: the latest value, the minimum, the maximum, the
|
|
8
|
+
* mean and the standard deviation are exact, the percentiles come from a histogram (3 significant digits)
|
|
9
|
+
*/
|
|
10
|
+
class Samples {
|
|
11
|
+
/**
|
|
12
|
+
* The histogram of the percentiles: it records integers from 1, so a value is recorded multiplied by the scale,
|
|
13
|
+
* plus 1 (a value may be 0)
|
|
14
|
+
*/
|
|
15
|
+
#histogram = (0, node_perf_hooks_1.createHistogram)();
|
|
16
|
+
#count = 0;
|
|
17
|
+
#latest = 0;
|
|
18
|
+
#min = 0;
|
|
19
|
+
#max = 0;
|
|
20
|
+
#mean = 0;
|
|
21
|
+
//The sum of the squares of the differences from the mean (Welford's algorithm)
|
|
22
|
+
#m2 = 0;
|
|
23
|
+
/**
|
|
24
|
+
* @param scale the factor of the precision of the percentiles (100 keeps 2 decimals)
|
|
25
|
+
*/
|
|
26
|
+
constructor(scale = 1) {
|
|
27
|
+
this.scale = scale;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Record a sample (a negative value is recorded as 0)
|
|
31
|
+
* @param value
|
|
32
|
+
*/
|
|
33
|
+
record(value) {
|
|
34
|
+
const sample = Number.isFinite(value) && value > 0 ? value : 0;
|
|
35
|
+
this.#histogram.record(Math.round(sample * this.scale) + 1);
|
|
36
|
+
this.#count++;
|
|
37
|
+
this.#latest = sample;
|
|
38
|
+
if (this.#count === 1) {
|
|
39
|
+
this.#min = sample;
|
|
40
|
+
this.#max = sample;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
if (sample < this.#min)
|
|
44
|
+
this.#min = sample;
|
|
45
|
+
if (sample > this.#max)
|
|
46
|
+
this.#max = sample;
|
|
47
|
+
}
|
|
48
|
+
const delta = sample - this.#mean;
|
|
49
|
+
this.#mean += delta / this.#count;
|
|
50
|
+
this.#m2 += delta * (sample - this.#mean);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The number of samples
|
|
54
|
+
*/
|
|
55
|
+
get count() {
|
|
56
|
+
return this.#count;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The latest sample, 0 without sample
|
|
60
|
+
*/
|
|
61
|
+
get latest() {
|
|
62
|
+
return this.#latest;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The minimum, 0 without sample
|
|
66
|
+
*/
|
|
67
|
+
get min() {
|
|
68
|
+
return this.#min;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The maximum, 0 without sample
|
|
72
|
+
*/
|
|
73
|
+
get max() {
|
|
74
|
+
return this.#max;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The mean, 0 without sample
|
|
78
|
+
*/
|
|
79
|
+
get mean() {
|
|
80
|
+
return this.#mean;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The (population) standard deviation, 0 without sample
|
|
84
|
+
*/
|
|
85
|
+
get stdDev() {
|
|
86
|
+
return this.#count ? Math.sqrt(this.#m2 / this.#count) : 0;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A percentile, 0 without sample
|
|
90
|
+
* @param percentile from 0 to 100
|
|
91
|
+
*/
|
|
92
|
+
percentile(percentile) {
|
|
93
|
+
if (!this.#count)
|
|
94
|
+
return 0;
|
|
95
|
+
return Math.min(Math.max((this.#histogram.percentile(percentile) - 1) / this.scale, this.#min), this.#max);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Forget the samples
|
|
99
|
+
*/
|
|
100
|
+
reset() {
|
|
101
|
+
this.#histogram.reset();
|
|
102
|
+
this.#count = 0;
|
|
103
|
+
this.#latest = 0;
|
|
104
|
+
this.#min = 0;
|
|
105
|
+
this.#max = 0;
|
|
106
|
+
this.#mean = 0;
|
|
107
|
+
this.#m2 = 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.Samples = Samples;
|
|
111
|
+
/**
|
|
112
|
+
* Round a number to a number of decimals
|
|
113
|
+
* @param value
|
|
114
|
+
* @param fractionDigits
|
|
115
|
+
* @constructor
|
|
116
|
+
*/
|
|
117
|
+
function round(value, fractionDigits) {
|
|
118
|
+
return parseFloat(value.toFixed(fractionDigits));
|
|
119
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|