Compare commits

...

3 Commits

Author SHA1 Message Date
ilya
b012df5669 Fix volume path in Docker run command (#1764) 2026-02-24 15:47:16 -05:00
henrygd
12545b4b6d fix: dedupe root-mirrored extra filesystems during disk discovery (#1428) 2026-02-24 15:41:29 -05:00
henrygd
9e2296452b fix: compute bandwidth alerts from byte-per-second source (#1770)
Use Info.BandwidthBytes converted to MB/s with float division so
bandwidth alert checks are based on current data without integer
truncation near thresholds.
2026-02-24 13:07:27 -05:00
4 changed files with 87 additions and 2 deletions

View File

@@ -197,9 +197,60 @@ func (a *Agent) initializeDiskInfo() {
a.fsStats[rootKey] = &system.FsStats{Root: true, Mountpoint: rootMountPoint}
}
a.pruneDuplicateRootExtraFilesystems()
a.initializeDiskIoStats(diskIoCounters)
}
// Removes extra filesystems that mirror root usage (https://github.com/henrygd/beszel/issues/1428).
func (a *Agent) pruneDuplicateRootExtraFilesystems() {
var rootMountpoint string
for _, stats := range a.fsStats {
if stats != nil && stats.Root {
rootMountpoint = stats.Mountpoint
break
}
}
if rootMountpoint == "" {
return
}
rootUsage, err := disk.Usage(rootMountpoint)
if err != nil {
return
}
for name, stats := range a.fsStats {
if stats == nil || stats.Root {
continue
}
extraUsage, err := disk.Usage(stats.Mountpoint)
if err != nil {
continue
}
if hasSameDiskUsage(rootUsage, extraUsage) {
slog.Info("Ignoring duplicate FS", "name", name, "mount", stats.Mountpoint)
delete(a.fsStats, name)
}
}
}
// hasSameDiskUsage compares root/extra usage with a small byte tolerance.
func hasSameDiskUsage(a, b *disk.UsageStat) bool {
if a == nil || b == nil || a.Total == 0 || b.Total == 0 {
return false
}
// Allow minor drift between sequential disk usage calls.
const toleranceBytes uint64 = 16 * 1024 * 1024
return withinUsageTolerance(a.Total, b.Total, toleranceBytes) &&
withinUsageTolerance(a.Used, b.Used, toleranceBytes)
}
// withinUsageTolerance reports whether two byte values differ by at most tolerance.
func withinUsageTolerance(a, b, tolerance uint64) bool {
if a >= b {
return a-b <= tolerance
}
return b-a <= tolerance
}
// Returns matching device from /proc/diskstats.
// bool is true if a match was found.
func findIoDevice(filesystem string, diskIoCounters map[string]disk.IOCountersStat) (string, bool) {

View File

@@ -372,3 +372,37 @@ func TestDiskUsageCaching(t *testing.T) {
"lastDiskUsageUpdate should be refreshed when cache expires")
})
}
func TestHasSameDiskUsage(t *testing.T) {
const toleranceBytes uint64 = 16 * 1024 * 1024
t.Run("returns true when totals and usage are equal", func(t *testing.T) {
a := &disk.UsageStat{Total: 100 * 1024 * 1024 * 1024, Used: 42 * 1024 * 1024 * 1024}
b := &disk.UsageStat{Total: 100 * 1024 * 1024 * 1024, Used: 42 * 1024 * 1024 * 1024}
assert.True(t, hasSameDiskUsage(a, b))
})
t.Run("returns true within tolerance", func(t *testing.T) {
a := &disk.UsageStat{Total: 100 * 1024 * 1024 * 1024, Used: 42 * 1024 * 1024 * 1024}
b := &disk.UsageStat{
Total: a.Total + toleranceBytes - 1,
Used: a.Used - toleranceBytes + 1,
}
assert.True(t, hasSameDiskUsage(a, b))
})
t.Run("returns false when total exceeds tolerance", func(t *testing.T) {
a := &disk.UsageStat{Total: 100 * 1024 * 1024 * 1024, Used: 42 * 1024 * 1024 * 1024}
b := &disk.UsageStat{
Total: a.Total + toleranceBytes + 1,
Used: a.Used,
}
assert.False(t, hasSameDiskUsage(a, b))
})
t.Run("returns false for nil or zero total", func(t *testing.T) {
assert.False(t, hasSameDiskUsage(nil, &disk.UsageStat{Total: 1, Used: 1}))
assert.False(t, hasSameDiskUsage(&disk.UsageStat{Total: 1, Used: 1}, nil))
assert.False(t, hasSameDiskUsage(&disk.UsageStat{Total: 0, Used: 0}, &disk.UsageStat{Total: 1, Used: 1}))
})
}

View File

@@ -38,7 +38,7 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *syst
case "Memory":
val = data.Info.MemPct
case "Bandwidth":
val = data.Info.Bandwidth
val = float64(data.Info.BandwidthBytes) / (1024 * 1024)
unit = " MB/s"
case "Disk":
maxUsedPct := data.Info.DiskPct

View File

@@ -43,7 +43,7 @@ export function copyDockerCompose(port = "45876", publicKey: string, token: stri
export function copyDockerRun(port = "45876", publicKey: string, token: string) {
copyToClipboard(
`docker run -d --name beszel-agent --network host --restart unless-stopped -v /var/run/docker.sock:/var/run/docker.sock:ro -v ./beszel_agent_data:/var/lib/beszel-agent -e KEY="${publicKey}" -e LISTEN=${port} -e TOKEN="${token}" -e HUB_URL="${getHubURL()}" henrygd/beszel-agent`
`docker run -d --name beszel-agent --network host --restart unless-stopped -v /var/run/docker.sock:/var/run/docker.sock:ro -v beszel_agent_data:/var/lib/beszel-agent -e KEY="${publicKey}" -e LISTEN=${port} -e TOKEN="${token}" -e HUB_URL="${getHubURL()}" henrygd/beszel-agent`
)
}