@glassmkr/crucible 0.4.0 → 0.5.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.
@@ -1,5 +1,6 @@
1
1
  import { readProcFile, sleep } from "../lib/parse.js";
2
2
  import { readFileSync } from "fs";
3
+ const previousCounters = new Map();
3
4
  function parseNetDev() {
4
5
  const raw = readProcFile("/proc/net/dev") || "";
5
6
  const result = {};
@@ -29,25 +30,58 @@ function getSpeed(iface) {
29
30
  return 0;
30
31
  }
31
32
  }
33
+ // Compute delta, handling counter wraps (current < previous means reset, use current as delta)
34
+ function delta(current, previous) {
35
+ if (current >= previous)
36
+ return current - previous;
37
+ return current; // counter wrapped or reset
38
+ }
32
39
  export async function collectNetwork() {
33
40
  const stats1 = parseNetDev();
34
41
  await sleep(1000);
35
42
  const stats2 = parseNetDev();
43
+ const currentIfaces = new Set();
36
44
  const results = [];
37
45
  for (const [name, s2] of Object.entries(stats2)) {
38
46
  const s1 = stats1[name];
39
47
  if (!s1)
40
48
  continue;
41
- results.push({
42
- interface: name,
43
- speed_mbps: getSpeed(name),
44
- rx_bytes_sec: s2.rx_bytes - s1.rx_bytes,
45
- tx_bytes_sec: s2.tx_bytes - s1.tx_bytes,
49
+ currentIfaces.add(name);
50
+ const prev = previousCounters.get(name);
51
+ // Compute error/drop deltas (0 on first cycle after start or new interface)
52
+ let rxErrorsDelta = 0;
53
+ let txErrorsDelta = 0;
54
+ let rxDropsDelta = 0;
55
+ let txDropsDelta = 0;
56
+ if (prev) {
57
+ rxErrorsDelta = delta(s2.rx_errors, prev.rx_errors);
58
+ txErrorsDelta = delta(s2.tx_errors, prev.tx_errors);
59
+ rxDropsDelta = delta(s2.rx_drops, prev.rx_drops);
60
+ txDropsDelta = delta(s2.tx_drops, prev.tx_drops);
61
+ }
62
+ // Store current cumulative values for next cycle
63
+ previousCounters.set(name, {
46
64
  rx_errors: s2.rx_errors,
47
65
  tx_errors: s2.tx_errors,
48
66
  rx_drops: s2.rx_drops,
49
67
  tx_drops: s2.tx_drops,
50
68
  });
69
+ results.push({
70
+ interface: name,
71
+ speed_mbps: getSpeed(name),
72
+ rx_bytes_sec: s2.rx_bytes - s1.rx_bytes, // already a 1-second delta
73
+ tx_bytes_sec: s2.tx_bytes - s1.tx_bytes,
74
+ rx_errors: rxErrorsDelta,
75
+ tx_errors: txErrorsDelta,
76
+ rx_drops: rxDropsDelta,
77
+ tx_drops: txDropsDelta,
78
+ });
79
+ }
80
+ // Remove stale interfaces that disappeared
81
+ for (const name of previousCounters.keys()) {
82
+ if (!currentIfaces.has(name)) {
83
+ previousCounters.delete(name);
84
+ }
51
85
  }
52
86
  return results;
53
87
  }
@@ -1 +1 @@
1
- {"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/collect/network.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/collect/network.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glassmkr/crucible",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Lightweight bare metal server monitoring. IPMI, SMART, OS, network. Opinionated alerts.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -7,6 +7,16 @@ interface IfaceStats {
7
7
  tx_bytes: number; tx_packets: number; tx_errors: number; tx_drops: number;
8
8
  }
9
9
 
10
+ // Previous cumulative counters for delta computation (persists in process memory across cycles)
11
+ interface PreviousCounters {
12
+ rx_errors: number;
13
+ tx_errors: number;
14
+ rx_drops: number;
15
+ tx_drops: number;
16
+ }
17
+
18
+ const previousCounters = new Map<string, PreviousCounters>();
19
+
10
20
  function parseNetDev(): Record<string, IfaceStats> {
11
21
  const raw = readProcFile("/proc/net/dev") || "";
12
22
  const result: Record<string, IfaceStats> = {};
@@ -35,26 +45,65 @@ function getSpeed(iface: string): number {
35
45
  }
36
46
  }
37
47
 
48
+ // Compute delta, handling counter wraps (current < previous means reset, use current as delta)
49
+ function delta(current: number, previous: number): number {
50
+ if (current >= previous) return current - previous;
51
+ return current; // counter wrapped or reset
52
+ }
53
+
38
54
  export async function collectNetwork(): Promise<NetworkInfo[]> {
39
55
  const stats1 = parseNetDev();
40
56
  await sleep(1000);
41
57
  const stats2 = parseNetDev();
42
58
 
59
+ const currentIfaces = new Set<string>();
43
60
  const results: NetworkInfo[] = [];
61
+
44
62
  for (const [name, s2] of Object.entries(stats2)) {
45
63
  const s1 = stats1[name];
46
64
  if (!s1) continue;
65
+ currentIfaces.add(name);
47
66
 
48
- results.push({
49
- interface: name,
50
- speed_mbps: getSpeed(name),
51
- rx_bytes_sec: s2.rx_bytes - s1.rx_bytes,
52
- tx_bytes_sec: s2.tx_bytes - s1.tx_bytes,
67
+ const prev = previousCounters.get(name);
68
+
69
+ // Compute error/drop deltas (0 on first cycle after start or new interface)
70
+ let rxErrorsDelta = 0;
71
+ let txErrorsDelta = 0;
72
+ let rxDropsDelta = 0;
73
+ let txDropsDelta = 0;
74
+
75
+ if (prev) {
76
+ rxErrorsDelta = delta(s2.rx_errors, prev.rx_errors);
77
+ txErrorsDelta = delta(s2.tx_errors, prev.tx_errors);
78
+ rxDropsDelta = delta(s2.rx_drops, prev.rx_drops);
79
+ txDropsDelta = delta(s2.tx_drops, prev.tx_drops);
80
+ }
81
+
82
+ // Store current cumulative values for next cycle
83
+ previousCounters.set(name, {
53
84
  rx_errors: s2.rx_errors,
54
85
  tx_errors: s2.tx_errors,
55
86
  rx_drops: s2.rx_drops,
56
87
  tx_drops: s2.tx_drops,
57
88
  });
89
+
90
+ results.push({
91
+ interface: name,
92
+ speed_mbps: getSpeed(name),
93
+ rx_bytes_sec: s2.rx_bytes - s1.rx_bytes, // already a 1-second delta
94
+ tx_bytes_sec: s2.tx_bytes - s1.tx_bytes,
95
+ rx_errors: rxErrorsDelta,
96
+ tx_errors: txErrorsDelta,
97
+ rx_drops: rxDropsDelta,
98
+ tx_drops: txDropsDelta,
99
+ });
100
+ }
101
+
102
+ // Remove stale interfaces that disappeared
103
+ for (const name of previousCounters.keys()) {
104
+ if (!currentIfaces.has(name)) {
105
+ previousCounters.delete(name);
106
+ }
58
107
  }
59
108
 
60
109
  return results;