badmfck-api-server 4.1.25 → 4.1.26

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.
@@ -13,6 +13,19 @@ export type THttpErr<E = any> = {
13
13
  details?: any;
14
14
  };
15
15
  export type THttpResult<T, E = any> = THttpOk<T> | THttpErr<E>;
16
+ export type THttpOutgoingLogItem = {
17
+ id: number;
18
+ created: number;
19
+ time: number;
20
+ method: HttpMethod;
21
+ url: string;
22
+ status?: number;
23
+ ok: boolean;
24
+ attempts: number;
25
+ request: any;
26
+ response: any;
27
+ error?: string;
28
+ };
16
29
  export type TRetryPolicy = {
17
30
  enabled?: boolean;
18
31
  maxAttempts?: number;
@@ -71,6 +84,12 @@ export declare class Http {
71
84
  private static _activeConnectionsByHost;
72
85
  private static _countedSockets;
73
86
  private static _socketHostKey;
87
+ private static _outgoingLog;
88
+ private static _nextOutgoingLogID;
89
+ private static _outgoingLogLimit;
90
+ private static _truncate;
91
+ private static _pushOutgoingLog;
92
+ static getOutgoingLogSnapshot(): THttpOutgoingLogItem[];
74
93
  private static ensureInit;
75
94
  static configure(partial: Partial<THttpConfig>): void;
76
95
  static createAgent(opts?: ConstructorParameters<typeof Agent>[0]): Agent;
@@ -88,6 +88,40 @@ class Http {
88
88
  static _activeConnectionsByHost = new Map();
89
89
  static _countedSockets = new WeakSet();
90
90
  static _socketHostKey = new WeakMap();
91
+ static _outgoingLog = [];
92
+ static _nextOutgoingLogID = 0;
93
+ static _outgoingLogLimit = 500;
94
+ static _truncate(v) {
95
+ if (v === undefined || v === null)
96
+ return v;
97
+ if (Buffer.isBuffer(v))
98
+ return `[Buffer ${v.length} bytes]`;
99
+ let json = "";
100
+ try {
101
+ json = JSON.stringify(v, (_, val) => {
102
+ if (typeof val === "string" && val.length > 255)
103
+ return val.slice(0, 255) + `...(${val.length})`;
104
+ if (Buffer.isBuffer(val))
105
+ return `[Buffer ${val.length} bytes]`;
106
+ return val;
107
+ });
108
+ }
109
+ catch {
110
+ return "[unserializable]";
111
+ }
112
+ return json.length > 500 ? json.slice(0, 500) + `...(total ${json.length})` : json;
113
+ }
114
+ static _pushOutgoingLog(item) {
115
+ const entry = { id: this._nextOutgoingLogID++, ...item };
116
+ this._outgoingLog.push(entry);
117
+ if (this._outgoingLog.length > this._outgoingLogLimit)
118
+ this._outgoingLog.shift();
119
+ if (this._nextOutgoingLogID > Number.MAX_SAFE_INTEGER - 1000)
120
+ this._nextOutgoingLogID = 0;
121
+ }
122
+ static getOutgoingLogSnapshot() {
123
+ return this._outgoingLog.slice();
124
+ }
91
125
  static ensureInit() {
92
126
  if (this._inited)
93
127
  return;
@@ -230,6 +264,7 @@ class Http {
230
264
  static async request(opts) {
231
265
  MonitorService_1.S_STAT_REGISTRATE_HTTP_REQUEST.invoke({ url: opts.url });
232
266
  this.ensureInit();
267
+ const overallStarted = Date.now();
233
268
  const cfg = this.config;
234
269
  const retryCfg = {
235
270
  enabled: opts.retry?.enabled ?? cfg.retry?.enabled ?? true,
@@ -263,7 +298,24 @@ class Http {
263
298
  }
264
299
  const responseType = opts.responseType ?? "json";
265
300
  const throwOnJsonParseError = opts.throwOnJsonParseError ?? false;
301
+ let attemptsMade = 0;
302
+ const finish = (result, networkErr) => {
303
+ Http._pushOutgoingLog({
304
+ created: overallStarted,
305
+ time: Date.now() - overallStarted,
306
+ method: opts.method,
307
+ url,
308
+ status: result.status,
309
+ ok: result.ok,
310
+ attempts: attemptsMade,
311
+ request: Http._truncate(opts.body),
312
+ response: Http._truncate(result.ok ? result.data : result.error),
313
+ error: networkErr ? String(networkErr?.message ?? networkErr) : undefined,
314
+ });
315
+ return result;
316
+ };
266
317
  for (let attempt = 1; attempt <= retryCfg.maxAttempts; attempt++) {
318
+ attemptsMade = attempt;
267
319
  const started = Date.now();
268
320
  cfg.onRequest?.({ method: opts.method, url, attempt });
269
321
  const controller = new AbortController();
@@ -307,7 +359,7 @@ class Http {
307
359
  }
308
360
  }
309
361
  if (status >= 200 && status < 300) {
310
- return { ok: true, status, data: parsed, headers: hdrs };
362
+ return finish({ ok: true, status, data: parsed, headers: hdrs });
311
363
  }
312
364
  const retryable = retryCfg.enabled &&
313
365
  isRetryableStatus(status, retryCfg.retryOnStatuses) &&
@@ -317,7 +369,7 @@ class Http {
317
369
  await sleep(backoff);
318
370
  continue;
319
371
  }
320
- return { ok: false, status, error: parsed, details: { headers: hdrs } };
372
+ return finish({ ok: false, status, error: parsed, details: { headers: hdrs } });
321
373
  }
322
374
  catch (err) {
323
375
  const ms = Date.now() - started;
@@ -331,13 +383,13 @@ class Http {
331
383
  await sleep(backoff);
332
384
  continue;
333
385
  }
334
- return { ok: false, error: err, details: { network: true } };
386
+ return finish({ ok: false, error: err, details: { network: true } }, err);
335
387
  }
336
388
  finally {
337
389
  clearTimeout(t);
338
390
  }
339
391
  }
340
- return { ok: false, error: "UNKNOWN" };
392
+ return finish({ ok: false, error: "UNKNOWN" });
341
393
  }
342
394
  static get(url, opts) {
343
395
  return this.request({ ...(opts || {}), method: "GET", url });
@@ -20,6 +20,9 @@ export declare class Monitor extends BaseEndpoint {
20
20
  changeLogLevel(req: HTTPRequestVO): Promise<TransferPacketVO>;
21
21
  logs(req: HTTPRequestVO): Promise<TransferPacketVO>;
22
22
  netlog(req: HTTPRequestVO): Promise<TransferPacketVO>;
23
+ outgoingNetlog(req: HTTPRequestVO): Promise<TransferPacketVO>;
24
+ sysinfo(req: HTTPRequestVO): Promise<TransferPacketVO>;
25
+ procinfo(req: HTTPRequestVO): Promise<TransferPacketVO>;
23
26
  metrics(req: HTTPRequestVO): Promise<TransferPacketVO>;
24
27
  connections(req: HTTPRequestVO): Promise<TransferPacketVO>;
25
28
  db(req: HTTPRequestVO): Promise<TransferPacketVO>;
@@ -15,6 +15,8 @@ const path_1 = __importDefault(require("path"));
15
15
  const Http_1 = require("../http/Http");
16
16
  const MonitorService_1 = require("../MonitorService");
17
17
  const DBService_1 = require("../DBService");
18
+ const SystemInfo_1 = require("./SystemInfo");
19
+ const ProcessMonitor_1 = require("./ProcessMonitor");
18
20
  exports.S_MONITOR_REGISTRATE_ACTION = new badmfck_signal_1.Signal();
19
21
  const logMap = {
20
22
  ALL: 10,
@@ -39,6 +41,9 @@ class Monitor extends BaseEndpoint_1.BaseEndpoint {
39
41
  { ignoreInterceptor: true, endpoint: "html", handler: this.html },
40
42
  { ignoreInterceptor: true, endpoint: "log", handler: this.logs },
41
43
  { ignoreInterceptor: true, endpoint: "netlog", handler: this.netlog },
44
+ { ignoreInterceptor: true, endpoint: "outgoingnetlog", handler: this.outgoingNetlog },
45
+ { ignoreInterceptor: true, endpoint: "sysinfo", handler: this.sysinfo },
46
+ { ignoreInterceptor: true, endpoint: "procinfo", handler: this.procinfo },
42
47
  { ignoreInterceptor: true, endpoint: "metrics", handler: this.metrics, validationModel: {
43
48
  range: "",
44
49
  $__range_values: ["week", "day", "hour"]
@@ -120,6 +125,18 @@ class Monitor extends BaseEndpoint_1.BaseEndpoint {
120
125
  const log = await APIService_1.REQ_HTTP_LOG.request(req.data);
121
126
  return { data: log };
122
127
  }
128
+ async outgoingNetlog(req) {
129
+ await this.checkAuthentication(req);
130
+ return { data: Http_1.Http.getOutgoingLogSnapshot() };
131
+ }
132
+ async sysinfo(req) {
133
+ await this.checkAuthentication(req);
134
+ return { data: await (0, SystemInfo_1.collectSystemInfo)() };
135
+ }
136
+ async procinfo(req) {
137
+ await this.checkAuthentication(req);
138
+ return { data: await ProcessMonitor_1.ProcessMonitor.getSnapshot() };
139
+ }
123
140
  async metrics(req) {
124
141
  await this.checkAuthentication(req);
125
142
  const result = await MonitorService_1.REQ_STAT.request(req.data);
@@ -0,0 +1,117 @@
1
+ /// <reference types="node" />
2
+ export declare class ProcessMonitor {
3
+ private static _inited;
4
+ private static _eld;
5
+ private static _gcObserver;
6
+ private static _gc;
7
+ private static _prevCpu;
8
+ private static _prevCpuAt;
9
+ private static _cpuPct;
10
+ private static _eluPrev;
11
+ private static _elu;
12
+ private static _processStartedAt;
13
+ static init(): void;
14
+ private static _sampleCpu;
15
+ private static _sampleELU;
16
+ private static _mapGcKind;
17
+ static getSnapshot(): Promise<{
18
+ identity: {
19
+ pid: number;
20
+ ppid: number;
21
+ title: string;
22
+ argv: string[];
23
+ execPath: string;
24
+ cwd: string;
25
+ nodeVersion: string;
26
+ v8Version: string;
27
+ platform: NodeJS.Platform;
28
+ arch: NodeJS.Architecture;
29
+ hostname: string;
30
+ user: {
31
+ uid: number;
32
+ gid: number;
33
+ } | null;
34
+ startedAtUnix: number;
35
+ uptimeSec: number;
36
+ availableParallelism: number;
37
+ };
38
+ memory: {
39
+ rss: number;
40
+ heapTotal: number;
41
+ heapUsed: number;
42
+ external: number;
43
+ arrayBuffers: any;
44
+ heap: {
45
+ sizeLimit: number;
46
+ usedHeap: number;
47
+ totalAvailable: number;
48
+ totalPhysical: number;
49
+ mallocedMemory: number;
50
+ peakMallocedMemory: number;
51
+ numberOfNativeContexts: number;
52
+ numberOfDetachedContexts: number;
53
+ };
54
+ heapSpaces: {
55
+ name: string;
56
+ size: number;
57
+ used: number;
58
+ available: number;
59
+ physical: number;
60
+ }[];
61
+ procStatus: Record<string, number> | null;
62
+ };
63
+ cpu: {
64
+ userPct: number;
65
+ systemPct: number;
66
+ userMicros: number;
67
+ systemMicros: number;
68
+ resource: any;
69
+ };
70
+ eventLoop: {
71
+ minMs: number;
72
+ maxMs: number;
73
+ meanMs: number;
74
+ stddevMs: number;
75
+ p50Ms: number;
76
+ p90Ms: number;
77
+ p99Ms: number;
78
+ utilizationPct: number;
79
+ activeHandles: number;
80
+ activeRequests: number;
81
+ spotLagMs: number;
82
+ } | null;
83
+ gc: {
84
+ totalCount: number;
85
+ totalTimeMs: number;
86
+ maxPauseMs: number;
87
+ byKind: Record<string, {
88
+ count: number;
89
+ timeMs: number;
90
+ }>;
91
+ lastPauses: {
92
+ kind: string;
93
+ ms: number;
94
+ timestamp: number;
95
+ }[];
96
+ };
97
+ fileDescriptors: {
98
+ open: number | null;
99
+ limitSoft: number | null;
100
+ limitHard: number | null;
101
+ };
102
+ io: Record<string, number> | null;
103
+ limits: Record<string, {
104
+ soft: string;
105
+ hard: string;
106
+ unit: string;
107
+ }> | null;
108
+ }>;
109
+ private static _readProcStatus;
110
+ private static _readProcIo;
111
+ private static _readProcLimits;
112
+ private static _countFds;
113
+ private static _parseLimitValue;
114
+ private static _toMsFinite;
115
+ private static _safePercentileMs;
116
+ private static _safeCount;
117
+ }
@@ -0,0 +1,308 @@
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.ProcessMonitor = void 0;
7
+ const os_1 = __importDefault(require("os"));
8
+ const v8_1 = __importDefault(require("v8"));
9
+ const perf_hooks_1 = require("perf_hooks");
10
+ const promises_1 = __importDefault(require("fs/promises"));
11
+ class ProcessMonitor {
12
+ static _inited = false;
13
+ static _eld = null;
14
+ static _gcObserver = null;
15
+ static _gc = {
16
+ totalCount: 0,
17
+ totalTimeMs: 0,
18
+ maxPauseMs: 0,
19
+ byKind: {},
20
+ lastPauses: [],
21
+ };
22
+ static _prevCpu = process.cpuUsage();
23
+ static _prevCpuAt = Date.now();
24
+ static _cpuPct = { userPct: 0, systemPct: 0 };
25
+ static _eluPrev = perf_hooks_1.performance.eventLoopUtilization();
26
+ static _elu = { idle: 0, active: 0, utilizationPct: 0 };
27
+ static _processStartedAt = Date.now() - process.uptime() * 1000;
28
+ static init() {
29
+ if (this._inited)
30
+ return;
31
+ this._inited = true;
32
+ this._eld = (0, perf_hooks_1.monitorEventLoopDelay)({ resolution: 20 });
33
+ this._eld.enable();
34
+ this._gcObserver = new perf_hooks_1.PerformanceObserver((list) => {
35
+ for (const entry of list.getEntries()) {
36
+ const kind = this._mapGcKind(entry.detail?.kind ?? entry.kind);
37
+ this._gc.totalCount++;
38
+ this._gc.totalTimeMs += entry.duration;
39
+ if (entry.duration > this._gc.maxPauseMs)
40
+ this._gc.maxPauseMs = entry.duration;
41
+ const bucket = this._gc.byKind[kind] ?? { count: 0, timeMs: 0 };
42
+ bucket.count++;
43
+ bucket.timeMs += entry.duration;
44
+ this._gc.byKind[kind] = bucket;
45
+ this._gc.lastPauses.push({ kind, ms: entry.duration, timestamp: Date.now() });
46
+ if (this._gc.lastPauses.length > 20)
47
+ this._gc.lastPauses.shift();
48
+ }
49
+ });
50
+ try {
51
+ this._gcObserver.observe({ entryTypes: ["gc"], buffered: false });
52
+ }
53
+ catch {
54
+ try {
55
+ this._gcObserver.observe({ type: "gc" });
56
+ }
57
+ catch { }
58
+ }
59
+ const cpuTimer = setInterval(() => this._sampleCpu(), 5000);
60
+ if (cpuTimer.unref)
61
+ cpuTimer.unref();
62
+ const eluTimer = setInterval(() => this._sampleELU(), 5000);
63
+ if (eluTimer.unref)
64
+ eluTimer.unref();
65
+ }
66
+ static _sampleCpu() {
67
+ const now = process.cpuUsage();
68
+ const nowAt = Date.now();
69
+ const dtMs = nowAt - this._prevCpuAt;
70
+ if (dtMs <= 0)
71
+ return;
72
+ const userPct = (now.user - this._prevCpu.user) / (dtMs * 1000) * 100;
73
+ const systemPct = (now.system - this._prevCpu.system) / (dtMs * 1000) * 100;
74
+ this._cpuPct = {
75
+ userPct: Math.round(userPct * 10) / 10,
76
+ systemPct: Math.round(systemPct * 10) / 10,
77
+ };
78
+ this._prevCpu = now;
79
+ this._prevCpuAt = nowAt;
80
+ }
81
+ static _sampleELU() {
82
+ const cur = perf_hooks_1.performance.eventLoopUtilization();
83
+ const delta = perf_hooks_1.performance.eventLoopUtilization(cur, this._eluPrev);
84
+ this._elu = {
85
+ idle: delta.idle,
86
+ active: delta.active,
87
+ utilizationPct: Math.round(delta.utilization * 10000) / 100,
88
+ };
89
+ this._eluPrev = cur;
90
+ }
91
+ static _mapGcKind(kind) {
92
+ if (typeof kind === "string")
93
+ return kind;
94
+ switch (kind) {
95
+ case 1: return "minor";
96
+ case 2: return "major";
97
+ case 4: return "incremental";
98
+ case 8: return "weakcb";
99
+ case 15: return "all";
100
+ default: return "unknown";
101
+ }
102
+ }
103
+ static async getSnapshot() {
104
+ const tStart = process.hrtime.bigint();
105
+ await new Promise(r => setImmediate(() => r()));
106
+ const spotLagMs = Number(process.hrtime.bigint() - tStart) / 1e6;
107
+ const mem = process.memoryUsage();
108
+ const heap = v8_1.default.getHeapStatistics();
109
+ const heapSpaces = v8_1.default.getHeapSpaceStatistics().map(s => ({
110
+ name: s.space_name,
111
+ size: s.space_size,
112
+ used: s.space_used_size,
113
+ available: s.space_available_size,
114
+ physical: s.physical_space_size,
115
+ }));
116
+ const procStatus = await this._readProcStatus();
117
+ const io = await this._readProcIo();
118
+ const limitsParsed = await this._readProcLimits();
119
+ const cpuTotal = process.cpuUsage();
120
+ let resource = null;
121
+ try {
122
+ const r = process.resourceUsage();
123
+ resource = {
124
+ maxRSS: r.maxRSS,
125
+ voluntaryContextSwitches: r.voluntaryContextSwitches,
126
+ involuntaryContextSwitches: r.involuntaryContextSwitches,
127
+ fsRead: r.fsRead,
128
+ fsWrite: r.fsWrite,
129
+ signalsCount: r.signalsCount,
130
+ ipcSent: r.ipcSent,
131
+ ipcReceived: r.ipcReceived,
132
+ userCPUTimeMs: Math.round(r.userCPUTime / 1000),
133
+ systemCPUTimeMs: Math.round(r.systemCPUTime / 1000),
134
+ };
135
+ }
136
+ catch { }
137
+ const fdOpen = await this._countFds();
138
+ const fdSoft = limitsParsed?.["Max open files"]?.soft;
139
+ const fdHard = limitsParsed?.["Max open files"]?.hard;
140
+ const h = this._eld;
141
+ const eventLoop = h ? {
142
+ minMs: this._toMsFinite(h.min),
143
+ maxMs: this._toMsFinite(h.max),
144
+ meanMs: this._toMsFinite(h.mean),
145
+ stddevMs: this._toMsFinite(h.stddev),
146
+ p50Ms: this._safePercentileMs(h, 50),
147
+ p90Ms: this._safePercentileMs(h, 90),
148
+ p99Ms: this._safePercentileMs(h, 99),
149
+ utilizationPct: this._elu.utilizationPct,
150
+ activeHandles: this._safeCount(() => process._getActiveHandles?.()?.length),
151
+ activeRequests: this._safeCount(() => process._getActiveRequests?.()?.length),
152
+ spotLagMs: Math.round(spotLagMs * 100) / 100,
153
+ } : null;
154
+ return {
155
+ identity: {
156
+ pid: process.pid,
157
+ ppid: process.ppid,
158
+ title: process.title,
159
+ argv: process.argv,
160
+ execPath: process.execPath,
161
+ cwd: process.cwd(),
162
+ nodeVersion: process.version,
163
+ v8Version: process.versions.v8,
164
+ platform: process.platform,
165
+ arch: process.arch,
166
+ hostname: os_1.default.hostname(),
167
+ user: typeof process.getuid === "function"
168
+ ? { uid: process.getuid(), gid: process.getgid?.() ?? -1 }
169
+ : null,
170
+ startedAtUnix: this._processStartedAt,
171
+ uptimeSec: Math.round(process.uptime()),
172
+ availableParallelism: typeof os_1.default.availableParallelism === "function"
173
+ ? os_1.default.availableParallelism()
174
+ : os_1.default.cpus().length,
175
+ },
176
+ memory: {
177
+ rss: mem.rss,
178
+ heapTotal: mem.heapTotal,
179
+ heapUsed: mem.heapUsed,
180
+ external: mem.external,
181
+ arrayBuffers: mem.arrayBuffers ?? 0,
182
+ heap: {
183
+ sizeLimit: heap.heap_size_limit,
184
+ usedHeap: heap.used_heap_size,
185
+ totalAvailable: heap.total_available_size,
186
+ totalPhysical: heap.total_physical_size,
187
+ mallocedMemory: heap.malloced_memory,
188
+ peakMallocedMemory: heap.peak_malloced_memory,
189
+ numberOfNativeContexts: heap.number_of_native_contexts,
190
+ numberOfDetachedContexts: heap.number_of_detached_contexts,
191
+ },
192
+ heapSpaces,
193
+ procStatus,
194
+ },
195
+ cpu: {
196
+ userPct: this._cpuPct.userPct,
197
+ systemPct: this._cpuPct.systemPct,
198
+ userMicros: cpuTotal.user,
199
+ systemMicros: cpuTotal.system,
200
+ resource,
201
+ },
202
+ eventLoop,
203
+ gc: {
204
+ totalCount: this._gc.totalCount,
205
+ totalTimeMs: Math.round(this._gc.totalTimeMs * 100) / 100,
206
+ maxPauseMs: Math.round(this._gc.maxPauseMs * 100) / 100,
207
+ byKind: this._gc.byKind,
208
+ lastPauses: this._gc.lastPauses.slice(-20),
209
+ },
210
+ fileDescriptors: {
211
+ open: fdOpen,
212
+ limitSoft: fdSoft ? this._parseLimitValue(fdSoft) : null,
213
+ limitHard: fdHard ? this._parseLimitValue(fdHard) : null,
214
+ },
215
+ io,
216
+ limits: limitsParsed,
217
+ };
218
+ }
219
+ static async _readProcStatus() {
220
+ try {
221
+ const txt = await promises_1.default.readFile(`/proc/${process.pid}/status`, "utf-8");
222
+ const keys = ["VmPeak", "VmSize", "VmHWM", "VmRSS", "VmData", "VmStk", "VmExe", "VmSwap", "Threads"];
223
+ const result = {};
224
+ for (const line of txt.split("\n")) {
225
+ for (const k of keys) {
226
+ if (line.startsWith(k + ":")) {
227
+ const m = line.match(new RegExp(`${k}:\\s+(\\d+)`));
228
+ if (m) {
229
+ const v = parseInt(m[1], 10);
230
+ result[k] = k === "Threads" ? v : v * 1024;
231
+ }
232
+ }
233
+ }
234
+ }
235
+ return result;
236
+ }
237
+ catch {
238
+ return null;
239
+ }
240
+ }
241
+ static async _readProcIo() {
242
+ try {
243
+ const txt = await promises_1.default.readFile(`/proc/${process.pid}/io`, "utf-8");
244
+ const result = {};
245
+ for (const line of txt.split("\n")) {
246
+ const m = line.match(/^(\w+):\s+(\d+)$/);
247
+ if (m)
248
+ result[m[1]] = parseInt(m[2], 10);
249
+ }
250
+ return result;
251
+ }
252
+ catch {
253
+ return null;
254
+ }
255
+ }
256
+ static async _readProcLimits() {
257
+ try {
258
+ const txt = await promises_1.default.readFile(`/proc/${process.pid}/limits`, "utf-8");
259
+ const result = {};
260
+ const lines = txt.split("\n").slice(1);
261
+ for (const line of lines) {
262
+ const m = line.match(/^(.+?)\s{2,}(\S+)\s+(\S+)\s+(\S+)\s*$/);
263
+ if (m)
264
+ result[m[1].trim()] = { soft: m[2], hard: m[3], unit: m[4] };
265
+ }
266
+ return result;
267
+ }
268
+ catch {
269
+ return null;
270
+ }
271
+ }
272
+ static async _countFds() {
273
+ try {
274
+ const entries = await promises_1.default.readdir(`/proc/${process.pid}/fd`);
275
+ return entries.length;
276
+ }
277
+ catch {
278
+ return null;
279
+ }
280
+ }
281
+ static _parseLimitValue(v) {
282
+ if (v === "unlimited")
283
+ return -1;
284
+ const n = parseInt(v, 10);
285
+ return Number.isFinite(n) ? n : null;
286
+ }
287
+ static _toMsFinite(ns) {
288
+ return Number.isFinite(ns) ? Math.round((ns / 1e6) * 100) / 100 : 0;
289
+ }
290
+ static _safePercentileMs(h, p) {
291
+ try {
292
+ return this._toMsFinite(h.percentile(p));
293
+ }
294
+ catch {
295
+ return 0;
296
+ }
297
+ }
298
+ static _safeCount(fn) {
299
+ try {
300
+ return fn() ?? 0;
301
+ }
302
+ catch {
303
+ return 0;
304
+ }
305
+ }
306
+ }
307
+ exports.ProcessMonitor = ProcessMonitor;
308
+ ProcessMonitor.init();
@@ -0,0 +1,71 @@
1
+ /// <reference types="node" />
2
+ export declare function collectSystemInfo(): Promise<{
3
+ cpu: {
4
+ usage: {
5
+ userPct: number;
6
+ systemPct: number;
7
+ idlePct: number;
8
+ iowaitPct: number;
9
+ } | null;
10
+ count: number;
11
+ models: Record<string, number>;
12
+ loadAvg: number[];
13
+ platform: NodeJS.Platform;
14
+ arch: NodeJS.Architecture;
15
+ uptimeSec: number;
16
+ };
17
+ memory: {
18
+ total: number;
19
+ free: number;
20
+ used: number;
21
+ usedPct: number;
22
+ };
23
+ disk: {
24
+ filesystem: string;
25
+ size: number;
26
+ used: number;
27
+ available: number;
28
+ usePct: string;
29
+ mount: string;
30
+ }[] | null;
31
+ connections: {
32
+ ports: number[];
33
+ total: number;
34
+ topRemote: {
35
+ ip: string;
36
+ count: number;
37
+ }[];
38
+ } | null;
39
+ nginx: {
40
+ installed: boolean;
41
+ version?: undefined;
42
+ status?: undefined;
43
+ listening?: undefined;
44
+ workerCount?: undefined;
45
+ } | {
46
+ installed: boolean;
47
+ version: string;
48
+ status: string;
49
+ listening: string[];
50
+ workerCount: number;
51
+ } | {
52
+ installed: boolean;
53
+ error: string;
54
+ };
55
+ pm2: {
56
+ installed: boolean;
57
+ error?: undefined;
58
+ processes?: undefined;
59
+ } | {
60
+ installed: boolean;
61
+ error: string;
62
+ processes?: undefined;
63
+ } | {
64
+ installed: boolean;
65
+ processes: any;
66
+ error?: undefined;
67
+ } | {
68
+ installed: boolean;
69
+ error: string;
70
+ };
71
+ }>;