voc-telemetry/main.go

135 lines
3.3 KiB
Go

package main
import (
"flag"
"fmt"
"github.com/labstack/echo-contrib/echoprometheus"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/prometheus/client_golang/prometheus"
"net/http"
)
type telemetry struct {
slug string `json:"slug"`
eventType string `json:"type"`
qualityChangeUp bool `json:"isUp"`
}
type metrics struct {
buffering *prometheus.CounterVec
recovery *prometheus.CounterVec
qualityUp *prometheus.CounterVec
qualityDown *prometheus.CounterVec
}
const (
type_buffering = "buffering"
type_recovery = "recovery"
type_quality_switch = "quality_switch"
)
func main() {
m, err := initMetrics()
if err != nil {
panic(err)
}
listenAddress := ":2342"
flag.StringVar(&listenAddress, "listen", listenAddress, "address to listen on")
flag.Parse()
e := echo.New()
e.Use(middleware.CORS())
e.Use(middleware.Decompress())
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.Use(middleware.BodyLimit("64K"))
e.Use(middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(5)))
e.Use(echoprometheus.NewMiddleware("http"))
e.GET("/metrics", echoprometheus.NewHandler())
e.POST("/", telemetryHandler(m))
e.Logger.Fatal(e.Start(listenAddress))
}
func telemetryHandler(m metrics) echo.HandlerFunc {
return func(c echo.Context) error {
t := new([]telemetry)
if err := c.Bind(t); err != nil {
return c.String(http.StatusBadRequest, "bad request")
}
for _, v := range *t {
switch v.eventType {
case type_buffering:
m.buffering.WithLabelValues(v.slug).Inc()
case type_recovery:
m.recovery.WithLabelValues(v.slug).Inc()
case type_quality_switch:
if v.qualityChangeUp {
m.qualityUp.WithLabelValues(v.slug).Inc()
} else {
m.qualityDown.WithLabelValues(v.slug).Inc()
}
}
}
return c.NoContent(http.StatusOK)
}
}
func initMetrics() (metrics, error) {
metricBuffering := prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "telemetry",
Subsystem: "player",
Name: "buffering",
}, []string{"slug"})
metricRecovery := prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "telemetry",
Subsystem: "player",
Name: "recovery",
}, []string{"slug"})
metricQualitySwitchUp := prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "telemetry",
Subsystem: "player",
Name: "quality_switch_up",
}, []string{"slug"})
metricQualitySwitchDown := prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "telemetry",
Subsystem: "player",
Name: "quality_switch_down",
}, []string{"slug"})
if err := prometheus.Register(metricBuffering); err != nil {
return metrics{}, fmt.Errorf("failed to register buffering metric: %w", err)
}
if err := prometheus.Register(metricRecovery); err != nil {
return metrics{}, fmt.Errorf("failed to register recovery metric: %w", err)
}
if err := prometheus.Register(metricQualitySwitchUp); err != nil {
return metrics{}, fmt.Errorf("failed to register quality_switch_up metric: %w", err)
}
if err := prometheus.Register(metricQualitySwitchDown); err != nil {
return metrics{}, fmt.Errorf("failed to register quality_switch_down metric: %w", err)
}
return metrics{
buffering: metricBuffering,
recovery: metricRecovery,
qualityUp: metricQualitySwitchUp,
qualityDown: metricQualitySwitchDown,
}, nil
}