diff --git a/beszel/internal/agent/system.go b/beszel/internal/agent/system.go index 4a9c2c6..215b504 100644 --- a/beszel/internal/agent/system.go +++ b/beszel/internal/agent/system.go @@ -80,10 +80,11 @@ func (a *Agent) getSystemStats() system.Stats { // load average if avgstat, err := load.Avg(); err == nil { - systemStats.LoadAvg1 = twoDecimals(avgstat.Load1) - systemStats.LoadAvg5 = twoDecimals(avgstat.Load5) - systemStats.LoadAvg15 = twoDecimals(avgstat.Load15) - slog.Debug("Load average", "5m", systemStats.LoadAvg5, "15m", systemStats.LoadAvg15) + // TODO: remove these in future release in favor of load avg array + systemStats.LoadAvg[0] = avgstat.Load1 + systemStats.LoadAvg[1] = avgstat.Load5 + systemStats.LoadAvg[2] = avgstat.Load15 + slog.Debug("Load average", "5m", avgstat.Load5, "15m", avgstat.Load15) } else { slog.Error("Error getting load average", "err", err) } @@ -255,9 +256,11 @@ func (a *Agent) getSystemStats() system.Stats { // update base system info a.systemInfo.Cpu = systemStats.Cpu - a.systemInfo.LoadAvg1 = systemStats.LoadAvg1 - a.systemInfo.LoadAvg5 = systemStats.LoadAvg5 - a.systemInfo.LoadAvg15 = systemStats.LoadAvg15 + a.systemInfo.LoadAvg = systemStats.LoadAvg + // TODO: remove these in future release in favor of load avg array + a.systemInfo.LoadAvg1 = systemStats.LoadAvg[0] + a.systemInfo.LoadAvg5 = systemStats.LoadAvg[1] + a.systemInfo.LoadAvg15 = systemStats.LoadAvg[2] a.systemInfo.MemPct = systemStats.MemPct a.systemInfo.DiskPct = systemStats.DiskPct a.systemInfo.Uptime, _ = host.Uptime() diff --git a/beszel/internal/alerts/alerts.go b/beszel/internal/alerts/alerts.go index b6a0533..e796a46 100644 --- a/beszel/internal/alerts/alerts.go +++ b/beszel/internal/alerts/alerts.go @@ -47,9 +47,7 @@ type SystemAlertStats struct { NetSent float64 `json:"ns"` NetRecv float64 `json:"nr"` Temperatures map[string]float32 `json:"t"` - LoadAvg1 float64 `json:"l1"` - LoadAvg5 float64 `json:"l5"` - LoadAvg15 float64 `json:"l15"` + LoadAvg [3]float64 `json:"la"` } type SystemAlertData struct { diff --git a/beszel/internal/alerts/alerts_system.go b/beszel/internal/alerts/alerts_system.go index 7c99a95..c261c69 100644 --- a/beszel/internal/alerts/alerts_system.go +++ b/beszel/internal/alerts/alerts_system.go @@ -55,13 +55,13 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *syst val = data.Info.DashboardTemp unit = "°C" case "LoadAvg1": - val = data.Info.LoadAvg1 + val = data.Info.LoadAvg[0] unit = "" case "LoadAvg5": - val = data.Info.LoadAvg5 + val = data.Info.LoadAvg[1] unit = "" case "LoadAvg15": - val = data.Info.LoadAvg15 + val = data.Info.LoadAvg[2] unit = "" } @@ -200,11 +200,11 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *syst alert.mapSums[key] += temp } case "LoadAvg1": - alert.val += stats.LoadAvg1 + alert.val += stats.LoadAvg[0] case "LoadAvg5": - alert.val += stats.LoadAvg5 + alert.val += stats.LoadAvg[1] case "LoadAvg15": - alert.val += stats.LoadAvg15 + alert.val += stats.LoadAvg[2] default: continue } diff --git a/beszel/internal/entities/system/system.go b/beszel/internal/entities/system/system.go index 7be298f..9efde5c 100644 --- a/beszel/internal/entities/system/system.go +++ b/beszel/internal/entities/system/system.go @@ -31,11 +31,13 @@ type Stats struct { Temperatures map[string]float64 `json:"t,omitempty" cbor:"20,keyasint,omitempty"` ExtraFs map[string]*FsStats `json:"efs,omitempty" cbor:"21,keyasint,omitempty"` GPUData map[string]GPUData `json:"g,omitempty" cbor:"22,keyasint,omitempty"` - LoadAvg1 float64 `json:"l1,omitempty" cbor:"23,keyasint,omitempty,omitzero"` - LoadAvg5 float64 `json:"l5,omitempty" cbor:"24,keyasint,omitempty,omitzero"` - LoadAvg15 float64 `json:"l15,omitempty" cbor:"25,keyasint,omitempty,omitzero"` + LoadAvg1 float64 `json:"l1,omitempty" cbor:"23,keyasint,omitempty"` + LoadAvg5 float64 `json:"l5,omitempty" cbor:"24,keyasint,omitempty"` + LoadAvg15 float64 `json:"l15,omitempty" cbor:"25,keyasint,omitempty"` Bandwidth [2]uint64 `json:"b,omitzero" cbor:"26,keyasint,omitzero"` // [sent bytes, recv bytes] MaxBandwidth [2]uint64 `json:"bm,omitzero" cbor:"27,keyasint,omitzero"` // [sent bytes, recv bytes] + LoadAvg [3]float64 `json:"la,omitempty" cbor:"28,keyasint"` + // TODO: remove other load fields in future release in favor of load avg array } type GPUData struct { @@ -79,25 +81,27 @@ const ( ) type Info struct { - Hostname string `json:"h" cbor:"0,keyasint"` - KernelVersion string `json:"k,omitempty" cbor:"1,keyasint,omitempty"` - Cores int `json:"c" cbor:"2,keyasint"` - Threads int `json:"t,omitempty" cbor:"3,keyasint,omitempty"` - CpuModel string `json:"m" cbor:"4,keyasint"` - Uptime uint64 `json:"u" cbor:"5,keyasint"` - Cpu float64 `json:"cpu" cbor:"6,keyasint"` - MemPct float64 `json:"mp" cbor:"7,keyasint"` - DiskPct float64 `json:"dp" cbor:"8,keyasint"` - Bandwidth float64 `json:"b" cbor:"9,keyasint"` - AgentVersion string `json:"v" cbor:"10,keyasint"` - Podman bool `json:"p,omitempty" cbor:"11,keyasint,omitempty"` - GpuPct float64 `json:"g,omitempty" cbor:"12,keyasint,omitempty"` - DashboardTemp float64 `json:"dt,omitempty" cbor:"13,keyasint,omitempty"` - Os Os `json:"os" cbor:"14,keyasint"` - LoadAvg1 float64 `json:"l1,omitempty" cbor:"15,keyasint,omitempty"` - LoadAvg5 float64 `json:"l5,omitempty" cbor:"16,keyasint,omitempty"` - LoadAvg15 float64 `json:"l15,omitempty" cbor:"17,keyasint,omitempty"` - BandwidthBytes uint64 `json:"bb" cbor:"18,keyasint"` + Hostname string `json:"h" cbor:"0,keyasint"` + KernelVersion string `json:"k,omitempty" cbor:"1,keyasint,omitempty"` + Cores int `json:"c" cbor:"2,keyasint"` + Threads int `json:"t,omitempty" cbor:"3,keyasint,omitempty"` + CpuModel string `json:"m" cbor:"4,keyasint"` + Uptime uint64 `json:"u" cbor:"5,keyasint"` + Cpu float64 `json:"cpu" cbor:"6,keyasint"` + MemPct float64 `json:"mp" cbor:"7,keyasint"` + DiskPct float64 `json:"dp" cbor:"8,keyasint"` + Bandwidth float64 `json:"b" cbor:"9,keyasint"` + AgentVersion string `json:"v" cbor:"10,keyasint"` + Podman bool `json:"p,omitempty" cbor:"11,keyasint,omitempty"` + GpuPct float64 `json:"g,omitempty" cbor:"12,keyasint,omitempty"` + DashboardTemp float64 `json:"dt,omitempty" cbor:"13,keyasint,omitempty"` + Os Os `json:"os" cbor:"14,keyasint"` + LoadAvg1 float64 `json:"l1,omitempty" cbor:"15,keyasint,omitempty"` + LoadAvg5 float64 `json:"l5,omitempty" cbor:"16,keyasint,omitempty"` + LoadAvg15 float64 `json:"l15,omitempty" cbor:"17,keyasint,omitempty"` + BandwidthBytes uint64 `json:"bb" cbor:"18,keyasint"` + LoadAvg [3]float64 `json:"la,omitempty" cbor:"19,keyasint"` + // TODO: remove load fields in future release in favor of load avg array } // Final data structure to return to the hub diff --git a/beszel/internal/records/records.go b/beszel/internal/records/records.go index a1856ee..7dd782b 100644 --- a/beszel/internal/records/records.go +++ b/beszel/internal/records/records.go @@ -203,9 +203,9 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) * sum.DiskWritePs += stats.DiskWritePs sum.NetworkSent += stats.NetworkSent sum.NetworkRecv += stats.NetworkRecv - sum.LoadAvg1 += stats.LoadAvg1 - sum.LoadAvg5 += stats.LoadAvg5 - sum.LoadAvg15 += stats.LoadAvg15 + sum.LoadAvg[0] += stats.LoadAvg[0] + sum.LoadAvg[1] += stats.LoadAvg[1] + sum.LoadAvg[2] += stats.LoadAvg[2] sum.Bandwidth[0] += stats.Bandwidth[0] sum.Bandwidth[1] += stats.Bandwidth[1] // Set peak values @@ -285,9 +285,9 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) * sum.DiskWritePs = twoDecimals(sum.DiskWritePs / count) sum.NetworkSent = twoDecimals(sum.NetworkSent / count) sum.NetworkRecv = twoDecimals(sum.NetworkRecv / count) - sum.LoadAvg1 = twoDecimals(sum.LoadAvg1 / count) - sum.LoadAvg5 = twoDecimals(sum.LoadAvg5 / count) - sum.LoadAvg15 = twoDecimals(sum.LoadAvg15 / count) + sum.LoadAvg[0] = twoDecimals(sum.LoadAvg[0] / count) + sum.LoadAvg[1] = twoDecimals(sum.LoadAvg[1] / count) + sum.LoadAvg[2] = twoDecimals(sum.LoadAvg[2] / count) sum.Bandwidth[0] = sum.Bandwidth[0] / uint64(count) sum.Bandwidth[1] = sum.Bandwidth[1] / uint64(count) // Average temperatures diff --git a/beszel/site/src/components/charts/load-average-chart.tsx b/beszel/site/src/components/charts/load-average-chart.tsx index 752993a..f5d4c5b 100644 --- a/beszel/site/src/components/charts/load-average-chart.tsx +++ b/beszel/site/src/components/charts/load-average-chart.tsx @@ -9,31 +9,30 @@ import { xAxis, } from "@/components/ui/chart" import { useYAxisWidth, cn, formatShortDate, toFixedFloat, decimalString, chartMargin } from "@/lib/utils" -import { ChartData } from "@/types" +import { ChartData, SystemStats } from "@/types" import { memo } from "react" import { t } from "@lingui/core/macro" export default memo(function LoadAverageChart({ chartData }: { chartData: ChartData }) { const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() - if (chartData.systemStats.length === 0) { - return null - } - - const keys = { - l1: { + const keys: { legacy: keyof SystemStats; color: string; label: string }[] = [ + { + legacy: "l1", color: "hsl(271, 81%, 60%)", // Purple label: t({ message: `1 min`, comment: "Load average" }), }, - l5: { + { + legacy: "l5", color: "hsl(217, 91%, 60%)", // Blue label: t({ message: `5 min`, comment: "Load average" }), }, - l15: { + { + legacy: "l15", color: "hsl(25, 95%, 53%)", // Orange label: t({ message: `15 min`, comment: "Load average" }), }, - } + ] return (