87 lines
2.2 KiB
Go
87 lines
2.2 KiB
Go
|
package loadavg
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"git.faercol.me/monitoring/sys-exporter/registry"
|
||
|
"github.com/prometheus/client_golang/prometheus"
|
||
|
)
|
||
|
|
||
|
const loadAvgFileLocation = "/proc/loadavg"
|
||
|
|
||
|
type LoadAvgCollector struct {
|
||
|
loadAvgFileLocation string
|
||
|
promExporter *prometheus.SummaryVec
|
||
|
updateFreq time.Duration
|
||
|
}
|
||
|
|
||
|
func (c *LoadAvgCollector) Collect() interface{} {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *LoadAvgCollector) update() error {
|
||
|
fileContent, err := os.ReadFile(c.loadAvgFileLocation)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to read loadavg file: %w", err)
|
||
|
}
|
||
|
|
||
|
vals := strings.Split(string(fileContent), " ")
|
||
|
if len(vals) != 5 {
|
||
|
return fmt.Errorf("invalid format %q for loadavg file", string(fileContent))
|
||
|
}
|
||
|
|
||
|
var load1Min, load5Min, load15Min float64
|
||
|
if load1Min, err = strconv.ParseFloat(vals[0], 64); err != nil {
|
||
|
return fmt.Errorf("invalid value %q for load 1min: %w", vals[0], err)
|
||
|
}
|
||
|
if load5Min, err = strconv.ParseFloat(vals[1], 64); err != nil {
|
||
|
return fmt.Errorf("invalid value %q for load 5mins: %w", vals[1], err)
|
||
|
}
|
||
|
if load15Min, err = strconv.ParseFloat(vals[2], 64); err != nil {
|
||
|
return fmt.Errorf("invalid value %q for load 15min: %w", vals[2], err)
|
||
|
}
|
||
|
|
||
|
c.promExporter.WithLabelValues("1min").Observe(load1Min)
|
||
|
c.promExporter.WithLabelValues("5mins").Observe(load5Min)
|
||
|
c.promExporter.WithLabelValues("15mins").Observe(load15Min)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *LoadAvgCollector) Run(ctx context.Context) {
|
||
|
if err := c.update(); err != nil {
|
||
|
fmt.Printf("Failed to init loadavg collector: %s\n", err)
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
select {
|
||
|
case <-ctx.Done():
|
||
|
return
|
||
|
case <-time.After(c.updateFreq):
|
||
|
if err := c.update(); err != nil {
|
||
|
fmt.Printf("Failed to update loadavg collector: %s\n", err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *LoadAvgCollector) PromCollector() prometheus.Collector {
|
||
|
return c.promExporter
|
||
|
}
|
||
|
|
||
|
func New() *LoadAvgCollector {
|
||
|
return &LoadAvgCollector{
|
||
|
updateFreq: 1 * time.Second,
|
||
|
loadAvgFileLocation: loadAvgFileLocation,
|
||
|
promExporter: prometheus.NewSummaryVec(prometheus.SummaryOpts{Namespace: "system", Name: "loadavg", Help: "Load average of the system"}, []string{"period"}),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func init() {
|
||
|
registry.R.MustRegisterCollector("system.loadavg", New())
|
||
|
}
|