mirror of
https://github.com/henrygd/beszel.git
synced 2026-08-14 14:27:51 +02:00
Compare commits
2 Commits
3586f73f30
...
3730a78e5a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3730a78e5a | ||
|
|
7cdd0907e8 |
@@ -56,7 +56,7 @@ dev-hub: export ENV=dev
|
|||||||
dev-hub:
|
dev-hub:
|
||||||
mkdir -p ./site/dist && touch ./site/dist/index.html
|
mkdir -p ./site/dist && touch ./site/dist/index.html
|
||||||
@if command -v entr >/dev/null 2>&1; then \
|
@if command -v entr >/dev/null 2>&1; then \
|
||||||
find ./cmd/hub ./internal/{alerts,hub,records,users} -name "*.go" | entr -r -s "cd ./cmd/hub && go run . serve"; \
|
find ./cmd/hub/*.go ./internal/{alerts,hub,records,users}/*.go | entr -r -s "cd ./cmd/hub && go run . serve --http 0.0.0.0:8090"; \
|
||||||
else \
|
else \
|
||||||
cd ./cmd/hub && go run . serve --http 0.0.0.0:8090; \
|
cd ./cmd/hub && go run . serve --http 0.0.0.0:8090; \
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ 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.LoadAvg5 = systemStats.LoadAvg5
|
a.systemInfo.LoadAvg5 = systemStats.LoadAvg5
|
||||||
a.systemInfo.LoadAvg15 = systemStats.LoadAvg15
|
a.systemInfo.LoadAvg15 = systemStats.LoadAvg15
|
||||||
a.systemInfo.MemPct = systemStats.MemPct
|
a.systemInfo.MemPct = systemStats.MemPct
|
||||||
|
|||||||
@@ -47,6 +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"`
|
||||||
LoadAvg5 float64 `json:"l5"`
|
LoadAvg5 float64 `json:"l5"`
|
||||||
LoadAvg15 float64 `json:"l15"`
|
LoadAvg15 float64 `json:"l15"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *syst
|
|||||||
}
|
}
|
||||||
val = data.Info.DashboardTemp
|
val = data.Info.DashboardTemp
|
||||||
unit = "°C"
|
unit = "°C"
|
||||||
|
case "LoadAvg1":
|
||||||
|
val = data.Info.LoadAvg1
|
||||||
|
unit = ""
|
||||||
case "LoadAvg5":
|
case "LoadAvg5":
|
||||||
val = data.Info.LoadAvg5
|
val = data.Info.LoadAvg5
|
||||||
unit = ""
|
unit = ""
|
||||||
@@ -196,6 +199,8 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *syst
|
|||||||
}
|
}
|
||||||
alert.mapSums[key] += temp
|
alert.mapSums[key] += temp
|
||||||
}
|
}
|
||||||
|
case "LoadAvg1":
|
||||||
|
alert.val += stats.LoadAvg1
|
||||||
case "LoadAvg5":
|
case "LoadAvg5":
|
||||||
alert.val += stats.LoadAvg5
|
alert.val += stats.LoadAvg5
|
||||||
case "LoadAvg15":
|
case "LoadAvg15":
|
||||||
|
|||||||
@@ -92,8 +92,9 @@ type Info struct {
|
|||||||
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"`
|
||||||
LoadAvg5 float64 `json:"l5,omitempty" cbor:"15,keyasint,omitempty,omitzero"`
|
LoadAvg1 float64 `json:"l1,omitempty" cbor:"15,keyasint,omitempty"`
|
||||||
LoadAvg15 float64 `json:"l15,omitempty" cbor:"16,keyasint,omitempty,omitzero"`
|
LoadAvg5 float64 `json:"l5,omitempty" cbor:"16,keyasint,omitempty"`
|
||||||
|
LoadAvg15 float64 `json:"l15,omitempty" cbor:"17,keyasint,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final data structure to return to the hub
|
// Final data structure to return to the hub
|
||||||
|
|||||||
@@ -203,6 +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.LoadAvg5 += stats.LoadAvg5
|
||||||
|
sum.LoadAvg15 += stats.LoadAvg15
|
||||||
// Set peak values
|
// Set peak values
|
||||||
sum.MaxCpu = max(sum.MaxCpu, stats.MaxCpu, stats.Cpu)
|
sum.MaxCpu = max(sum.MaxCpu, stats.MaxCpu, stats.Cpu)
|
||||||
sum.MaxNetworkSent = max(sum.MaxNetworkSent, stats.MaxNetworkSent, stats.NetworkSent)
|
sum.MaxNetworkSent = max(sum.MaxNetworkSent, stats.MaxNetworkSent, stats.NetworkSent)
|
||||||
@@ -278,7 +281,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.LoadAvg5 = twoDecimals(sum.LoadAvg5 / count)
|
||||||
|
sum.LoadAvg15 = twoDecimals(sum.LoadAvg15 / count)
|
||||||
// Average temperatures
|
// Average temperatures
|
||||||
if sum.Temperatures != nil && tempCount > 0 {
|
if sum.Temperatures != nil && tempCount > 0 {
|
||||||
for key := range sum.Temperatures {
|
for key := range sum.Temperatures {
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ func init() {
|
|||||||
"Disk",
|
"Disk",
|
||||||
"Temperature",
|
"Temperature",
|
||||||
"Bandwidth",
|
"Bandwidth",
|
||||||
|
"LoadAvg1",
|
||||||
"LoadAvg5",
|
"LoadAvg5",
|
||||||
"LoadAvg15"
|
"LoadAvg15"
|
||||||
]
|
]
|
||||||
91
beszel/site/src/components/charts/load-average-chart.tsx
Normal file
91
beszel/site/src/components/charts/load-average-chart.tsx
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import { CartesianGrid, Line, LineChart, YAxis } from "recharts"
|
||||||
|
|
||||||
|
import {
|
||||||
|
ChartContainer,
|
||||||
|
ChartLegend,
|
||||||
|
ChartLegendContent,
|
||||||
|
ChartTooltip,
|
||||||
|
ChartTooltipContent,
|
||||||
|
xAxis,
|
||||||
|
} from "@/components/ui/chart"
|
||||||
|
import { useYAxisWidth, cn, formatShortDate, toFixedFloat, decimalString, chartMargin } from "@/lib/utils"
|
||||||
|
import { ChartData } 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: {
|
||||||
|
color: "hsl(271, 81%, 60%)", // Purple
|
||||||
|
label: t`1 min`,
|
||||||
|
},
|
||||||
|
l5: {
|
||||||
|
color: "hsl(217, 91%, 60%)", // Blue
|
||||||
|
label: t`5 min`,
|
||||||
|
},
|
||||||
|
l15: {
|
||||||
|
color: "hsl(25, 95%, 53%)", // Orange
|
||||||
|
label: t`15 min`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ChartContainer
|
||||||
|
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||||
|
"opacity-100": yAxisWidth,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<LineChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||||
|
<CartesianGrid vertical={false} />
|
||||||
|
<YAxis
|
||||||
|
direction="ltr"
|
||||||
|
orientation={chartData.orientation}
|
||||||
|
className="tracking-tighter"
|
||||||
|
domain={[0, "auto"]}
|
||||||
|
width={yAxisWidth}
|
||||||
|
tickFormatter={(value) => {
|
||||||
|
return updateYAxisWidth(String(toFixedFloat(value, 2)))
|
||||||
|
}}
|
||||||
|
tickLine={false}
|
||||||
|
axisLine={false}
|
||||||
|
/>
|
||||||
|
{xAxis(chartData)}
|
||||||
|
<ChartTooltip
|
||||||
|
animationEasing="ease-out"
|
||||||
|
animationDuration={150}
|
||||||
|
// @ts-ignore
|
||||||
|
// itemSorter={(a, b) => b.value - a.value}
|
||||||
|
content={
|
||||||
|
<ChartTooltipContent
|
||||||
|
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||||
|
contentFormatter={(item) => decimalString(item.value)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{Object.entries(keys).map(([key, value]: [string, { color: string; label: string }]) => {
|
||||||
|
return (
|
||||||
|
<Line
|
||||||
|
key={key}
|
||||||
|
dataKey={`stats.${key}`}
|
||||||
|
name={value.label}
|
||||||
|
type="monotoneX"
|
||||||
|
dot={false}
|
||||||
|
strokeWidth={1.5}
|
||||||
|
stroke={value.color}
|
||||||
|
isAnimationActive={false}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
<ChartLegend content={<ChartLegendContent />} />
|
||||||
|
</LineChart>
|
||||||
|
</ChartContainer>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
@@ -48,6 +48,7 @@ const DiskChart = lazy(() => import("../charts/disk-chart"))
|
|||||||
const SwapChart = lazy(() => import("../charts/swap-chart"))
|
const SwapChart = lazy(() => import("../charts/swap-chart"))
|
||||||
const TemperatureChart = lazy(() => import("../charts/temperature-chart"))
|
const TemperatureChart = lazy(() => import("../charts/temperature-chart"))
|
||||||
const GpuPowerChart = lazy(() => import("../charts/gpu-power-chart"))
|
const GpuPowerChart = lazy(() => import("../charts/gpu-power-chart"))
|
||||||
|
const LoadAverageChart = lazy(() => import("../charts/load-average-chart"))
|
||||||
|
|
||||||
const cache = new Map<string, any>()
|
const cache = new Map<string, any>()
|
||||||
|
|
||||||
@@ -595,6 +596,18 @@ export default function SystemDetail({ name }: { name: string }) {
|
|||||||
</ChartCard>
|
</ChartCard>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Load Average chart */}
|
||||||
|
{system.info.l1 !== undefined && (
|
||||||
|
<ChartCard
|
||||||
|
empty={dataEmpty}
|
||||||
|
grid={grid}
|
||||||
|
title={t`Load Average`}
|
||||||
|
description={t`System load averages over time`}
|
||||||
|
>
|
||||||
|
<LoadAverageChart chartData={chartData} />
|
||||||
|
</ChartCard>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Temperature chart */}
|
{/* Temperature chart */}
|
||||||
{systemStats.at(-1)?.stats.t && (
|
{systemStats.at(-1)?.stats.t && (
|
||||||
<ChartCard
|
<ChartCard
|
||||||
|
|||||||
@@ -182,14 +182,14 @@ export default function SystemsTable() {
|
|||||||
onClick={() => copyToClipboard(info.getValue() as string)}
|
onClick={() => copyToClipboard(info.getValue() as string)}
|
||||||
>
|
>
|
||||||
{info.getValue() as string}
|
{info.getValue() as string}
|
||||||
<CopyIcon className="h-2.5 w-2.5" />
|
<CopyIcon className="size-2.5" />
|
||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
header: sortableHeader,
|
header: sortableHeader,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (originalRow) => originalRow.info.cpu,
|
accessorFn: ({ info }) => decimalString(info.cpu, info.cpu >= 10 ? 1 : 2),
|
||||||
id: "cpu",
|
id: "cpu",
|
||||||
name: () => t`CPU`,
|
name: () => t`CPU`,
|
||||||
cell: CellFormatter,
|
cell: CellFormatter,
|
||||||
@@ -221,6 +221,44 @@ export default function SystemsTable() {
|
|||||||
Icon: GpuIcon,
|
Icon: GpuIcon,
|
||||||
header: sortableHeader,
|
header: sortableHeader,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "loadAverage",
|
||||||
|
accessorFn: ({ info }) => {
|
||||||
|
const { l1 = 0, l5 = 0, l15 = 0 } = info
|
||||||
|
return l1 + l5 + l15
|
||||||
|
},
|
||||||
|
name: () => t({ message: "Load Avg", comment: "Short label for load average" }),
|
||||||
|
size: 0,
|
||||||
|
Icon: HourglassIcon,
|
||||||
|
header: sortableHeader,
|
||||||
|
cell(info: CellContext<SystemRecord, unknown>) {
|
||||||
|
const { info: sysInfo, status } = info.row.original
|
||||||
|
if (sysInfo.l1 == undefined) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const { l1 = 0, l5 = 0, l15 = 0, t: cpuThreads = 1 } = sysInfo
|
||||||
|
const loadAverages = [l1, l5, l15]
|
||||||
|
|
||||||
|
function getDotColor() {
|
||||||
|
const max = Math.max(...loadAverages)
|
||||||
|
const normalized = max / cpuThreads
|
||||||
|
if (status !== "up") return "bg-primary/30"
|
||||||
|
if (normalized < 0.7) return "bg-green-500"
|
||||||
|
if (normalized < 1.0) return "bg-yellow-500"
|
||||||
|
return "bg-red-600"
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2 w-full tabular-nums tracking-tight">
|
||||||
|
<span className={cn("inline-block size-2 rounded-full", getDotColor())} />
|
||||||
|
{loadAverages.map((la, i) => (
|
||||||
|
<span key={i}>{decimalString(la, la >= 10 ? 1 : 2)}</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (originalRow) => originalRow.info.b || 0,
|
accessorFn: (originalRow) => originalRow.info.b || 0,
|
||||||
id: "net",
|
id: "net",
|
||||||
@@ -229,8 +267,12 @@ export default function SystemsTable() {
|
|||||||
Icon: EthernetIcon,
|
Icon: EthernetIcon,
|
||||||
header: sortableHeader,
|
header: sortableHeader,
|
||||||
cell(info) {
|
cell(info) {
|
||||||
|
if (info.row.original.status !== "up") {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const val = info.getValue() as number
|
||||||
const userSettings = useStore($userSettings)
|
const userSettings = useStore($userSettings)
|
||||||
const { value, unit } = formatBytes(info.getValue() as number, true, userSettings.unitNet, true)
|
const { value, unit } = formatBytes(val, true, userSettings.unitNet, true)
|
||||||
return (
|
return (
|
||||||
<span className="tabular-nums whitespace-nowrap">
|
<span className="tabular-nums whitespace-nowrap">
|
||||||
{decimalString(value, value >= 100 ? 1 : 2)} {unit}
|
{decimalString(value, value >= 100 ? 1 : 2)} {unit}
|
||||||
@@ -238,46 +280,6 @@ export default function SystemsTable() {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
accessorFn: (originalRow) => originalRow.info.l5,
|
|
||||||
id: "l5",
|
|
||||||
name: () => t({ message: "L5", comment: "Load average 5 minutes" }),
|
|
||||||
size: 0,
|
|
||||||
hideSort: true,
|
|
||||||
Icon: HourglassIcon,
|
|
||||||
header: sortableHeader,
|
|
||||||
cell(info) {
|
|
||||||
const val = info.getValue() as number
|
|
||||||
if (!val) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<span className={cn("tabular-nums whitespace-nowrap", viewMode === "table" && "ps-1")}>
|
|
||||||
{decimalString(val)}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorFn: (originalRow) => originalRow.info.l15,
|
|
||||||
id: "l15",
|
|
||||||
name: () => t({ message: "L15", comment: "Load average 15 minutes" }),
|
|
||||||
size: 0,
|
|
||||||
hideSort: true,
|
|
||||||
Icon: HourglassIcon,
|
|
||||||
header: sortableHeader,
|
|
||||||
cell(info) {
|
|
||||||
const val = info.getValue() as number
|
|
||||||
if (!val) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<span className={cn("tabular-nums whitespace-nowrap", viewMode === "table" && "ps-1")}>
|
|
||||||
{decimalString(val)}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessorFn: (originalRow) => originalRow.info.dt,
|
accessorFn: (originalRow) => originalRow.info.dt,
|
||||||
id: "temp",
|
id: "temp",
|
||||||
@@ -546,7 +548,7 @@ function SystemsTableHead({ table, colLength }: { table: TableType<SystemRecord>
|
|||||||
<TableRow key={headerGroup.id}>
|
<TableRow key={headerGroup.id}>
|
||||||
{headerGroup.headers.map((header) => {
|
{headerGroup.headers.map((header) => {
|
||||||
return (
|
return (
|
||||||
<TableHead className="px-1" key={header.id}>
|
<TableHead className="px-1.5" key={header.id}>
|
||||||
{flexRender(header.column.columnDef.header, header.getContext())}
|
{flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
</TableHead>
|
</TableHead>
|
||||||
)
|
)
|
||||||
|
|||||||
49
beszel/site/src/components/ui/collapsible.tsx
Normal file
49
beszel/site/src/components/ui/collapsible.tsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { ChevronDownIcon, HourglassIcon } from "lucide-react"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { Button } from "./button"
|
||||||
|
|
||||||
|
interface CollapsibleProps {
|
||||||
|
title: string
|
||||||
|
children: React.ReactNode
|
||||||
|
description?: React.ReactNode
|
||||||
|
defaultOpen?: boolean
|
||||||
|
className?: string
|
||||||
|
icon?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Collapsible({ title, children, description, defaultOpen = false, className, icon }: CollapsibleProps) {
|
||||||
|
const [isOpen, setIsOpen] = React.useState(defaultOpen)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn("border rounded-lg", className)}>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="w-full justify-between p-4 font-semibold"
|
||||||
|
onClick={() => setIsOpen(!isOpen)}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
{icon}
|
||||||
|
{title}
|
||||||
|
</div>
|
||||||
|
<ChevronDownIcon
|
||||||
|
className={cn("h-4 w-4 transition-transform duration-200", {
|
||||||
|
"rotate-180": isOpen,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
{description && (
|
||||||
|
<div className="px-4 pb-2 text-sm text-muted-foreground">
|
||||||
|
{description}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isOpen && (
|
||||||
|
<div className="px-4 pb-4">
|
||||||
|
<div className="grid gap-3">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -407,6 +407,16 @@ export const alertInfo: Record<string, AlertInfo> = {
|
|||||||
icon: ThermometerIcon,
|
icon: ThermometerIcon,
|
||||||
desc: () => t`Triggers when any sensor exceeds a threshold`,
|
desc: () => t`Triggers when any sensor exceeds a threshold`,
|
||||||
},
|
},
|
||||||
|
LoadAvg1: {
|
||||||
|
name: () => t`Load Average 1m`,
|
||||||
|
unit: "",
|
||||||
|
icon: HourglassIcon,
|
||||||
|
max: 100,
|
||||||
|
min: 0.1,
|
||||||
|
start: 10,
|
||||||
|
step: 0.1,
|
||||||
|
desc: () => t`Triggers when 1 minute load average exceeds a threshold`,
|
||||||
|
},
|
||||||
LoadAvg5: {
|
LoadAvg5: {
|
||||||
name: () => t`Load Average 5m`,
|
name: () => t`Load Average 5m`,
|
||||||
unit: "",
|
unit: "",
|
||||||
|
|||||||
2
beszel/site/src/types.d.ts
vendored
2
beszel/site/src/types.d.ts
vendored
@@ -44,6 +44,8 @@ export interface SystemInfo {
|
|||||||
c: number
|
c: number
|
||||||
/** cpu model */
|
/** cpu model */
|
||||||
m: string
|
m: string
|
||||||
|
/** load average 1 minute */
|
||||||
|
l1?: number
|
||||||
/** load average 5 minutes */
|
/** load average 5 minutes */
|
||||||
l5?: number
|
l5?: number
|
||||||
/** load average 15 minutes */
|
/** load average 15 minutes */
|
||||||
|
|||||||
Reference in New Issue
Block a user