Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf0bdd54af |
@@ -90,6 +90,10 @@ type FS struct {
|
|||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Size uint64 `json:"size"`
|
Size uint64 `json:"size"`
|
||||||
Used uint64 `json:"used"`
|
Used uint64 `json:"used"`
|
||||||
|
// Remote is set when the filesystem lives on another machine — a CIFS or NFS share,
|
||||||
|
// sshfs, and so on. Its bytes are somebody else's disk, so a panel about this machine's
|
||||||
|
// hardware leaves it out, while the sensor stays for anyone who does want it.
|
||||||
|
Remote bool `json:"remote,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UPS struct {
|
type UPS struct {
|
||||||
@@ -766,6 +770,15 @@ func foldNVMe(devs []Disk) []Disk {
|
|||||||
|
|
||||||
// Kernel/virtual filesystems that aren't storage. Anything else that's mounted is
|
// Kernel/virtual filesystems that aren't storage. Anything else that's mounted is
|
||||||
// shown, so new real filesystems (bcachefs, exotic FUSE) work without a code change.
|
// shown, so new real filesystems (bcachefs, exotic FUSE) work without a code change.
|
||||||
|
// remoteFS is every filesystem type whose storage is not in this machine.
|
||||||
|
var remoteFS = map[string]bool{
|
||||||
|
"cifs": true, "smb3": true, "smbfs": true, "nfs": true, "nfs4": true, "afs": true,
|
||||||
|
"ceph": true, "glusterfs": true, "9p": true, "afpfs": true, "davfs": true,
|
||||||
|
"fuse.sshfs": true, "sshfs": true, "fuse.rclone": true, "fuse.s3fs": true,
|
||||||
|
"fuse.davfs2": true, "fuse.curlftpfs": true, "fuse.gcsfuse": true, "beegfs": true,
|
||||||
|
"lustre": true, "orangefs": true, "pvfs2": true, "coda": true, "ncpfs": true,
|
||||||
|
}
|
||||||
|
|
||||||
var pseudoFS = map[string]bool{
|
var pseudoFS = map[string]bool{
|
||||||
"proc": true, "sysfs": true, "devtmpfs": true, "devpts": true, "tmpfs": true, "ramfs": true,
|
"proc": true, "sysfs": true, "devtmpfs": true, "devpts": true, "tmpfs": true, "ramfs": true,
|
||||||
"cgroup": true, "cgroup2": true, "pstore": true, "bpf": true, "securityfs": true, "debugfs": true,
|
"cgroup": true, "cgroup2": true, "pstore": true, "bpf": true, "securityfs": true, "debugfs": true,
|
||||||
@@ -812,7 +825,7 @@ func filesystems() []FS {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
bs := uint64(st.Bsize)
|
bs := uint64(st.Bsize)
|
||||||
done <- FS{Mount: mount, Type: fs[2], Size: st.Blocks * bs, Used: (st.Blocks - st.Bfree) * bs}
|
done <- FS{Mount: mount, Type: fs[2], Size: st.Blocks * bs, Used: (st.Blocks - st.Bfree) * bs, Remote: remoteFS[fs[2]]}
|
||||||
}()
|
}()
|
||||||
select {
|
select {
|
||||||
case r := <-done:
|
case r := <-done:
|
||||||
@@ -820,7 +833,7 @@ func filesystems() []FS {
|
|||||||
out = append(out, r)
|
out = append(out, r)
|
||||||
}
|
}
|
||||||
case <-time.After(3 * time.Second):
|
case <-time.After(3 * time.Second):
|
||||||
out = append(out, FS{Mount: mount, Type: fs[2]}) // unreachable: size 0 signals it
|
out = append(out, FS{Mount: mount, Type: fs[2], Remote: remoteFS[fs[2]]}) // unreachable: size 0 signals it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
|
|||||||
@@ -117,9 +117,15 @@ func flatten(s Sample, want func(id string) bool) []sensors.Sensor {
|
|||||||
|
|
||||||
for _, x := range s.FS {
|
for _, x := range s.FS {
|
||||||
p := "fs." + sensors.Seg(x.Mount)
|
p := "fs." + sensors.Seg(x.Mount)
|
||||||
f.add(p+".size", x.Mount+" size", "bytes", "B", float64(x.Size), s.fsT, none, "mount", x.Mount, "fstype", x.Type)
|
// remote says the bytes are on another machine (a CIFS or NFS share), so a view of
|
||||||
f.add(p+".used", x.Mount+" used", "bytes", "B", float64(x.Used), s.fsT, upTo(float64(x.Size)), "mount", x.Mount, "fstype", x.Type)
|
// this machine's hardware can leave it out without losing the sensor
|
||||||
f.add(p+".used_pct", x.Mount+" used", "usage", "%", ratio(x.Used, x.Size), s.fsT, pct, "mount", x.Mount, "fstype", x.Type)
|
lbl := []string{"mount", x.Mount, "fstype", x.Type}
|
||||||
|
if x.Remote {
|
||||||
|
lbl = append(lbl, "remote", "1")
|
||||||
|
}
|
||||||
|
f.add(p+".size", x.Mount+" size", "bytes", "B", float64(x.Size), s.fsT, none, lbl...)
|
||||||
|
f.add(p+".used", x.Mount+" used", "bytes", "B", float64(x.Used), s.fsT, upTo(float64(x.Size)), lbl...)
|
||||||
|
f.add(p+".used_pct", x.Mount+" used", "usage", "%", ratio(x.Used, x.Size), s.fsT, pct, lbl...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if u := s.UPS; u != nil {
|
if u := s.UPS; u != nil {
|
||||||
|
|||||||
+2
-1
@@ -320,7 +320,8 @@ export default function Top() {
|
|||||||
const swap = s?.swap ?? pt?.swap
|
const swap = s?.swap ?? pt?.swap
|
||||||
const net = (s?.net ?? pt?.net ?? []).filter((n) => n.up && n.iface !== 'lo')
|
const net = (s?.net ?? pt?.net ?? []).filter((n) => n.up && n.iface !== 'lo')
|
||||||
const iface = net[0]
|
const iface = net[0]
|
||||||
const fs = s?.fs ?? []
|
// the disks box is this machine's own storage: a CIFS or NFS share is somebody else's disk
|
||||||
|
const fs = (s?.fs ?? []).filter((f) => !f.remote)
|
||||||
const pct = (a: number, b: number) => (b > 0 ? (a / b) * 100 : 0)
|
const pct = (a: number, b: number) => (b > 0 ? (a / b) * 100 : 0)
|
||||||
// the top of a graph's scale: the peak of what it is drawing — the window, not everything kept
|
// the top of a graph's scale: the peak of what it is drawing — the window, not everything kept
|
||||||
const peak = (id: string) => Math.max(1, ...(curves.get(id) ?? []).slice(-cap))
|
const peak = (id: string) => Math.max(1, ...(curves.get(id) ?? []).slice(-cap))
|
||||||
|
|||||||
+1
-1
@@ -70,7 +70,7 @@ export interface Temp { chip: string; label: string; c: number; max?: number; cr
|
|||||||
export interface Fan { chip: string; label: string; rpm: number }
|
export interface Fan { chip: string; label: string; rpm: number }
|
||||||
export interface NetIf { iface: string; up: boolean; rx_bps: number; tx_bps: number; rx_total: number; tx_total: number }
|
export interface NetIf { iface: string; up: boolean; rx_bps: number; tx_bps: number; rx_total: number; tx_total: number }
|
||||||
export interface Disk { name: string; model?: string; size: number; read_bps: number; write_bps: number; util_pct: number; temp?: number }
|
export interface Disk { name: string; model?: string; size: number; read_bps: number; write_bps: number; util_pct: number; temp?: number }
|
||||||
export interface FS { mount: string; type: string; size: number; used: number }
|
export interface FS { mount: string; type: string; size: number; used: number; remote?: boolean }
|
||||||
export interface UPS { driver: string; model: string; state: string; source: string; on_battery: boolean; in_v: number; out_v: number; battery_pct: number; runtime_min: number; load_w: number; load_pct: number; last_event?: string }
|
export interface UPS { driver: string; model: string; state: string; source: string; on_battery: boolean; in_v: number; out_v: number; battery_pct: number; runtime_min: number; load_w: number; load_pct: number; last_event?: string }
|
||||||
export interface Proc { pid: number; ppid: number; name: string; cmd?: string; user: string; cpu: number; cpu_time: number; rss: number; threads: number; state: string; nice: number; started: number }
|
export interface Proc { pid: number; ppid: number; name: string; cmd?: string; user: string; cpu: number; cpu_time: number; rss: number; threads: number; state: string; nice: number; started: number }
|
||||||
export interface MemInfo { total: number; used: number; avail: number; free?: number; cached?: number; buffers?: number }
|
export interface MemInfo { total: number; used: number; avail: number; free?: number; cached?: number; buffers?: number }
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export function sampleOf(v: Values, cat: Catalog): Sample {
|
|||||||
fans: hw('fan.').map(({ id, s }) => ({ chip: s.labels!.chip, label: s.labels!.label, rpm: num(v, id) })),
|
fans: hw('fan.').map(({ id, s }) => ({ chip: s.labels!.chip, label: s.labels!.label, rpm: num(v, id) })),
|
||||||
net: [...groups(v, cat, 'net.', 'iface')].map(([iface, p]) => ({ iface, up: v[p + '.up'] === true, rx_bps: num(v, p + '.rx'), tx_bps: num(v, p + '.tx'), rx_total: num(v, p + '.rx_total'), tx_total: num(v, p + '.tx_total') })),
|
net: [...groups(v, cat, 'net.', 'iface')].map(([iface, p]) => ({ iface, up: v[p + '.up'] === true, rx_bps: num(v, p + '.rx'), tx_bps: num(v, p + '.tx'), rx_total: num(v, p + '.rx_total'), tx_total: num(v, p + '.tx_total') })),
|
||||||
disks: [...groups(v, cat, 'disk.', 'device')].map(([name, p]) => ({ name, model: cat.get(p + '.size')?.labels?.model || undefined, size: num(v, p + '.size'), read_bps: num(v, p + '.read'), write_bps: num(v, p + '.write'), util_pct: num(v, p + '.util'), temp: num(v, p + '.temp') || undefined })),
|
disks: [...groups(v, cat, 'disk.', 'device')].map(([name, p]) => ({ name, model: cat.get(p + '.size')?.labels?.model || undefined, size: num(v, p + '.size'), read_bps: num(v, p + '.read'), write_bps: num(v, p + '.write'), util_pct: num(v, p + '.util'), temp: num(v, p + '.temp') || undefined })),
|
||||||
fs: [...groups(v, cat, 'fs.', 'mount')].map(([mount, p]) => ({ mount, type: cat.get(p + '.size')?.labels?.fstype ?? '', size: num(v, p + '.size'), used: num(v, p + '.used') })),
|
fs: [...groups(v, cat, 'fs.', 'mount')].map(([mount, p]) => ({ mount, type: cat.get(p + '.size')?.labels?.fstype ?? '', size: num(v, p + '.size'), used: num(v, p + '.used'), remote: cat.get(p + '.size')?.labels?.remote === '1' })),
|
||||||
ups: v['ups.battery'] === undefined ? null : {
|
ups: v['ups.battery'] === undefined ? null : {
|
||||||
driver: cat.get('ups.last_event')?.labels?.driver ?? '', model: cat.get('ups.battery')?.labels?.model ?? '', state: str(v, 'ups.state'), source: str(v, 'ups.source'),
|
driver: cat.get('ups.last_event')?.labels?.driver ?? '', model: cat.get('ups.battery')?.labels?.model ?? '', state: str(v, 'ups.state'), source: str(v, 'ups.source'),
|
||||||
on_battery: v['ups.on_battery'] === true, in_v: num(v, 'ups.in_v'), out_v: num(v, 'ups.out_v'), battery_pct: num(v, 'ups.battery'), runtime_min: num(v, 'ups.runtime'),
|
on_battery: v['ups.on_battery'] === true, in_v: num(v, 'ups.in_v'), out_v: num(v, 'ups.out_v'), battery_pct: num(v, 'ups.battery'), runtime_min: num(v, 'ups.runtime'),
|
||||||
|
|||||||
Reference in New Issue
Block a user