@daemonitor/plugins 1.1.13 → 1.1.15
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.
|
@@ -28,7 +28,26 @@ const SYS = {
|
|
|
28
28
|
name: "1.3.6.1.2.1.1.5.0", // sysName
|
|
29
29
|
ifOper: "1.3.6.1.2.1.2.2.1.8", // ifOperStatus (walk): 1=up 2=down
|
|
30
30
|
ifAdmin: "1.3.6.1.2.1.2.2.1.7", // ifAdminStatus (walk): 1=up (enabled)
|
|
31
|
+
ifHCIn: "1.3.6.1.2.1.31.1.1.1.6", // ifHCInOctets (walk, Counter64)
|
|
32
|
+
ifHCOut: "1.3.6.1.2.1.31.1.1.1.10", // ifHCOutOctets (walk, Counter64)
|
|
31
33
|
};
|
|
34
|
+
// UCD-SNMP-MIB + HOST-RESOURCES — CPU/RAM/load on net-snmp devices (EdgeOS
|
|
35
|
+
// routers, Linux hosts). All best-effort: absent on gear that doesn't ship the
|
|
36
|
+
// UCD MIB (many switches), so every read is null-tolerant.
|
|
37
|
+
const UCD = {
|
|
38
|
+
cpuIdle: "1.3.6.1.4.1.2021.11.11.0", // ssCpuIdle (%) → cpu% = 100 - idle
|
|
39
|
+
load1: "1.3.6.1.4.1.2021.10.1.3.1", // laLoad 1-min
|
|
40
|
+
load5: "1.3.6.1.4.1.2021.10.1.3.2",
|
|
41
|
+
load15: "1.3.6.1.4.1.2021.10.1.3.3",
|
|
42
|
+
memTotal: "1.3.6.1.4.1.2021.4.5.0", // memTotalReal (KB)
|
|
43
|
+
memAvail: "1.3.6.1.4.1.2021.4.6.0", // memAvailReal (KB, free excl. cache)
|
|
44
|
+
memBuffer: "1.3.6.1.4.1.2021.4.14.0", // memBuffer (KB)
|
|
45
|
+
memCached: "1.3.6.1.4.1.2021.4.15.0", // memCached (KB)
|
|
46
|
+
hrProcLoad: "1.3.6.1.2.1.25.3.3.1.2", // hrProcessorLoad (walk, per-core %) — CPU fallback
|
|
47
|
+
};
|
|
48
|
+
// Per-target previous interface-octet sample, for throughput (bps) rate calc
|
|
49
|
+
// across polls. Module-level: one collectDevice call per target per cycle.
|
|
50
|
+
const netPrev = {};
|
|
32
51
|
// QNAP enterprise MIB (NAS-MIB, 1.3.6.1.4.1.24681.1.2). A full walk of this
|
|
33
52
|
// subtree times out on QTS, so everything here is fetched by exact OID.
|
|
34
53
|
const QNAP = {
|
|
@@ -167,6 +186,54 @@ async function collectDevice(t) {
|
|
|
167
186
|
}
|
|
168
187
|
// sysUpTime timeticks → seconds
|
|
169
188
|
const upSecs = uptimeRaw != null ? Math.round((Number(String(uptimeRaw).replace(/[^0-9]/g, "")) || 0) / 100) : undefined;
|
|
189
|
+
// CPU / RAM / load / network — best-effort UCD-SNMP + IF-MIB counters. Absent
|
|
190
|
+
// on gear without the UCD MIB (returns "No Such Object" fast → null), so every
|
|
191
|
+
// field is optional and simply omitted when unsupported.
|
|
192
|
+
const [cpuIdle, load1, load5, load15, memTotal, memAvail, memBuffer, memCached, procLoads, hcIn, hcOut] = await Promise.all([
|
|
193
|
+
snmpGet(t, UCD.cpuIdle), snmpGet(t, UCD.load1), snmpGet(t, UCD.load5), snmpGet(t, UCD.load15),
|
|
194
|
+
snmpGet(t, UCD.memTotal), snmpGet(t, UCD.memAvail), snmpGet(t, UCD.memBuffer), snmpGet(t, UCD.memCached),
|
|
195
|
+
snmpWalk(t, UCD.hrProcLoad), snmpWalk(t, SYS.ifHCIn), snmpWalk(t, SYS.ifHCOut),
|
|
196
|
+
]);
|
|
197
|
+
// CPU %: prefer ssCpuIdle (100 - idle); fall back to avg per-core hrProcessorLoad.
|
|
198
|
+
let cpuPct;
|
|
199
|
+
if (cpuIdle != null && !isNaN(Number(cpuIdle))) {
|
|
200
|
+
cpuPct = Math.max(0, Math.min(100, 100 - Math.round(Number(cpuIdle))));
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
const cores = procLoads.map(Number).filter((n) => !isNaN(n));
|
|
204
|
+
if (cores.length)
|
|
205
|
+
cpuPct = Math.round(cores.reduce((a, b) => a + b, 0) / cores.length);
|
|
206
|
+
}
|
|
207
|
+
const load1n = parseNum(load1);
|
|
208
|
+
const loadavg = [parseNum(load1), parseNum(load5), parseNum(load15)].filter((n) => n != null);
|
|
209
|
+
// RAM used %: (total - free - buffers - cache) / total. memAvailReal excludes
|
|
210
|
+
// cache already on some agents; subtracting buffer+cache is safe (they default 0).
|
|
211
|
+
let memPct, memTotalMB;
|
|
212
|
+
const mTot = parseNum(memTotal), mAvail = parseNum(memAvail);
|
|
213
|
+
const mBuf = parseNum(memBuffer) || 0, mCache = parseNum(memCached) || 0;
|
|
214
|
+
if (mTot && mTot > 0 && mAvail != null) {
|
|
215
|
+
const usedKb = Math.max(0, mTot - mAvail - mBuf - mCache);
|
|
216
|
+
memPct = Math.round((usedKb / mTot) * 100);
|
|
217
|
+
memTotalMB = Math.round(mTot / 1024);
|
|
218
|
+
}
|
|
219
|
+
// Network throughput (aggregate bytes/sec, to match the OS plugin's NET
|
|
220
|
+
// metric): delta of summed HC octets vs the prior poll. First poll (or a
|
|
221
|
+
// counter reset) yields no rate.
|
|
222
|
+
let netIn, netOut;
|
|
223
|
+
const sumIn = hcIn.map(Number).filter((n) => !isNaN(n)).reduce((a, b) => a + b, 0);
|
|
224
|
+
const sumOut = hcOut.map(Number).filter((n) => !isNaN(n)).reduce((a, b) => a + b, 0);
|
|
225
|
+
if (hcIn.length || hcOut.length) {
|
|
226
|
+
const now = Date.now();
|
|
227
|
+
const prev = netPrev[t.ip];
|
|
228
|
+
if (prev && sumIn >= prev.in && sumOut >= prev.out && now > prev.ts) {
|
|
229
|
+
const dt = (now - prev.ts) / 1000;
|
|
230
|
+
if (dt > 0) {
|
|
231
|
+
netIn = Math.round((sumIn - prev.in) / dt);
|
|
232
|
+
netOut = Math.round((sumOut - prev.out) / dt);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
netPrev[t.ip] = { in: sumIn, out: sumOut, ts: now };
|
|
236
|
+
}
|
|
170
237
|
return {
|
|
171
238
|
name: t.name,
|
|
172
239
|
ip: t.ip,
|
|
@@ -177,6 +244,14 @@ async function collectDevice(t) {
|
|
|
177
244
|
uptimeSecs: upSecs,
|
|
178
245
|
portsUp,
|
|
179
246
|
portsTotal,
|
|
247
|
+
cpuPct,
|
|
248
|
+
cpuCores: procLoads.length || undefined, // for load-per-core normalization
|
|
249
|
+
load1: load1n,
|
|
250
|
+
loadavg: loadavg.length ? loadavg : undefined,
|
|
251
|
+
memPct,
|
|
252
|
+
memTotalMB,
|
|
253
|
+
netIn,
|
|
254
|
+
netOut,
|
|
180
255
|
};
|
|
181
256
|
}
|
|
182
257
|
// Walk that keeps each row's index (numeric OID suffix) — needed to resolve the
|
|
@@ -89,6 +89,25 @@ export function createWebsitePlugin() {
|
|
|
89
89
|
const start = Date.now();
|
|
90
90
|
const label = ep.name || ep.url;
|
|
91
91
|
const uid = `web-${(ep.name || ep.url).replace(/[^a-zA-Z0-9_.-]+/g, "-")}`;
|
|
92
|
+
// Origin-only monitor: skip the public tier (unreachable behind a CDN bot
|
|
93
|
+
// challenge) and report the direct origin check as the endpoint's health.
|
|
94
|
+
if (ep.originOnly && ep.origin?.url) {
|
|
95
|
+
const o = await checkOrigin(ep);
|
|
96
|
+
await plugin.send({
|
|
97
|
+
name: label,
|
|
98
|
+
url: ep.url || o.url,
|
|
99
|
+
status: o.status,
|
|
100
|
+
duration: o.duration,
|
|
101
|
+
ok: o.ok,
|
|
102
|
+
originOnly: true,
|
|
103
|
+
hasAllExpectedStrings: o.hasAllExpectedStrings,
|
|
104
|
+
hasAnyUnexpectedStrings: o.hasAnyUnexpectedStrings,
|
|
105
|
+
missingExpected: o.missingExpected,
|
|
106
|
+
matchedUnexpected: o.matchedUnexpected,
|
|
107
|
+
error: o.error,
|
|
108
|
+
}, uid);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
92
111
|
let publicResult;
|
|
93
112
|
try {
|
|
94
113
|
const ctrl = new AbortController();
|