package loadavg import ( "context" "fmt" "os" "strconv" "strings" "time" "git.faercol.me/monitoring/sys-exporter/registry" "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" ) const loadAvgFileLocation = "/proc/loadavg" type LoadAvgCollector struct { loadAvgFileLocation string promExporter *prometheus.SummaryVec updateFreq time.Duration l *zap.SugaredLogger } 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, l *zap.SugaredLogger) { c.l = l c.l.Debug("Initializing collector") if err := c.update(); err != nil { c.l.Errorf("Failed to init collector: %s\n", err) } for { select { case <-ctx.Done(): c.l.Debug("Stopping collector") return case <-time.After(c.updateFreq): c.l.Debug("Updating collector") if err := c.update(); err != nil { c.l.Errorf("Failed to update 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()) }