feat: collect and report 1-min load average

This commit is contained in:
2026-06-18 14:41:04 +01:00
parent 6756d19d93
commit b8ee27eec3
10 changed files with 139 additions and 4 deletions

View File

@@ -9,6 +9,7 @@ import (
"bugs.watch/agent/internal/collectors"
"bugs.watch/agent/internal/collectors/cpu"
"bugs.watch/agent/internal/collectors/disk"
"bugs.watch/agent/internal/collectors/loadavg"
"bugs.watch/agent/internal/collectors/memory"
"bugs.watch/agent/internal/collectors/uptime"
"bugs.watch/agent/internal/config"
@@ -32,6 +33,7 @@ func Run(ctx context.Context, cfg config.Config) {
cpu.New(),
memory.New(),
disk.New(),
loadavg.New(),
}
mgr := dbmanager.New(cfg.DBConfigPath)

View File

@@ -16,7 +16,9 @@ type Window struct {
uptime uint64
// DB metrics — populated only when a DB collector is registered.
load float64
// DB metrics. populated only when a DB collector is registered.
hasDB bool
dbDriver uint8
dbConnPctSum float64
@@ -34,6 +36,7 @@ type Snapshot struct {
MemAvg float64
DiskAvg float64
Uptime uint64
Load float64
// nil when DB monitoring is not enabled.
DBDriver *uint8
@@ -66,6 +69,10 @@ func (w *Window) SetUptime(value uint64) {
w.uptime = value
}
func (w *Window) SetLoad(value float64) {
w.load = value
}
func (w *Window) AddDBConnPct(v float64) {
w.dbConnPctSum += v
w.dbConnPctCount++
@@ -118,6 +125,7 @@ func (w *Window) Snapshot() Snapshot {
MemAvg: memAvg,
DiskAvg: diskAvg,
Uptime: w.uptime,
Load: w.load,
}
if w.hasDB {

View File

@@ -0,0 +1,41 @@
package loadavg
import (
"os"
"strconv"
"strings"
"bugs.watch/agent/internal/aggregate"
)
type Collector struct{}
func New() *Collector {
return &Collector{}
}
func (c *Collector) Name() string {
return "loadavg"
}
// Collect reads /proc/loadavg and stores the 1-minute load average.
// Failure is silently ignored by design.
func (c *Collector) Collect(window *aggregate.Window) {
data, err := os.ReadFile("/proc/loadavg")
if err != nil {
return
}
// Format: "<load1> <load5> <load15> <running/total> <last_pid>"
fields := strings.Fields(string(data))
if len(fields) < 1 {
return
}
load1, err := strconv.ParseFloat(fields[0], 64)
if err != nil {
return
}
window.SetLoad(load1)
}

View File

@@ -20,7 +20,7 @@ import (
sqlitecol "bugs.watch/agent/internal/collectors/sqlite"
)
// Driver type identifiers used as the db_driver field in the health payload
// Driver type identifiers. used as the db_driver field in the health payload
// so the dashboard can render the correct icon without parsing strings.
const (
DriverNone uint8 = 0

View File

@@ -38,6 +38,7 @@ func (s *HTTPSender) Send(ctx context.Context, snap aggregate.Snapshot) error {
MemAvg: snap.MemAvg,
DiskAvg: snap.DiskAvg,
Uptime: snap.Uptime,
Load: snap.Load,
HostID: s.hostID,
Environment: s.env,
DBDriver: snap.DBDriver,

View File

@@ -22,11 +22,12 @@ func (s *LoggingSender) Send(ctx context.Context, snap aggregate.Snapshot) error
return ctx.Err()
default:
log.Printf(
"SEND cpu=%.2f%% mem=%.2f%% disk=%.2f%% uptime=%ds",
"SEND cpu=%.2f%% mem=%.2f%% disk=%.2f%% uptime=%ds load=%.2f",
snap.CPUAvg,
snap.MemAvg,
snap.DiskAvg,
snap.Uptime,
snap.Load,
)
return nil
}

View File

@@ -10,11 +10,12 @@ type SnapshotPayload struct {
MemAvg float64 `json:"mem_avg"`
DiskAvg float64 `json:"disk_avg"`
Uptime uint64 `json:"uptime"`
Load float64 `json:"load"`
HostID string `json:"host_id,omitempty"`
Environment string `json:"environment,omitempty"`
// Optional only present when DB monitoring is enabled.
// Optional. only present when DB monitoring is enabled.
// DBDriver is a numeric identifier: 1=mysql/mariadb 2=postgres 3=redis 4=mongodb 5=sqlite
DBDriver *uint8 `json:"db_driver,omitempty"`
DBConnPct *float64 `json:"db_conn_pct,omitempty"`