add lite summary statistics

This commit is contained in:
Josh Deprez 2024-08-25 17:12:19 +10:00
parent 0be5c6d759
commit e9b129c58c

View file

@ -7,36 +7,93 @@ import (
"flag" "flag"
"fmt" "fmt"
"log" "log"
"math"
"net/http" "net/http"
"os/exec" "os/exec"
"sync"
"time" "time"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
) )
var ( var (
addr = flag.String("listen-address", ":9454", "The address to listen on for HTTP requests.") addr = flag.String("listen-address", ":9454", "The address to listen on for HTTP requests.")
pollInterval = flag.Duration("poll-interval", 1*time.Second, "Time between executions of `lifepo4wered-cli get`")
lifepo4weredVars = prometheus.NewGaugeVec( lifepo4weredVars = promauto.NewGaugeVec(
prometheus.GaugeOpts{ prometheus.GaugeOpts{
Name: "lifepo4wered", Name: "lifepo4wered",
Help: "Variables gathered from the lifepo4wered-cli tool", Help: "Variables gathered from the lifepo4wered-cli tool",
}, },
[]string{"var"}, []string{"var"},
) )
lifepo4weredSummaries = map[string]*liteSummary{
"VIN": newLiteSummary("voltage_in", "Voltage in (mV)"),
"VOUT": newLiteSummary("voltage_out", "Voltage out (mV)"),
"VBAT": newLiteSummary("voltage_bat", "Battery voltage (mV)"),
"IOUT": newLiteSummary("current_out", "Current out (mA)"),
}
lifepo4weredPOut = newLiteSummary("power_out", "Power out (mW)")
) )
func init() { type liteSummary struct {
prometheus.MustRegister(lifepo4weredVars) mu sync.Mutex
min float64
max float64
sum float64
count int
desc *prometheus.Desc
} }
func getVars() { func newLiteSummary(varName, help string) *liteSummary {
s := &liteSummary{
min: math.Inf(1),
max: math.Inf(-1),
desc: prometheus.NewDesc("lifepo4wered_"+varName, help, []string{"stat"}, nil),
}
prometheus.MustRegister(s)
return s
}
func (s *liteSummary) Describe(ch chan<- *prometheus.Desc) { ch <- s.desc }
func (s *liteSummary) Collect(ch chan<- prometheus.Metric) {
s.mu.Lock()
defer s.mu.Unlock()
ch <- prometheus.MustNewConstMetric(s.desc, prometheus.GaugeValue, s.min, "min")
ch <- prometheus.MustNewConstMetric(s.desc, prometheus.GaugeValue, s.max, "max")
mean := s.sum
if s.count > 0 {
mean /= float64(s.count)
}
ch <- prometheus.MustNewConstMetric(s.desc, prometheus.GaugeValue, mean, "mean")
s.min = math.Inf(1)
s.max = math.Inf(-1)
s.sum, s.count = 0, 0
}
func (s *liteSummary) Observe(x float64) {
s.mu.Lock()
defer s.mu.Unlock()
s.min = min(s.min, x)
s.max = max(s.max, x)
s.sum += x
s.count++
}
func pollVars() {
cmd := exec.Command("lifepo4wered-cli", "get") cmd := exec.Command("lifepo4wered-cli", "get")
out, err := cmd.Output() out, err := cmd.Output()
if err != nil { if err != nil {
log.Fatalf("Couldn't execute command: %v", err) log.Fatalf("Couldn't execute command: %v", err)
} }
pout := 1
labels := prometheus.Labels{"var": ""}
s := bufio.NewScanner(bytes.NewReader(out)) s := bufio.NewScanner(bytes.NewReader(out))
for s.Scan() { for s.Scan() {
// token space equals space number // token space equals space number
@ -45,20 +102,33 @@ func getVars() {
if _, err := fmt.Sscanf(s.Text(), "%s = %d", &name, &num); err != nil { if _, err := fmt.Sscanf(s.Text(), "%s = %d", &name, &num); err != nil {
log.Fatalf("Couldn't scan line: %v", err) log.Fatalf("Couldn't scan line: %v", err)
} }
lifepo4weredVars.With(prometheus.Labels{"var": name}).Set(float64(num)) labels["var"] = name
lifepo4weredVars.With(labels).Set(float64(num))
v, ok := lifepo4weredSummaries[name]
if !ok {
continue
}
v.Observe(float64(num))
switch name {
case "VOUT", "IOUT":
pout *= num
}
} }
if err := s.Err(); err != nil { if err := s.Err(); err != nil {
log.Fatalf("Couldn't scan output: %v", err) log.Fatalf("Couldn't scan output: %v", err)
} }
lifepo4weredPOut.Observe(float64(pout) / 1e3) // mV * mA = µW; 1000µW = 1mW.
} }
func main() { func main() {
flag.Parse() flag.Parse()
getVars() pollVars()
go func() { go func() {
for range time.Tick(15 * time.Second) { for range time.Tick(*pollInterval) {
getVars() pollVars()
} }
}() }()