135 lines
3.3 KiB
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"`
|
|
Offset float32 `json:"offset"`
|
|
}
|
|
|
|
type metrics struct {
|
|
buffering *prometheus.CounterVec
|
|
recovery *prometheus.CounterVec
|
|
qualityUp *prometheus.CounterVec
|
|
qualityDown *prometheus.CounterVec
|
|
}
|
|
|
|
const (
|
|
typeBuffering = "buffering"
|
|
typeRecovery = "recovery"
|
|
typeQualitySwitch = "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.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 typeBuffering:
|
|
m.buffering.WithLabelValues(v.Slug).Inc()
|
|
case typeRecovery:
|
|
m.recovery.WithLabelValues(v.Slug).Inc()
|
|
case typeQualitySwitch:
|
|
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
|
|
}
|