85 lines
1.9 KiB
Go
85 lines
1.9 KiB
Go
|
package uptime
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"git.faercol.me/monitoring/sys-exporter/registry"
|
||
|
"github.com/prometheus/client_golang/prometheus"
|
||
|
)
|
||
|
|
||
|
const procUptimeLocation = "/proc/uptime"
|
||
|
|
||
|
type UptimeCollector struct {
|
||
|
ctx context.Context
|
||
|
procFileLocation string
|
||
|
uptimeFreq time.Duration
|
||
|
uptime time.Duration
|
||
|
uptimeProm prometheus.Gauge
|
||
|
}
|
||
|
|
||
|
func (c *UptimeCollector) Collect() interface{} {
|
||
|
return c.uptime
|
||
|
}
|
||
|
|
||
|
func (c *UptimeCollector) update() error {
|
||
|
fileContent, err := os.ReadFile(c.procFileLocation)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to read uptime file: %w", err)
|
||
|
}
|
||
|
|
||
|
uptimeVals := strings.Split(string(fileContent), " ")
|
||
|
if len(uptimeVals) != 2 {
|
||
|
return fmt.Errorf("invalid format for /proc/uptime: %q", string(fileContent))
|
||
|
}
|
||
|
|
||
|
uptimeFloat, err := strconv.ParseFloat(uptimeVals[0], 64)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("invalid uptime format for float %s: %w", uptimeVals[0], err)
|
||
|
}
|
||
|
|
||
|
c.uptime = time.Duration(int(uptimeFloat)) * time.Second
|
||
|
c.uptimeProm.Set(uptimeFloat)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *UptimeCollector) PromCollector() prometheus.Collector {
|
||
|
return c.uptimeProm
|
||
|
}
|
||
|
|
||
|
func (c *UptimeCollector) Run(ctx context.Context) {
|
||
|
if err := c.update(); err != nil {
|
||
|
fmt.Printf("Failed to init collector: %s\n", err)
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
select {
|
||
|
case <-ctx.Done():
|
||
|
return
|
||
|
case <-time.After(c.uptimeFreq):
|
||
|
if err := c.update(); err != nil {
|
||
|
fmt.Printf("Failed to update collector: %s\n", err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func New() *UptimeCollector {
|
||
|
return &UptimeCollector{
|
||
|
ctx: context.TODO(),
|
||
|
procFileLocation: procUptimeLocation,
|
||
|
uptimeFreq: 1 * time.Second,
|
||
|
uptime: 0,
|
||
|
uptimeProm: prometheus.NewGauge(prometheus.GaugeOpts{Namespace: "system", Name: "uptime_nanosec", Help: "System uptime in nanoseconds"}),
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
func init() {
|
||
|
registry.R.MustRegisterCollector("system.uptime", New())
|
||
|
}
|