mirror of
https://github.com/henrygd/beszel.git
synced 2026-09-17 05:24:31 +00:00
feat(hub/agent): alphabetical disk ordering and root disk renaming (#2006)
This commit is contained in:
+7
-1
@@ -193,7 +193,13 @@ func (a *Agent) gatherStats(options common.DataRequestOptions) *system.CombinedD
|
||||
data.Stats.ExtraFs = make(map[string]*system.FsStats)
|
||||
data.Info.ExtraFsPct = make(map[string]float64)
|
||||
for name, stats := range a.fsStats {
|
||||
if !stats.Root && stats.DiskTotal > 0 {
|
||||
if stats.Root {
|
||||
if stats.Name != "" {
|
||||
data.Info.RootDiskName = stats.Name
|
||||
}
|
||||
continue
|
||||
}
|
||||
if stats.DiskTotal > 0 {
|
||||
// Use custom name if available, otherwise use device name
|
||||
key := name
|
||||
if stats.Name != "" {
|
||||
|
||||
+14
-11
@@ -18,10 +18,11 @@ import (
|
||||
// fsRegistrationContext holds the shared lookup state needed to resolve a
|
||||
// filesystem into the tracked fsStats key and metadata.
|
||||
type fsRegistrationContext struct {
|
||||
filesystem string // value of optional FILESYSTEM env var
|
||||
isWindows bool
|
||||
efPath string // path to extra filesystems (default "/extra-filesystems")
|
||||
diskIoCounters map[string]disk.IOCountersStat
|
||||
filesystem string // device part of optional FILESYSTEM env var
|
||||
filesystemName string // optional custom name from FILESYSTEM=device__name
|
||||
isWindows bool
|
||||
efPath string // path to extra filesystems (default "/extra-filesystems")
|
||||
diskIoCounters map[string]disk.IOCountersStat
|
||||
}
|
||||
|
||||
// diskDiscovery groups the transient state for a single initializeDiskInfo run so
|
||||
@@ -177,7 +178,7 @@ func (d *diskDiscovery) addConfiguredRootFs() bool {
|
||||
|
||||
for _, p := range d.partitions {
|
||||
if filesystemMatchesPartitionSetting(d.ctx.filesystem, p) {
|
||||
d.addFsStat(p.Device, p.Mountpoint, true, "")
|
||||
d.addFsStat(p.Device, p.Mountpoint, true, d.ctx.filesystemName)
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -185,7 +186,7 @@ func (d *diskDiscovery) addConfiguredRootFs() bool {
|
||||
// FILESYSTEM may name a physical disk absent from partitions (e.g. ZFS lists
|
||||
// dataset paths like zroot/ROOT/default, not block devices).
|
||||
if ioKey, match := findIoDevice(d.ctx.filesystem, d.ctx.diskIoCounters); match {
|
||||
d.agent.fsStats[ioKey] = &system.FsStats{Root: true, Mountpoint: d.rootMountPoint}
|
||||
d.agent.fsStats[ioKey] = &system.FsStats{Root: true, Mountpoint: d.rootMountPoint, Name: d.ctx.filesystemName}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -300,7 +301,8 @@ func (d *diskDiscovery) addExtraFilesystemFolders(folderNames []string) {
|
||||
|
||||
// Sets up the filesystems to monitor for disk usage and I/O.
|
||||
func (a *Agent) initializeDiskInfo() {
|
||||
filesystem, _ := utils.GetEnv("FILESYSTEM")
|
||||
filesystemRaw, _ := utils.GetEnv("FILESYSTEM")
|
||||
filesystem, filesystemName := parseFilesystemEntry(filesystemRaw)
|
||||
hasRoot := false
|
||||
isWindows := runtime.GOOS == "windows"
|
||||
|
||||
@@ -323,10 +325,11 @@ func (a *Agent) initializeDiskInfo() {
|
||||
}
|
||||
slog.Debug("Disk I/O", "diskstats", diskIoCounters)
|
||||
ctx := fsRegistrationContext{
|
||||
filesystem: filesystem,
|
||||
isWindows: isWindows,
|
||||
diskIoCounters: diskIoCounters,
|
||||
efPath: "/extra-filesystems",
|
||||
filesystem: filesystem,
|
||||
filesystemName: filesystemName,
|
||||
isWindows: isWindows,
|
||||
diskIoCounters: diskIoCounters,
|
||||
efPath: "/extra-filesystems",
|
||||
}
|
||||
|
||||
// Get the appropriate root mount point for this system
|
||||
|
||||
+9
-12
@@ -78,14 +78,7 @@ func TestParseFilesystemEntry(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fsEntry := strings.TrimSpace(tt.input)
|
||||
var fs, customName string
|
||||
if parts := strings.SplitN(fsEntry, "__", 2); len(parts) == 2 {
|
||||
fs = strings.TrimSpace(parts[0])
|
||||
customName = strings.TrimSpace(parts[1])
|
||||
} else {
|
||||
fs = fsEntry
|
||||
}
|
||||
fs, customName := parseFilesystemEntry(tt.input)
|
||||
|
||||
assert.Equal(t, tt.expectedFs, fs)
|
||||
assert.Equal(t, tt.expectedName, customName)
|
||||
@@ -287,8 +280,9 @@ func TestAddConfiguredRootFs(t *testing.T) {
|
||||
rootMountPoint: "/",
|
||||
partitions: []disk.PartitionStat{{Device: "/dev/ada0p2", Mountpoint: "/"}},
|
||||
ctx: fsRegistrationContext{
|
||||
filesystem: "/dev/ada0p2",
|
||||
isWindows: false,
|
||||
filesystem: "/dev/ada0p2",
|
||||
filesystemName: "root disk",
|
||||
isWindows: false,
|
||||
diskIoCounters: map[string]disk.IOCountersStat{
|
||||
"ada0": {Name: "ada0", ReadBytes: 1000, WriteBytes: 1000},
|
||||
},
|
||||
@@ -302,6 +296,7 @@ func TestAddConfiguredRootFs(t *testing.T) {
|
||||
assert.True(t, exists)
|
||||
assert.True(t, stats.Root)
|
||||
assert.Equal(t, "/", stats.Mountpoint)
|
||||
assert.Equal(t, "root disk", stats.Name)
|
||||
})
|
||||
|
||||
t.Run("adds root from io device when partition is missing", func(t *testing.T) {
|
||||
@@ -310,8 +305,9 @@ func TestAddConfiguredRootFs(t *testing.T) {
|
||||
agent: agent,
|
||||
rootMountPoint: "/sysroot",
|
||||
ctx: fsRegistrationContext{
|
||||
filesystem: "zroot",
|
||||
isWindows: false,
|
||||
filesystem: "zroot",
|
||||
filesystemName: "root pool",
|
||||
isWindows: false,
|
||||
diskIoCounters: map[string]disk.IOCountersStat{
|
||||
"nda0": {Name: "nda0", Label: "zroot", ReadBytes: 1000, WriteBytes: 1000},
|
||||
},
|
||||
@@ -325,6 +321,7 @@ func TestAddConfiguredRootFs(t *testing.T) {
|
||||
assert.True(t, exists)
|
||||
assert.True(t, stats.Root)
|
||||
assert.Equal(t, "/sysroot", stats.Mountpoint)
|
||||
assert.Equal(t, "root pool", stats.Name)
|
||||
})
|
||||
|
||||
t.Run("returns false when filesystem cannot be resolved", func(t *testing.T) {
|
||||
|
||||
@@ -157,6 +157,7 @@ type Info struct {
|
||||
ExtraFsPct map[string]float64 `json:"efs,omitempty" cbor:"21,keyasint,omitempty"`
|
||||
Services []uint16 `json:"sv,omitempty" cbor:"22,keyasint,omitempty"` // [totalServices, numFailedServices]
|
||||
Battery [2]uint8 `json:"bat,omitzero" cbor:"23,keyasint,omitzero"` // [percent, charge state]
|
||||
RootDiskName string `json:"rdn,omitempty" cbor:"24,keyasint,omitempty"` // custom name for root disk (set via FILESYSTEM=device__name)
|
||||
}
|
||||
|
||||
// Data that does not change during process lifetime and is not needed in All Systems table
|
||||
|
||||
@@ -114,8 +114,10 @@ export function DiskUsageChart({ systemData, extraFsName }: { systemData: System
|
||||
diskSize = Math.round(diskSize)
|
||||
}
|
||||
|
||||
const title = extraFsName ? `${extraFsName} ${t`Usage`}` : t`Disk Usage`
|
||||
const description = extraFsName ? t`Disk usage of ${extraFsName}` : t`Usage of root partition`
|
||||
const rootName = systemData.system?.info?.rdn
|
||||
const rootLabel = rootName ?? t`Root`
|
||||
const title = extraFsName ? `${extraFsName} ${t`Usage`}` : `${rootLabel} ${t`Usage`}`
|
||||
const description = extraFsName ? t`Disk usage of ${extraFsName}` : t`Disk usage of ${rootLabel}`
|
||||
|
||||
return (
|
||||
<ChartCard empty={dataEmpty} grid={grid} title={title} description={description}>
|
||||
@@ -152,8 +154,10 @@ export function DiskIOChart({ systemData, extraFsName }: { systemData: SystemDat
|
||||
return null
|
||||
}
|
||||
|
||||
const title = extraFsName ? `${extraFsName} I/O` : t`Disk I/O`
|
||||
const description = extraFsName ? t`Throughput of ${extraFsName}` : t`Throughput of root filesystem`
|
||||
const rootName = systemData.system?.info?.rdn
|
||||
const rootLabel = rootName ?? t`Root`
|
||||
const title = extraFsName ? `${extraFsName} I/O` : `${rootLabel} I/O`
|
||||
const description = extraFsName ? t`Throughput of ${extraFsName}` : t`Throughput of ${rootLabel}`
|
||||
|
||||
const hasMoreIOMetrics = chartData.systemStats?.some((record) => record.stats?.dios?.at(0))
|
||||
|
||||
@@ -264,7 +268,7 @@ export function ExtraFsCharts({ systemData }: { systemData: SystemData }) {
|
||||
|
||||
return (
|
||||
<div className="grid xl:grid-cols-2 gap-4">
|
||||
{Object.keys(extraFs).map((extraFsName) => {
|
||||
{Object.keys(extraFs).sort((a, b) => a.localeCompare(b)).map((extraFsName) => {
|
||||
let diskSize = systemStats.at(-1)?.stats.efs?.[extraFsName].d ?? NaN
|
||||
// round to nearest GB
|
||||
if (diskSize >= 100) {
|
||||
|
||||
@@ -484,9 +484,9 @@ function DiskCellWithMultiple(info: CellContext<SystemRecord, unknown>) {
|
||||
const { info: sysInfo, status, id } = info.row.original
|
||||
const extraFs = Object.entries(sysInfo.efs ?? {})
|
||||
const rootDiskPct = sysInfo.dp
|
||||
const rootDiskName = sysInfo.rdn
|
||||
|
||||
// sort extra disks by percentage descending
|
||||
extraFs.sort((a, b) => b[1] - a[1])
|
||||
extraFs.sort((a, b) => a[0].localeCompare(b[0]))
|
||||
|
||||
function getIndicatorColor(pct: number) {
|
||||
const threshold = getMeterStateByThresholds(pct, colorWarn, colorCrit)
|
||||
@@ -541,8 +541,8 @@ function DiskCellWithMultiple(info: CellContext<SystemRecord, unknown>) {
|
||||
<TooltipContent side="right" className="max-w-xs pb-2">
|
||||
<div className="grid gap-1">
|
||||
<div className="grid gap-0.5">
|
||||
<div className="text-[0.65rem] text-muted-foreground uppercase tracking-wide tabular-nums">
|
||||
<Trans context="Root disk label">Root</Trans>
|
||||
<div className="text-[0.65rem] max-w-40 text-muted-foreground uppercase tracking-wide truncate tabular-nums">
|
||||
{rootDiskName ?? <Trans context="Root disk label">Root</Trans>}
|
||||
</div>
|
||||
<div className="flex gap-2 items-center tabular-nums text-xs">
|
||||
<span className="min-w-7">{decimalString(rootDiskPct, rootDiskPct >= 10 ? 1 : 2)}%</span>
|
||||
|
||||
Vendored
+2
@@ -78,6 +78,8 @@ export interface SystemInfo {
|
||||
efs?: Record<string, number>
|
||||
/** services [totalServices, numFailedServices] */
|
||||
sv?: [number, number]
|
||||
/** custom root disk name */
|
||||
rdn?: string
|
||||
}
|
||||
|
||||
export interface SystemStats {
|
||||
|
||||
Reference in New Issue
Block a user