thinknagent 0.1.23 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/history.js +1 -0
- package/lib/metrics.js +46 -18
- package/package.json +1 -1
package/lib/history.js
CHANGED
|
@@ -56,6 +56,7 @@ class HistoryManager {
|
|
|
56
56
|
load: metrics.cpu?.loadAvg ?? 0,
|
|
57
57
|
mem: metrics.memory?.usedPct ?? 0,
|
|
58
58
|
memUsedMB: Math.round((metrics.memory?.used || 0) / (1024 * 1024)),
|
|
59
|
+
buffcache: metrics.memory?.buffcache ?? 0,
|
|
59
60
|
rxSec: metrics.network?.[0]?.rxSec ?? 0,
|
|
60
61
|
txSec: metrics.network?.[0]?.txSec ?? 0,
|
|
61
62
|
procs: metrics.processes?.total ?? 0,
|
package/lib/metrics.js
CHANGED
|
@@ -47,6 +47,12 @@ class MetricsPoller {
|
|
|
47
47
|
si.processes(),
|
|
48
48
|
]);
|
|
49
49
|
|
|
50
|
+
// True active process memory (excluding OS buffer / page cache)
|
|
51
|
+
const realUsedBytes = (typeof mem.available === 'number' && mem.available > 0)
|
|
52
|
+
? (mem.total - mem.available)
|
|
53
|
+
: (mem.active || (mem.used - (mem.buffcache || 0)));
|
|
54
|
+
const realUsedPct = parseFloat(Math.min(100, Math.max(0, (realUsedBytes / mem.total) * 100)).toFixed(1));
|
|
55
|
+
|
|
50
56
|
const payload = {
|
|
51
57
|
ts: Date.now(),
|
|
52
58
|
cpu: {
|
|
@@ -55,10 +61,15 @@ class MetricsPoller {
|
|
|
55
61
|
loadAvg: cpu.avgLoad ?? 0,
|
|
56
62
|
},
|
|
57
63
|
memory: {
|
|
58
|
-
total:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
total: mem.total,
|
|
65
|
+
active: realUsedBytes,
|
|
66
|
+
activePct: realUsedPct,
|
|
67
|
+
buffcache: mem.buffcache || Math.max(0, mem.used - realUsedBytes),
|
|
68
|
+
rawUsed: mem.used,
|
|
69
|
+
rawUsedPct: parseFloat(((mem.used / mem.total) * 100).toFixed(1)),
|
|
70
|
+
free: mem.available || mem.free,
|
|
71
|
+
used: realUsedBytes,
|
|
72
|
+
usedPct: realUsedPct,
|
|
62
73
|
},
|
|
63
74
|
disk: disk.map(d => ({
|
|
64
75
|
fs: d.fs,
|
|
@@ -130,10 +141,18 @@ class MetricsPoller {
|
|
|
130
141
|
|
|
131
142
|
// ─── Automated Spike Diagnostic & Root Cause Engine ────────────────────────
|
|
132
143
|
const curCpuUsage = parseFloat(cpu.currentLoad.toFixed(1));
|
|
133
|
-
const curMemPct =
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const
|
|
144
|
+
const curMemPct = realUsedPct;
|
|
145
|
+
|
|
146
|
+
// Filter real user/application processes with actual resource footprint
|
|
147
|
+
const sortedMemProcs = (procs.list || [])
|
|
148
|
+
.filter(p => p && p.pid > 1 && (p.pmem > 0.5 || p.pcpu > 0.5))
|
|
149
|
+
.sort((a, b) => (b.pmem || 0) - (a.pmem || 0));
|
|
150
|
+
const topMemProc = sortedMemProcs[0] || (procs.list || []).sort((a, b) => (b.pmem || 0) - (a.pmem || 0))[0] || null;
|
|
151
|
+
|
|
152
|
+
const sortedCpuProcs = (procs.list || [])
|
|
153
|
+
.filter(p => p && p.pid > 1 && (p.pcpu > 0.5 || p.pmem > 0.5))
|
|
154
|
+
.sort((a, b) => (b.pcpu || 0) - (a.pcpu || 0));
|
|
155
|
+
const topCpuProc = sortedCpuProcs[0] || (procs.list || []).sort((a, b) => (b.pcpu || 0) - (a.pcpu || 0))[0] || null;
|
|
137
156
|
|
|
138
157
|
let diagnostics = {
|
|
139
158
|
hasSpike: false,
|
|
@@ -150,35 +169,44 @@ class MetricsPoller {
|
|
|
150
169
|
this._lastMemPct = curMemPct;
|
|
151
170
|
this._lastCpuUsage = curCpuUsage;
|
|
152
171
|
|
|
153
|
-
|
|
172
|
+
const topMemMB = topMemProc ? Math.round(((topMemProc.pmem || 0) / 100) * (mem.total / (1024 * 1024))) : 0;
|
|
173
|
+
const topMemPct = topMemProc ? parseFloat((topMemProc.pmem || 0).toFixed(1)) : 0;
|
|
174
|
+
const hasRealMemCulprit = topMemProc && (topMemPct >= 3.0 || topMemMB >= 35);
|
|
175
|
+
|
|
176
|
+
// Trigger spike only on sudden surge OR critically high memory with an identified culprit
|
|
177
|
+
if (memDelta >= 5.0 || (curMemPct >= 90 && hasRealMemCulprit)) {
|
|
154
178
|
diagnostics.hasSpike = true;
|
|
155
179
|
diagnostics.type = 'memory';
|
|
156
180
|
diagnostics.deltaPct = memDelta;
|
|
157
|
-
if (
|
|
158
|
-
const procMemMB = Math.round(((topMemProc.pmem || 0) / 100) * (mem.total / (1024 * 1024)));
|
|
181
|
+
if (hasRealMemCulprit) {
|
|
159
182
|
diagnostics.culprit = {
|
|
160
183
|
pid: topMemProc.pid,
|
|
161
184
|
name: topMemProc.name,
|
|
162
185
|
command: topMemProc.command ? topMemProc.command.slice(0, 80) : topMemProc.name,
|
|
163
|
-
memPct:
|
|
164
|
-
memMB:
|
|
186
|
+
memPct: topMemPct,
|
|
187
|
+
memMB: topMemMB,
|
|
165
188
|
cpu: parseFloat((topMemProc.pcpu || 0).toFixed(1))
|
|
166
189
|
};
|
|
167
|
-
diagnostics.explanation = `Memory surge detected (${curMemPct}% RAM, delta: ${memDelta >= 0 ? '+' : ''}${memDelta}%). Primary consumer is "${topMemProc.name}" (PID ${topMemProc.pid}) utilizing ${
|
|
190
|
+
diagnostics.explanation = `Memory surge detected (${curMemPct}% RAM, delta: ${memDelta >= 0 ? '+' : ''}${memDelta}%). Primary consumer is "${topMemProc.name}" (PID ${topMemProc.pid}) utilizing ${topMemPct}% (${topMemMB} MB). Probable cause: Rapid memory allocation, large dataset buffer in memory, or memory leak.`;
|
|
191
|
+
} else {
|
|
192
|
+
diagnostics.explanation = `Memory load is elevated (${curMemPct}% RAM, delta: ${memDelta >= 0 ? '+' : ''}${memDelta}%), distributed across system caches and background services. No single runaway process.`;
|
|
168
193
|
}
|
|
169
|
-
} else if (curCpuUsage >=
|
|
194
|
+
} else if (cpuDelta >= 30.0 || (curCpuUsage >= 85 && topCpuProc && (topCpuProc.pcpu || 0) >= 10.0)) {
|
|
195
|
+
const topCpuVal = topCpuProc ? parseFloat((topCpuProc.pcpu || 0).toFixed(1)) : 0;
|
|
170
196
|
diagnostics.hasSpike = true;
|
|
171
197
|
diagnostics.type = 'cpu';
|
|
172
198
|
diagnostics.deltaPct = cpuDelta;
|
|
173
|
-
if (topCpuProc) {
|
|
199
|
+
if (topCpuProc && topCpuVal >= 5.0) {
|
|
174
200
|
diagnostics.culprit = {
|
|
175
201
|
pid: topCpuProc.pid,
|
|
176
202
|
name: topCpuProc.name,
|
|
177
203
|
command: topCpuProc.command ? topCpuProc.command.slice(0, 80) : topCpuProc.name,
|
|
178
|
-
cpu:
|
|
204
|
+
cpu: topCpuVal,
|
|
179
205
|
memPct: parseFloat((topCpuProc.pmem || 0).toFixed(1))
|
|
180
206
|
};
|
|
181
|
-
diagnostics.explanation = `High CPU workload spike detected (${curCpuUsage}% CPU, delta: ${cpuDelta >= 0 ? '+' : ''}${cpuDelta}%). Primary consumer is "${topCpuProc.name}" (PID ${topCpuProc.pid}) utilizing ${
|
|
207
|
+
diagnostics.explanation = `High CPU workload spike detected (${curCpuUsage}% CPU, delta: ${cpuDelta >= 0 ? '+' : ''}${cpuDelta}%). Primary consumer is "${topCpuProc.name}" (PID ${topCpuProc.pid}) utilizing ${topCpuVal}% CPU. Probable cause: Intensive computation, complex query/loop execution, or heavy background processing.`;
|
|
208
|
+
} else {
|
|
209
|
+
diagnostics.explanation = `High CPU utilization (${curCpuUsage}% CPU, delta: ${cpuDelta >= 0 ? '+' : ''}${cpuDelta}%) spread across multiple threads.`;
|
|
182
210
|
}
|
|
183
211
|
}
|
|
184
212
|
|
package/package.json
CHANGED