@arcblock/pm2-prom-module 2.6.1

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.
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.deletePromAppInstancesMetrics = exports.deletePromAppMetrics = exports.combineAllRegistries = exports.initDynamicGaugeMetricClients = exports.initMetrics = exports.dynamicGaugeMetricClients = exports.metricAppStatus = exports.metricAppPidsMemory = exports.metricAppUptime = exports.metricAppRestartCount = exports.metricAppPidsCpuThreshold = exports.metricAppPidsCpuLast = exports.metricAppAverageCpu = exports.metricAppTotalMemory = exports.metricAppAverageMemory = exports.metricAppInstances = exports.metricAvailableApps = exports.registry = void 0;
16
+ const prom_client_1 = __importDefault(require("prom-client"));
17
+ const node_os_1 = __importDefault(require("node:os"));
18
+ const cpu_1 = require("../utils/cpu");
19
+ const docker_1 = require("../utils/docker");
20
+ const app_1 = require("./app");
21
+ const METRIC_FREE_MEMORY = 'free_memory';
22
+ const METRIC_AVAILABLE_CPU = 'cpu_count';
23
+ const METRIC_AVAILABLE_APPS = 'available_apps';
24
+ const METRIC_APP_INSTANCES = 'app_instances';
25
+ const METRIC_APP_AVERAGE_MEMORY = 'app_average_memory';
26
+ const METRIC_APP_PIDS_MEMORY = 'app_pids_memory';
27
+ const METRIC_APP_TOTAL_MEMORY = 'app_total_memory';
28
+ const METRIC_APP_AVERAGE_CPU = 'app_average_cpu';
29
+ const METRIC_APP_PIDS_CPU = 'app_pids_cpu';
30
+ const METRIC_APP_PIDS_CPU_THRESHOLD = 'app_pids_cpu_threshold';
31
+ const METRIC_APP_RESTART_COUNT = 'app_restart_count';
32
+ const METRIC_APP_UPTIME = 'app_uptime';
33
+ const METRIC_APP_STATUS = 'app_status';
34
+ const METRIC_TOTAL_MEMORY_CONTAINER = 'container_total_memory';
35
+ const METRIC_FREE_MEMORY_CONTAINER = 'container_free_memory';
36
+ const METRIC_USED_MEMORY_CONTAINER = 'container_used_memory';
37
+ const METRIC_AVAILABLE_CPU_CONTAINER = 'container_cpu_count';
38
+ exports.registry = new prom_client_1.default.Registry();
39
+ let currentPrefix = '';
40
+ exports.dynamicGaugeMetricClients = {};
41
+ // Metrics
42
+ const initMetrics = (prefix) => {
43
+ currentPrefix = prefix;
44
+ new prom_client_1.default.Gauge({
45
+ name: `${prefix}_${METRIC_FREE_MEMORY}`,
46
+ help: 'Show available host free memory (System OS)',
47
+ collect() {
48
+ this.set(node_os_1.default.freemem());
49
+ },
50
+ registers: [exports.registry],
51
+ });
52
+ new prom_client_1.default.Gauge({
53
+ name: `${prefix}_${METRIC_AVAILABLE_CPU}`,
54
+ help: 'Show available CPUs count (System OS)',
55
+ collect() {
56
+ this.set((0, cpu_1.getCpuCount)());
57
+ },
58
+ registers: [exports.registry],
59
+ });
60
+ // Check if we in docker container
61
+ (0, docker_1.hasDockerLimitFiles)()
62
+ .then(() => {
63
+ new prom_client_1.default.Gauge({
64
+ name: `${prefix}_${METRIC_TOTAL_MEMORY_CONTAINER}`,
65
+ help: 'Available memory in container',
66
+ collect() {
67
+ return __awaiter(this, void 0, void 0, function* () {
68
+ try {
69
+ const memory = yield (0, docker_1.getAvailableMemory)();
70
+ this.set(memory);
71
+ }
72
+ catch (_a) { }
73
+ });
74
+ },
75
+ registers: [exports.registry],
76
+ });
77
+ new prom_client_1.default.Gauge({
78
+ name: `${prefix}_${METRIC_FREE_MEMORY_CONTAINER}`,
79
+ help: 'Free memory in container',
80
+ collect() {
81
+ return __awaiter(this, void 0, void 0, function* () {
82
+ try {
83
+ const memory = yield (0, docker_1.getFreeMemory)();
84
+ this.set(memory);
85
+ }
86
+ catch (_a) { }
87
+ });
88
+ },
89
+ registers: [exports.registry],
90
+ });
91
+ new prom_client_1.default.Gauge({
92
+ name: `${prefix}_${METRIC_USED_MEMORY_CONTAINER}`,
93
+ help: 'Used memory in container',
94
+ collect() {
95
+ return __awaiter(this, void 0, void 0, function* () {
96
+ try {
97
+ const memory = yield (0, docker_1.getUsedMemory)();
98
+ this.set(memory);
99
+ }
100
+ catch (_a) { }
101
+ });
102
+ },
103
+ registers: [exports.registry],
104
+ });
105
+ new prom_client_1.default.Gauge({
106
+ name: `${prefix}_${METRIC_AVAILABLE_CPU_CONTAINER}`,
107
+ help: 'Available CPUs limit in container',
108
+ collect() {
109
+ return __awaiter(this, void 0, void 0, function* () {
110
+ try {
111
+ const limit = yield (0, docker_1.getCPULimit)();
112
+ this.set(limit);
113
+ }
114
+ catch (_a) { }
115
+ });
116
+ },
117
+ registers: [exports.registry],
118
+ });
119
+ })
120
+ .catch(() => {
121
+ //
122
+ });
123
+ exports.metricAvailableApps = new prom_client_1.default.Gauge({
124
+ name: `${prefix}_${METRIC_AVAILABLE_APPS}`,
125
+ help: 'Show available apps to monitor',
126
+ registers: [exports.registry],
127
+ });
128
+ // Specific app metrics
129
+ exports.metricAppInstances = new prom_client_1.default.Gauge({
130
+ name: `${prefix}_${METRIC_APP_INSTANCES}`,
131
+ help: 'Show app instances count',
132
+ registers: [exports.registry],
133
+ labelNames: ['app'],
134
+ });
135
+ exports.metricAppAverageMemory = new prom_client_1.default.Gauge({
136
+ name: `${prefix}_${METRIC_APP_AVERAGE_MEMORY}`,
137
+ help: 'Show average using memory of an app',
138
+ registers: [exports.registry],
139
+ labelNames: ['app'],
140
+ });
141
+ exports.metricAppTotalMemory = new prom_client_1.default.Gauge({
142
+ name: `${prefix}_${METRIC_APP_TOTAL_MEMORY}`,
143
+ help: 'Show total using memory of an app',
144
+ registers: [exports.registry],
145
+ labelNames: ['app'],
146
+ });
147
+ exports.metricAppAverageCpu = new prom_client_1.default.Gauge({
148
+ name: `${prefix}_${METRIC_APP_AVERAGE_CPU}`,
149
+ help: 'Show average app cpu usage',
150
+ registers: [exports.registry],
151
+ labelNames: ['app'],
152
+ });
153
+ exports.metricAppUptime = new prom_client_1.default.Gauge({
154
+ name: `${prefix}_${METRIC_APP_UPTIME}`,
155
+ help: 'Show app uptime in seconds',
156
+ registers: [exports.registry],
157
+ labelNames: ['app'],
158
+ });
159
+ exports.metricAppStatus = new prom_client_1.default.Gauge({
160
+ name: `${prefix}_${METRIC_APP_STATUS}`,
161
+ help: 'Current App status. (0-unknown,1-running,2-pending,3-stopped,4-errored)',
162
+ registers: [exports.registry],
163
+ labelNames: ['app'],
164
+ });
165
+ // Metrics with instances
166
+ exports.metricAppPidsCpuLast = new prom_client_1.default.Gauge({
167
+ name: `${prefix}_${METRIC_APP_PIDS_CPU}`,
168
+ help: 'Show current (last) usage CPU for every app instance',
169
+ registers: [exports.registry],
170
+ labelNames: ['app', 'instance'],
171
+ });
172
+ exports.metricAppPidsCpuThreshold = new prom_client_1.default.Gauge({
173
+ name: `${prefix}_${METRIC_APP_PIDS_CPU_THRESHOLD}`,
174
+ help: 'Show average CPU for every app instance to detect autoscale if module exists',
175
+ registers: [exports.registry],
176
+ labelNames: ['app', 'instance'],
177
+ });
178
+ exports.metricAppRestartCount = new prom_client_1.default.Gauge({
179
+ name: `${prefix}_${METRIC_APP_RESTART_COUNT}`,
180
+ help: 'Show restart count of the app',
181
+ registers: [exports.registry],
182
+ labelNames: ['app', 'instance'],
183
+ });
184
+ exports.metricAppPidsMemory = new prom_client_1.default.Gauge({
185
+ name: `${prefix}_${METRIC_APP_PIDS_MEMORY}`,
186
+ help: 'Show current usage memory for every app instance',
187
+ registers: [exports.registry],
188
+ labelNames: ['app', 'instance'],
189
+ });
190
+ };
191
+ exports.initMetrics = initMetrics;
192
+ const initDynamicGaugeMetricClients = (metrics) => {
193
+ metrics.forEach((entry) => {
194
+ exports.dynamicGaugeMetricClients[entry.key] = new prom_client_1.default.Gauge({
195
+ name: `${currentPrefix}_${entry.key}`,
196
+ help: entry.description,
197
+ registers: [exports.registry],
198
+ labelNames: ['app', 'instance'],
199
+ });
200
+ });
201
+ };
202
+ exports.initDynamicGaugeMetricClients = initDynamicGaugeMetricClients;
203
+ const combineAllRegistries = (needAggregate) => {
204
+ const appRegistry = (0, app_1.getAppRegistry)(needAggregate);
205
+ if (appRegistry) {
206
+ return prom_client_1.default.Registry.merge([exports.registry, appRegistry]);
207
+ }
208
+ else {
209
+ return exports.registry;
210
+ }
211
+ };
212
+ exports.combineAllRegistries = combineAllRegistries;
213
+ const deletePromAppMetrics = (appName, instances) => {
214
+ exports.metricAppInstances === null || exports.metricAppInstances === void 0 ? void 0 : exports.metricAppInstances.remove(appName);
215
+ exports.metricAppAverageMemory === null || exports.metricAppAverageMemory === void 0 ? void 0 : exports.metricAppAverageMemory.remove(appName);
216
+ exports.metricAppTotalMemory === null || exports.metricAppTotalMemory === void 0 ? void 0 : exports.metricAppTotalMemory.remove(appName);
217
+ exports.metricAppAverageCpu === null || exports.metricAppAverageCpu === void 0 ? void 0 : exports.metricAppAverageCpu.remove(appName);
218
+ exports.metricAppUptime === null || exports.metricAppUptime === void 0 ? void 0 : exports.metricAppUptime.remove(appName);
219
+ exports.metricAppStatus === null || exports.metricAppStatus === void 0 ? void 0 : exports.metricAppStatus.remove(appName);
220
+ (0, exports.deletePromAppInstancesMetrics)(appName, instances);
221
+ };
222
+ exports.deletePromAppMetrics = deletePromAppMetrics;
223
+ const deletePromAppInstancesMetrics = (appName, instances) => {
224
+ instances.forEach((pmId) => {
225
+ exports.metricAppPidsCpuLast === null || exports.metricAppPidsCpuLast === void 0 ? void 0 : exports.metricAppPidsCpuLast.remove({ app: appName, instance: pmId });
226
+ exports.metricAppPidsCpuThreshold === null || exports.metricAppPidsCpuThreshold === void 0 ? void 0 : exports.metricAppPidsCpuThreshold.remove({ app: appName, instance: pmId });
227
+ exports.metricAppRestartCount === null || exports.metricAppRestartCount === void 0 ? void 0 : exports.metricAppRestartCount.remove({ app: appName, instance: pmId });
228
+ exports.metricAppPidsMemory === null || exports.metricAppPidsMemory === void 0 ? void 0 : exports.metricAppPidsMemory.remove({ app: appName, instance: pmId });
229
+ for (const [, entry] of Object.entries(exports.dynamicGaugeMetricClients)) {
230
+ entry === null || entry === void 0 ? void 0 : entry.remove({ app: appName, instance: pmId });
231
+ }
232
+ });
233
+ };
234
+ exports.deletePromAppInstancesMetrics = deletePromAppInstancesMetrics;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.getHistogramBuckets = exports.IHistogram = void 0;
16
+ const prom_client_1 = __importDefault(require("prom-client"));
17
+ class IHistogram extends prom_client_1.default.Histogram {
18
+ constructor() {
19
+ super(...arguments);
20
+ this.values = {};
21
+ }
22
+ setValues(defaultLabels, values) {
23
+ let valueKey = '';
24
+ for (const [key, value] of Object.entries(defaultLabels)) {
25
+ valueKey += `${key}:${value};`;
26
+ }
27
+ this.values[valueKey] = values.map((entry) => {
28
+ const newEntry = Object.assign({}, entry);
29
+ const labels = Object.assign(Object.assign({}, entry.labels), defaultLabels);
30
+ newEntry.labels = labels;
31
+ return newEntry;
32
+ });
33
+ }
34
+ getForPromString() {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const values = [];
37
+ for (const [, entries] of Object.entries(this.values)) {
38
+ entries.forEach((value) => values.push(value));
39
+ }
40
+ return {
41
+ name: this.name,
42
+ help: this.help,
43
+ type: this.type,
44
+ values,
45
+ aggregator: this.aggregator,
46
+ };
47
+ });
48
+ }
49
+ }
50
+ exports.IHistogram = IHistogram;
51
+ const getHistogramBuckets = (values) => {
52
+ const labels = new Set();
53
+ values.forEach((entry) => {
54
+ Object.keys(entry.labels).forEach((label) => {
55
+ if (label === 'le' && entry.labels[label] !== '+Inf') {
56
+ labels.add(Number(entry.labels[label]));
57
+ }
58
+ });
59
+ });
60
+ return Array.from(labels);
61
+ };
62
+ exports.getHistogramBuckets = getHistogramBuckets;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ISummary = void 0;
16
+ const prom_client_1 = __importDefault(require("prom-client"));
17
+ class ISummary extends prom_client_1.default.Summary {
18
+ constructor() {
19
+ super(...arguments);
20
+ this.values = {};
21
+ }
22
+ setValues(defaultLabels, values) {
23
+ let valueKey = '';
24
+ for (const [key, value] of Object.entries(defaultLabels)) {
25
+ valueKey += `${key}:${value};`;
26
+ }
27
+ this.values[valueKey] = values.map((entry) => {
28
+ const newEntry = Object.assign({}, entry);
29
+ const labels = Object.assign(Object.assign({}, entry.labels), defaultLabels);
30
+ newEntry.labels = labels;
31
+ return newEntry;
32
+ });
33
+ }
34
+ get() {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const values = [];
37
+ for (const [, entries] of Object.entries(this.values)) {
38
+ entries.forEach((value) => values.push(value));
39
+ }
40
+ return {
41
+ name: this.name,
42
+ help: this.help,
43
+ type: this.type,
44
+ values,
45
+ aggregator: this.aggregator,
46
+ collect: () => __awaiter(this, void 0, void 0, function* () { }),
47
+ };
48
+ });
49
+ }
50
+ }
51
+ exports.ISummary = ISummary;
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@arcblock/pm2-prom-module",
3
+ "version": "2.6.1",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "PM2 module to help collect applications statistic and send it to Prometheus server",
8
+ "main": "index.js",
9
+ "dependencies": {
10
+ "pidusage": "^3.0.2",
11
+ "pm2": "^5.3.0",
12
+ "pmx": "beta",
13
+ "prom-client": "^15.1.3",
14
+ "xbytes": "^1.9.1",
15
+ "zx": "^4.3.0"
16
+ },
17
+ "scripts": {
18
+ "predev": "pm2 delete pm2-prom-module || true && npm run build",
19
+ "dev": "pm2 install .",
20
+ "build": "tsc -p tsconfig.json",
21
+ "watch": "tsc -w -p tsconfig.json",
22
+ "release": "npm run build && npm publish",
23
+ "bump:version": "zx scripts/bump-version.mjs --quiet"
24
+ },
25
+ "files": [
26
+ "README.md",
27
+ "**/*.js"
28
+ ],
29
+ "apps": [
30
+ {
31
+ "merge_logs": true,
32
+ "max_memory_restart": "1024M",
33
+ "script": "index.js"
34
+ }
35
+ ],
36
+ "config": {
37
+ "port": "9988",
38
+ "hostname": "0.0.0.0",
39
+ "unix_socket_path": "",
40
+ "service_name": "",
41
+ "debug": false,
42
+ "aggregate_app_metrics": true,
43
+ "app_check_interval": 1000,
44
+ "prefix": "pm2"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^18.19.50",
48
+ "@types/pidusage": "^2.0.5",
49
+ "bumpp": "^10.1.0",
50
+ "typescript": "^5.3.3"
51
+ },
52
+ "engines": {
53
+ "node": ">=14"
54
+ },
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "https://github.com/VeXell/pm2-prom-module.git"
58
+ },
59
+ "author": "Viacheslav Volkov (vexell@gmail.com)",
60
+ "license": "MIT",
61
+ "keywords": [
62
+ "PM2",
63
+ "Prometheus",
64
+ "Metrics",
65
+ "Monitoring",
66
+ "Prom client",
67
+ "Module",
68
+ "Node.js",
69
+ "Javascript"
70
+ ]
71
+ }
package/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/utils/cpu.js ADDED
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getPidsUsage = exports.getCpuCount = void 0;
7
+ const node_child_process_1 = require("node:child_process");
8
+ const node_os_1 = __importDefault(require("node:os"));
9
+ const pidusage_1 = __importDefault(require("pidusage"));
10
+ // We also get it from nproc and use the minimum of the two.
11
+ const getConcurrencyFromNProc = () => {
12
+ try {
13
+ return parseInt((0, node_child_process_1.execSync)('nproc', { stdio: 'pipe' }).toString().trim(), 10);
14
+ }
15
+ catch (error) {
16
+ return null;
17
+ }
18
+ };
19
+ const getCpuCount = () => {
20
+ if (node_os_1.default.availableParallelism) {
21
+ return node_os_1.default.availableParallelism();
22
+ }
23
+ const node = node_os_1.default.cpus().length;
24
+ const nproc = getConcurrencyFromNProc();
25
+ if (nproc === null) {
26
+ return node;
27
+ }
28
+ return Math.min(nproc, node);
29
+ };
30
+ exports.getCpuCount = getCpuCount;
31
+ const getPidsUsage = (pids) => {
32
+ return new Promise((resolve, reject) => {
33
+ if (pids.length) {
34
+ (0, pidusage_1.default)(pids, (err, stats) => {
35
+ if (err) {
36
+ reject(err);
37
+ }
38
+ resolve(stats);
39
+ });
40
+ }
41
+ else {
42
+ resolve({});
43
+ }
44
+ });
45
+ };
46
+ exports.getPidsUsage = getPidsUsage;
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.getDockerStats = exports.getCPULimit = exports.getFreeMemory = exports.getUsedMemory = exports.getAvailableMemory = exports.hasDockerLimitFiles = void 0;
16
+ const promises_1 = require("node:fs/promises");
17
+ const node_os_1 = __importDefault(require("node:os"));
18
+ const cpu_1 = require("./cpu");
19
+ const zx_1 = require("zx");
20
+ const xbytes_1 = __importDefault(require("xbytes"));
21
+ // 禁用命令和结果的自动输出
22
+ zx_1.$.verbose = false;
23
+ //const MEMORY_AVAILABLE = '/sys/fs/cgroup/memory.limit_in_bytes';
24
+ //const MEMORY_USED = '/sys/fs/cgroup/memory.usage_in_bytes';
25
+ const MEMORY_AVAILABLE = '/sys/fs/cgroup/memory.max';
26
+ const MEMORY_USED = '/sys/fs/cgroup/memory.current';
27
+ const CPUS_LIMIT = '/sys/fs/cgroup/cpu.max';
28
+ const hasDockerLimitFiles = () => __awaiter(void 0, void 0, void 0, function* () {
29
+ yield (0, promises_1.access)(MEMORY_AVAILABLE, promises_1.constants.R_OK);
30
+ });
31
+ exports.hasDockerLimitFiles = hasDockerLimitFiles;
32
+ const getAvailableMemory = () => __awaiter(void 0, void 0, void 0, function* () {
33
+ try {
34
+ const data = (yield (0, promises_1.readFile)(MEMORY_AVAILABLE, { encoding: 'utf8' })).trim();
35
+ if (data === 'max') {
36
+ return node_os_1.default.totalmem();
37
+ }
38
+ else {
39
+ const memoryNumber = parseInt(data, 10);
40
+ if (isNaN(memoryNumber)) {
41
+ return 0;
42
+ }
43
+ else {
44
+ return memoryNumber;
45
+ }
46
+ }
47
+ }
48
+ catch (_a) {
49
+ return 0;
50
+ }
51
+ });
52
+ exports.getAvailableMemory = getAvailableMemory;
53
+ const getUsedMemory = () => __awaiter(void 0, void 0, void 0, function* () {
54
+ try {
55
+ const data = (yield (0, promises_1.readFile)(MEMORY_USED, { encoding: 'utf8' })).trim();
56
+ const usedMemory = parseInt(data, 10);
57
+ if (isNaN(usedMemory)) {
58
+ return 0;
59
+ }
60
+ else {
61
+ return usedMemory;
62
+ }
63
+ }
64
+ catch (_b) {
65
+ return 0;
66
+ }
67
+ });
68
+ exports.getUsedMemory = getUsedMemory;
69
+ const getFreeMemory = () => __awaiter(void 0, void 0, void 0, function* () {
70
+ try {
71
+ const data = (yield (0, promises_1.readFile)(MEMORY_AVAILABLE, { encoding: 'utf8' })).trim();
72
+ const systemFreeMem = node_os_1.default.freemem();
73
+ if (data === 'max') {
74
+ // In that case we do not have any limits. Use only freemem
75
+ return systemFreeMem;
76
+ }
77
+ // In that case we should calculate free memory
78
+ const availableMemory = parseInt(data, 10);
79
+ if (isNaN(availableMemory)) {
80
+ // If we can not parse return OS Free memory
81
+ return systemFreeMem;
82
+ }
83
+ const usedMemory = yield (0, exports.getUsedMemory)();
84
+ if (availableMemory <= systemFreeMem) {
85
+ // We have docker limit in the container
86
+ return availableMemory - usedMemory;
87
+ }
88
+ else {
89
+ // Limited by system available memory
90
+ return systemFreeMem;
91
+ }
92
+ }
93
+ catch (_c) {
94
+ return 0;
95
+ }
96
+ });
97
+ exports.getFreeMemory = getFreeMemory;
98
+ const getCPULimit = () => __awaiter(void 0, void 0, void 0, function* () {
99
+ let count = (0, cpu_1.getCpuCount)();
100
+ const delimeter = 100000;
101
+ try {
102
+ const data = (yield (0, promises_1.readFile)(CPUS_LIMIT, { encoding: 'utf8' })).trim();
103
+ if (data) {
104
+ const values = data.split(' ');
105
+ if (values.length === 2) {
106
+ const parsedValue = parseInt(values[0], 10);
107
+ if (!isNaN(parsedValue)) {
108
+ count = parsedValue / delimeter;
109
+ }
110
+ }
111
+ }
112
+ }
113
+ catch (_d) { }
114
+ return count;
115
+ });
116
+ exports.getCPULimit = getCPULimit;
117
+ function getDockerStats(ids) {
118
+ return __awaiter(this, void 0, void 0, function* () {
119
+ try {
120
+ if (!ids.length) {
121
+ return [];
122
+ }
123
+ const result = yield (0, zx_1.$) `docker stats --no-stream --format "{{json .}}" -a`;
124
+ if (result.exitCode || !result.stdout) {
125
+ return [];
126
+ }
127
+ const statsRows = result.stdout
128
+ .split('\n')
129
+ .filter(Boolean)
130
+ .map((x) => JSON.parse(x));
131
+ const stats = statsRows.map((x) => {
132
+ const [memoryUsage, totalMemory] = x.MemUsage.split('/').map((x) => xbytes_1.default.parseSize(x.trim()));
133
+ return {
134
+ name: x.Name,
135
+ cpuUsage: +x.CPUPerc.replace('%', ''),
136
+ memoryUsage: memoryUsage,
137
+ totalMemory: totalMemory,
138
+ };
139
+ });
140
+ return ids.map((id) => {
141
+ return stats.find((x) => x.name === id);
142
+ });
143
+ }
144
+ catch (error) {
145
+ console.error(error);
146
+ return [];
147
+ }
148
+ });
149
+ }
150
+ exports.getDockerStats = getDockerStats;
package/utils/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toUndescore = void 0;
4
+ function toUndescore(str) {
5
+ return str.toLowerCase().replace(/\s+/g, '_');
6
+ }
7
+ exports.toUndescore = toUndescore;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logger = exports.getLogger = exports.initLogger = void 0;
4
+ class SimpleLogger {
5
+ constructor(isDebug = false) {
6
+ this.isDebug = false;
7
+ this.isDebug = isDebug;
8
+ }
9
+ debug(message) {
10
+ if (this.isDebug) {
11
+ const value = `DEBUG: ${message}`;
12
+ this.log(value);
13
+ }
14
+ }
15
+ error(message) {
16
+ const value = `ERROR: ${message}`;
17
+ this.logError(value);
18
+ }
19
+ info(message) {
20
+ const value = `INFO: ${message}`;
21
+ this.log(value);
22
+ }
23
+ log(message) {
24
+ console.log(message);
25
+ }
26
+ logError(message) {
27
+ console.error(message);
28
+ }
29
+ }
30
+ let loggerInstance;
31
+ const initLogger = ({ isDebug }) => {
32
+ if (!loggerInstance) {
33
+ loggerInstance = new SimpleLogger(isDebug);
34
+ }
35
+ };
36
+ exports.initLogger = initLogger;
37
+ const getLogger = () => {
38
+ if (!loggerInstance) {
39
+ loggerInstance = new SimpleLogger();
40
+ }
41
+ return loggerInstance;
42
+ };
43
+ exports.getLogger = getLogger;
44
+ exports.logger = (0, exports.getLogger)();