mirror of
https://github.com/fankes/beszel.git
synced 2025-10-19 09:49:28 +08:00
refactor load average handling (#982)
- Transitioned from individual load average fields (LoadAvg1, LoadAvg5, LoadAvg15) to a single array (LoadAvg) - Ensure load is displayed when all zero values.
This commit is contained in:
@@ -80,10 +80,11 @@ func (a *Agent) getSystemStats() system.Stats {
|
|||||||
|
|
||||||
// load average
|
// load average
|
||||||
if avgstat, err := load.Avg(); err == nil {
|
if avgstat, err := load.Avg(); err == nil {
|
||||||
systemStats.LoadAvg1 = twoDecimals(avgstat.Load1)
|
// TODO: remove these in future release in favor of load avg array
|
||||||
systemStats.LoadAvg5 = twoDecimals(avgstat.Load5)
|
systemStats.LoadAvg[0] = avgstat.Load1
|
||||||
systemStats.LoadAvg15 = twoDecimals(avgstat.Load15)
|
systemStats.LoadAvg[1] = avgstat.Load5
|
||||||
slog.Debug("Load average", "5m", systemStats.LoadAvg5, "15m", systemStats.LoadAvg15)
|
systemStats.LoadAvg[2] = avgstat.Load15
|
||||||
|
slog.Debug("Load average", "5m", avgstat.Load5, "15m", avgstat.Load15)
|
||||||
} else {
|
} else {
|
||||||
slog.Error("Error getting load average", "err", err)
|
slog.Error("Error getting load average", "err", err)
|
||||||
}
|
}
|
||||||
@@ -255,9 +256,11 @@ func (a *Agent) getSystemStats() system.Stats {
|
|||||||
|
|
||||||
// update base system info
|
// update base system info
|
||||||
a.systemInfo.Cpu = systemStats.Cpu
|
a.systemInfo.Cpu = systemStats.Cpu
|
||||||
a.systemInfo.LoadAvg1 = systemStats.LoadAvg1
|
a.systemInfo.LoadAvg = systemStats.LoadAvg
|
||||||
a.systemInfo.LoadAvg5 = systemStats.LoadAvg5
|
// TODO: remove these in future release in favor of load avg array
|
||||||
a.systemInfo.LoadAvg15 = systemStats.LoadAvg15
|
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.MemPct = systemStats.MemPct
|
||||||
a.systemInfo.DiskPct = systemStats.DiskPct
|
a.systemInfo.DiskPct = systemStats.DiskPct
|
||||||
a.systemInfo.Uptime, _ = host.Uptime()
|
a.systemInfo.Uptime, _ = host.Uptime()
|
||||||
|
@@ -47,9 +47,7 @@ type SystemAlertStats struct {
|
|||||||
NetSent float64 `json:"ns"`
|
NetSent float64 `json:"ns"`
|
||||||
NetRecv float64 `json:"nr"`
|
NetRecv float64 `json:"nr"`
|
||||||
Temperatures map[string]float32 `json:"t"`
|
Temperatures map[string]float32 `json:"t"`
|
||||||
LoadAvg1 float64 `json:"l1"`
|
LoadAvg [3]float64 `json:"la"`
|
||||||
LoadAvg5 float64 `json:"l5"`
|
|
||||||
LoadAvg15 float64 `json:"l15"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SystemAlertData struct {
|
type SystemAlertData struct {
|
||||||
|
@@ -55,13 +55,13 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *syst
|
|||||||
val = data.Info.DashboardTemp
|
val = data.Info.DashboardTemp
|
||||||
unit = "°C"
|
unit = "°C"
|
||||||
case "LoadAvg1":
|
case "LoadAvg1":
|
||||||
val = data.Info.LoadAvg1
|
val = data.Info.LoadAvg[0]
|
||||||
unit = ""
|
unit = ""
|
||||||
case "LoadAvg5":
|
case "LoadAvg5":
|
||||||
val = data.Info.LoadAvg5
|
val = data.Info.LoadAvg[1]
|
||||||
unit = ""
|
unit = ""
|
||||||
case "LoadAvg15":
|
case "LoadAvg15":
|
||||||
val = data.Info.LoadAvg15
|
val = data.Info.LoadAvg[2]
|
||||||
unit = ""
|
unit = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,11 +200,11 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *syst
|
|||||||
alert.mapSums[key] += temp
|
alert.mapSums[key] += temp
|
||||||
}
|
}
|
||||||
case "LoadAvg1":
|
case "LoadAvg1":
|
||||||
alert.val += stats.LoadAvg1
|
alert.val += stats.LoadAvg[0]
|
||||||
case "LoadAvg5":
|
case "LoadAvg5":
|
||||||
alert.val += stats.LoadAvg5
|
alert.val += stats.LoadAvg[1]
|
||||||
case "LoadAvg15":
|
case "LoadAvg15":
|
||||||
alert.val += stats.LoadAvg15
|
alert.val += stats.LoadAvg[2]
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@@ -31,11 +31,13 @@ type Stats struct {
|
|||||||
Temperatures map[string]float64 `json:"t,omitempty" cbor:"20,keyasint,omitempty"`
|
Temperatures map[string]float64 `json:"t,omitempty" cbor:"20,keyasint,omitempty"`
|
||||||
ExtraFs map[string]*FsStats `json:"efs,omitempty" cbor:"21,keyasint,omitempty"`
|
ExtraFs map[string]*FsStats `json:"efs,omitempty" cbor:"21,keyasint,omitempty"`
|
||||||
GPUData map[string]GPUData `json:"g,omitempty" cbor:"22,keyasint,omitempty"`
|
GPUData map[string]GPUData `json:"g,omitempty" cbor:"22,keyasint,omitempty"`
|
||||||
LoadAvg1 float64 `json:"l1,omitempty" cbor:"23,keyasint,omitempty,omitzero"`
|
LoadAvg1 float64 `json:"l1,omitempty" cbor:"23,keyasint,omitempty"`
|
||||||
LoadAvg5 float64 `json:"l5,omitempty" cbor:"24,keyasint,omitempty,omitzero"`
|
LoadAvg5 float64 `json:"l5,omitempty" cbor:"24,keyasint,omitempty"`
|
||||||
LoadAvg15 float64 `json:"l15,omitempty" cbor:"25,keyasint,omitempty,omitzero"`
|
LoadAvg15 float64 `json:"l15,omitempty" cbor:"25,keyasint,omitempty"`
|
||||||
Bandwidth [2]uint64 `json:"b,omitzero" cbor:"26,keyasint,omitzero"` // [sent bytes, recv bytes]
|
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]
|
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 {
|
type GPUData struct {
|
||||||
@@ -79,25 +81,27 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Info struct {
|
type Info struct {
|
||||||
Hostname string `json:"h" cbor:"0,keyasint"`
|
Hostname string `json:"h" cbor:"0,keyasint"`
|
||||||
KernelVersion string `json:"k,omitempty" cbor:"1,keyasint,omitempty"`
|
KernelVersion string `json:"k,omitempty" cbor:"1,keyasint,omitempty"`
|
||||||
Cores int `json:"c" cbor:"2,keyasint"`
|
Cores int `json:"c" cbor:"2,keyasint"`
|
||||||
Threads int `json:"t,omitempty" cbor:"3,keyasint,omitempty"`
|
Threads int `json:"t,omitempty" cbor:"3,keyasint,omitempty"`
|
||||||
CpuModel string `json:"m" cbor:"4,keyasint"`
|
CpuModel string `json:"m" cbor:"4,keyasint"`
|
||||||
Uptime uint64 `json:"u" cbor:"5,keyasint"`
|
Uptime uint64 `json:"u" cbor:"5,keyasint"`
|
||||||
Cpu float64 `json:"cpu" cbor:"6,keyasint"`
|
Cpu float64 `json:"cpu" cbor:"6,keyasint"`
|
||||||
MemPct float64 `json:"mp" cbor:"7,keyasint"`
|
MemPct float64 `json:"mp" cbor:"7,keyasint"`
|
||||||
DiskPct float64 `json:"dp" cbor:"8,keyasint"`
|
DiskPct float64 `json:"dp" cbor:"8,keyasint"`
|
||||||
Bandwidth float64 `json:"b" cbor:"9,keyasint"`
|
Bandwidth float64 `json:"b" cbor:"9,keyasint"`
|
||||||
AgentVersion string `json:"v" cbor:"10,keyasint"`
|
AgentVersion string `json:"v" cbor:"10,keyasint"`
|
||||||
Podman bool `json:"p,omitempty" cbor:"11,keyasint,omitempty"`
|
Podman bool `json:"p,omitempty" cbor:"11,keyasint,omitempty"`
|
||||||
GpuPct float64 `json:"g,omitempty" cbor:"12,keyasint,omitempty"`
|
GpuPct float64 `json:"g,omitempty" cbor:"12,keyasint,omitempty"`
|
||||||
DashboardTemp float64 `json:"dt,omitempty" cbor:"13,keyasint,omitempty"`
|
DashboardTemp float64 `json:"dt,omitempty" cbor:"13,keyasint,omitempty"`
|
||||||
Os Os `json:"os" cbor:"14,keyasint"`
|
Os Os `json:"os" cbor:"14,keyasint"`
|
||||||
LoadAvg1 float64 `json:"l1,omitempty" cbor:"15,keyasint,omitempty"`
|
LoadAvg1 float64 `json:"l1,omitempty" cbor:"15,keyasint,omitempty"`
|
||||||
LoadAvg5 float64 `json:"l5,omitempty" cbor:"16,keyasint,omitempty"`
|
LoadAvg5 float64 `json:"l5,omitempty" cbor:"16,keyasint,omitempty"`
|
||||||
LoadAvg15 float64 `json:"l15,omitempty" cbor:"17,keyasint,omitempty"`
|
LoadAvg15 float64 `json:"l15,omitempty" cbor:"17,keyasint,omitempty"`
|
||||||
BandwidthBytes uint64 `json:"bb" cbor:"18,keyasint"`
|
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
|
// Final data structure to return to the hub
|
||||||
|
@@ -203,9 +203,9 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
|
|||||||
sum.DiskWritePs += stats.DiskWritePs
|
sum.DiskWritePs += stats.DiskWritePs
|
||||||
sum.NetworkSent += stats.NetworkSent
|
sum.NetworkSent += stats.NetworkSent
|
||||||
sum.NetworkRecv += stats.NetworkRecv
|
sum.NetworkRecv += stats.NetworkRecv
|
||||||
sum.LoadAvg1 += stats.LoadAvg1
|
sum.LoadAvg[0] += stats.LoadAvg[0]
|
||||||
sum.LoadAvg5 += stats.LoadAvg5
|
sum.LoadAvg[1] += stats.LoadAvg[1]
|
||||||
sum.LoadAvg15 += stats.LoadAvg15
|
sum.LoadAvg[2] += stats.LoadAvg[2]
|
||||||
sum.Bandwidth[0] += stats.Bandwidth[0]
|
sum.Bandwidth[0] += stats.Bandwidth[0]
|
||||||
sum.Bandwidth[1] += stats.Bandwidth[1]
|
sum.Bandwidth[1] += stats.Bandwidth[1]
|
||||||
// Set peak values
|
// Set peak values
|
||||||
@@ -285,9 +285,9 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
|
|||||||
sum.DiskWritePs = twoDecimals(sum.DiskWritePs / count)
|
sum.DiskWritePs = twoDecimals(sum.DiskWritePs / count)
|
||||||
sum.NetworkSent = twoDecimals(sum.NetworkSent / count)
|
sum.NetworkSent = twoDecimals(sum.NetworkSent / count)
|
||||||
sum.NetworkRecv = twoDecimals(sum.NetworkRecv / count)
|
sum.NetworkRecv = twoDecimals(sum.NetworkRecv / count)
|
||||||
sum.LoadAvg1 = twoDecimals(sum.LoadAvg1 / count)
|
sum.LoadAvg[0] = twoDecimals(sum.LoadAvg[0] / count)
|
||||||
sum.LoadAvg5 = twoDecimals(sum.LoadAvg5 / count)
|
sum.LoadAvg[1] = twoDecimals(sum.LoadAvg[1] / count)
|
||||||
sum.LoadAvg15 = twoDecimals(sum.LoadAvg15 / count)
|
sum.LoadAvg[2] = twoDecimals(sum.LoadAvg[2] / count)
|
||||||
sum.Bandwidth[0] = sum.Bandwidth[0] / uint64(count)
|
sum.Bandwidth[0] = sum.Bandwidth[0] / uint64(count)
|
||||||
sum.Bandwidth[1] = sum.Bandwidth[1] / uint64(count)
|
sum.Bandwidth[1] = sum.Bandwidth[1] / uint64(count)
|
||||||
// Average temperatures
|
// Average temperatures
|
||||||
|
@@ -9,31 +9,30 @@ import {
|
|||||||
xAxis,
|
xAxis,
|
||||||
} from "@/components/ui/chart"
|
} from "@/components/ui/chart"
|
||||||
import { useYAxisWidth, cn, formatShortDate, toFixedFloat, decimalString, chartMargin } from "@/lib/utils"
|
import { useYAxisWidth, cn, formatShortDate, toFixedFloat, decimalString, chartMargin } from "@/lib/utils"
|
||||||
import { ChartData } from "@/types"
|
import { ChartData, SystemStats } from "@/types"
|
||||||
import { memo } from "react"
|
import { memo } from "react"
|
||||||
import { t } from "@lingui/core/macro"
|
import { t } from "@lingui/core/macro"
|
||||||
|
|
||||||
export default memo(function LoadAverageChart({ chartData }: { chartData: ChartData }) {
|
export default memo(function LoadAverageChart({ chartData }: { chartData: ChartData }) {
|
||||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
|
|
||||||
if (chartData.systemStats.length === 0) {
|
const keys: { legacy: keyof SystemStats; color: string; label: string }[] = [
|
||||||
return null
|
{
|
||||||
}
|
legacy: "l1",
|
||||||
|
|
||||||
const keys = {
|
|
||||||
l1: {
|
|
||||||
color: "hsl(271, 81%, 60%)", // Purple
|
color: "hsl(271, 81%, 60%)", // Purple
|
||||||
label: t({ message: `1 min`, comment: "Load average" }),
|
label: t({ message: `1 min`, comment: "Load average" }),
|
||||||
},
|
},
|
||||||
l5: {
|
{
|
||||||
|
legacy: "l5",
|
||||||
color: "hsl(217, 91%, 60%)", // Blue
|
color: "hsl(217, 91%, 60%)", // Blue
|
||||||
label: t({ message: `5 min`, comment: "Load average" }),
|
label: t({ message: `5 min`, comment: "Load average" }),
|
||||||
},
|
},
|
||||||
l15: {
|
{
|
||||||
|
legacy: "l15",
|
||||||
color: "hsl(25, 95%, 53%)", // Orange
|
color: "hsl(25, 95%, 53%)", // Orange
|
||||||
label: t({ message: `15 min`, comment: "Load average" }),
|
label: t({ message: `15 min`, comment: "Load average" }),
|
||||||
},
|
},
|
||||||
}
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -69,16 +68,22 @@ export default memo(function LoadAverageChart({ chartData }: { chartData: ChartD
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{Object.entries(keys).map(([key, value]: [string, { color: string; label: string }]) => {
|
{keys.map(({ legacy, color, label }, i) => {
|
||||||
|
const dataKey = (value: { stats: SystemStats }) => {
|
||||||
|
if (chartData.agentVersion.patch < 1) {
|
||||||
|
return value.stats?.[legacy]
|
||||||
|
}
|
||||||
|
return value.stats?.la?.[i] ?? value.stats?.[legacy]
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Line
|
<Line
|
||||||
key={key}
|
key={i}
|
||||||
dataKey={`stats.${key}`}
|
dataKey={dataKey}
|
||||||
name={value.label}
|
name={label}
|
||||||
type="monotoneX"
|
type="monotoneX"
|
||||||
dot={false}
|
dot={false}
|
||||||
strokeWidth={1.5}
|
strokeWidth={1.5}
|
||||||
stroke={value.color}
|
stroke={color}
|
||||||
isAnimationActive={false}
|
isAnimationActive={false}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@@ -26,6 +26,7 @@ import {
|
|||||||
getHostDisplayValue,
|
getHostDisplayValue,
|
||||||
getPbTimestamp,
|
getPbTimestamp,
|
||||||
listen,
|
listen,
|
||||||
|
parseSemVer,
|
||||||
toFixedFloat,
|
toFixedFloat,
|
||||||
useLocalStorage,
|
useLocalStorage,
|
||||||
} from "@/lib/utils"
|
} from "@/lib/utils"
|
||||||
@@ -191,6 +192,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
|||||||
chartTime,
|
chartTime,
|
||||||
orientation: direction === "rtl" ? "right" : "left",
|
orientation: direction === "rtl" ? "right" : "left",
|
||||||
...getTimeData(chartTime, lastCreated),
|
...getTimeData(chartTime, lastCreated),
|
||||||
|
agentVersion: parseSemVer(system?.info?.v),
|
||||||
}
|
}
|
||||||
}, [systemStats, containerData, direction])
|
}, [systemStats, containerData, direction])
|
||||||
|
|
||||||
@@ -642,7 +644,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Load Average chart */}
|
{/* Load Average chart */}
|
||||||
{system.info.l1 !== undefined && (
|
{chartData.agentVersion?.minor >= 12 && (
|
||||||
<ChartCard
|
<ChartCard
|
||||||
empty={dataEmpty}
|
empty={dataEmpty}
|
||||||
grid={grid}
|
grid={grid}
|
||||||
|
@@ -73,6 +73,7 @@ import {
|
|||||||
formatTemperature,
|
formatTemperature,
|
||||||
decimalString,
|
decimalString,
|
||||||
formatBytes,
|
formatBytes,
|
||||||
|
parseSemVer,
|
||||||
} from "@/lib/utils"
|
} from "@/lib/utils"
|
||||||
import AlertsButton from "../alerts/alert-button"
|
import AlertsButton from "../alerts/alert-button"
|
||||||
import { $router, Link, navigate } from "../router"
|
import { $router, Link, navigate } from "../router"
|
||||||
@@ -224,8 +225,12 @@ export default function SystemsTable() {
|
|||||||
{
|
{
|
||||||
id: "loadAverage",
|
id: "loadAverage",
|
||||||
accessorFn: ({ info }) => {
|
accessorFn: ({ info }) => {
|
||||||
const { l1 = 0, l5 = 0, l15 = 0 } = info
|
const sum = info.la?.reduce((acc, curr) => acc + curr, 0)
|
||||||
return l1 + l5 + l15
|
// TODO: remove this in future release in favor of la array
|
||||||
|
if (!sum) {
|
||||||
|
return (info.l1 ?? 0) + (info.l5 ?? 0) + (info.l15 ?? 0)
|
||||||
|
}
|
||||||
|
return sum
|
||||||
},
|
},
|
||||||
name: () => t({ message: "Load Avg", comment: "Short label for load average" }),
|
name: () => t({ message: "Load Avg", comment: "Short label for load average" }),
|
||||||
size: 0,
|
size: 0,
|
||||||
@@ -233,16 +238,22 @@ export default function SystemsTable() {
|
|||||||
header: sortableHeader,
|
header: sortableHeader,
|
||||||
cell(info: CellContext<SystemRecord, unknown>) {
|
cell(info: CellContext<SystemRecord, unknown>) {
|
||||||
const { info: sysInfo, status } = info.row.original
|
const { info: sysInfo, status } = info.row.original
|
||||||
if (sysInfo.l1 === undefined) {
|
// agent version
|
||||||
|
const { minor, patch } = parseSemVer(sysInfo.v)
|
||||||
|
let loadAverages = sysInfo.la
|
||||||
|
|
||||||
|
// use legacy load averages if agent version is less than 12.1.0
|
||||||
|
if (!loadAverages || (minor === 12 && patch < 1)) {
|
||||||
|
loadAverages = [sysInfo.l1 ?? 0, sysInfo.l5 ?? 0, sysInfo.l15 ?? 0]
|
||||||
|
}
|
||||||
|
|
||||||
|
const max = Math.max(...loadAverages)
|
||||||
|
if (max === 0 && (status === "paused" || minor < 12)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const { l1 = 0, l5 = 0, l15 = 0, t: cpuThreads = 1 } = sysInfo
|
|
||||||
const loadAverages = [l1, l5, l15]
|
|
||||||
|
|
||||||
function getDotColor() {
|
function getDotColor() {
|
||||||
const max = Math.max(...loadAverages)
|
const normalized = max / (sysInfo.t ?? 1)
|
||||||
const normalized = max / cpuThreads
|
|
||||||
if (status !== "up") return "bg-primary/30"
|
if (status !== "up") return "bg-primary/30"
|
||||||
if (normalized < 0.7) return "bg-green-500"
|
if (normalized < 0.7) return "bg-green-500"
|
||||||
if (normalized < 1) return "bg-yellow-500"
|
if (normalized < 1) return "bg-yellow-500"
|
||||||
@@ -252,7 +263,7 @@ export default function SystemsTable() {
|
|||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-[.35em] w-full tabular-nums tracking-tight">
|
<div className="flex items-center gap-[.35em] w-full tabular-nums tracking-tight">
|
||||||
<span className={cn("inline-block size-2 rounded-full me-0.5", getDotColor())} />
|
<span className={cn("inline-block size-2 rounded-full me-0.5", getDotColor())} />
|
||||||
{loadAverages.map((la, i) => (
|
{loadAverages?.map((la, i) => (
|
||||||
<span key={i}>{decimalString(la, la >= 10 ? 1 : 2)}</span>
|
<span key={i}>{decimalString(la, la >= 10 ? 1 : 2)}</span>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -9,6 +9,7 @@ import {
|
|||||||
ChartTimeData,
|
ChartTimeData,
|
||||||
ChartTimes,
|
ChartTimes,
|
||||||
FingerprintRecord,
|
FingerprintRecord,
|
||||||
|
SemVer,
|
||||||
SystemRecord,
|
SystemRecord,
|
||||||
UserSettings,
|
UserSettings,
|
||||||
} from "@/types"
|
} from "@/types"
|
||||||
@@ -495,3 +496,14 @@ export function formatDuration(
|
|||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(" ")
|
.join(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const parseSemVer = (semVer = ""): SemVer => {
|
||||||
|
// if (semVer.startsWith("v")) {
|
||||||
|
// semVer = semVer.slice(1)
|
||||||
|
// }
|
||||||
|
if (semVer.includes("-")) {
|
||||||
|
semVer = semVer.slice(0, semVer.indexOf("-"))
|
||||||
|
}
|
||||||
|
const parts = semVer.split(".").map(Number)
|
||||||
|
return { major: parts?.[0] ?? 0, minor: parts?.[1] ?? 0, patch: parts?.[2] ?? 0 }
|
||||||
|
}
|
||||||
|
12
beszel/site/src/types.d.ts
vendored
12
beszel/site/src/types.d.ts
vendored
@@ -50,6 +50,8 @@ export interface SystemInfo {
|
|||||||
l5?: number
|
l5?: number
|
||||||
/** load average 15 minutes */
|
/** load average 15 minutes */
|
||||||
l15?: number
|
l15?: number
|
||||||
|
/** load average */
|
||||||
|
la?: [number, number, number]
|
||||||
/** operating system */
|
/** operating system */
|
||||||
o?: string
|
o?: string
|
||||||
/** uptime */
|
/** uptime */
|
||||||
@@ -79,12 +81,15 @@ export interface SystemStats {
|
|||||||
cpu: number
|
cpu: number
|
||||||
/** peak cpu */
|
/** peak cpu */
|
||||||
cpum?: number
|
cpum?: number
|
||||||
|
// TODO: remove these in future release in favor of la
|
||||||
/** load average 1 minute */
|
/** load average 1 minute */
|
||||||
l1?: number
|
l1?: number
|
||||||
/** load average 5 minutes */
|
/** load average 5 minutes */
|
||||||
l5?: number
|
l5?: number
|
||||||
/** load average 15 minutes */
|
/** load average 15 minutes */
|
||||||
l15?: number
|
l15?: number
|
||||||
|
/** load average */
|
||||||
|
la?: [number, number, number]
|
||||||
/** total memory (gb) */
|
/** total memory (gb) */
|
||||||
m: number
|
m: number
|
||||||
/** memory used (gb) */
|
/** memory used (gb) */
|
||||||
@@ -234,7 +239,14 @@ type ChartDataContainer = {
|
|||||||
[key: string]: key extends "created" ? never : ContainerStats
|
[key: string]: key extends "created" ? never : ContainerStats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SemVer {
|
||||||
|
major: number
|
||||||
|
minor: number
|
||||||
|
patch: number
|
||||||
|
}
|
||||||
|
|
||||||
export interface ChartData {
|
export interface ChartData {
|
||||||
|
agentVersion: SemVer
|
||||||
systemStats: SystemStatsRecord[]
|
systemStats: SystemStatsRecord[]
|
||||||
containerData: ChartDataContainer[]
|
containerData: ChartDataContainer[]
|
||||||
orientation: "right" | "left"
|
orientation: "right" | "left"
|
||||||
|
Reference in New Issue
Block a user