From 6b9fb7bc453168f78e8c6099d297d4676239c34d Mon Sep 17 00:00:00 2001 From: Garionion Date: Thu, 28 Dec 2023 21:32:48 +0100 Subject: [PATCH] first commit --- flake.nix | 13 +++++ go.mod | 36 ++++++++++++++ go.sum | 72 ++++++++++++++++++++++++++++ main.go | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++ package.nix | 35 ++++++++++++++ 5 files changed, 289 insertions(+) create mode 100644 flake.nix create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 package.nix diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..b744f32 --- /dev/null +++ b/flake.nix @@ -0,0 +1,13 @@ +{ + description = "voc-telemetry"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem + (system: + let pkgs = nixpkgs.legacyPackages.${system}; in + { + #devShell = import ./default.nix { inherit pkgs; }; + defaultPackage = import ./package.nix { inherit pkgs;}; + } + ); +} \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5120c07 --- /dev/null +++ b/go.mod @@ -0,0 +1,36 @@ +module voc-telemetry + +go 1.21 + +require ( + github.com/labstack/echo v3.3.10+incompatible + github.com/labstack/echo-contrib v0.15.0 + github.com/labstack/echo/v4 v4.10.2 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/labstack/gommon v0.4.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.40.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.3.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a984ee8 --- /dev/null +++ b/go.sum @@ -0,0 +1,72 @@ +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg= +github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= +github.com/labstack/echo-contrib v0.15.0 h1:9K+oRU265y4Mu9zpRDv3X+DGTqUALY6oRHCSZZKCRVU= +github.com/labstack/echo-contrib v0.15.0/go.mod h1:lei+qt5CLB4oa7VHTE0yEfQSEB9XTJI1LUqko9UWvo4= +github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= +github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.40.0 h1:Afz7EVRqGg2Mqqf4JuF9vdvp1pi220m55Pi9T2JnO4Q= +github.com/prometheus/common v0.40.0/go.mod h1:L65ZJPSmfn/UBWLQIHV7dBrKFidB/wPlF1y5TlSt9OE= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= diff --git a/main.go b/main.go new file mode 100644 index 0000000..937f768 --- /dev/null +++ b/main.go @@ -0,0 +1,133 @@ +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"` +} + +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.slug == "up" { + 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 +} diff --git a/package.nix b/package.nix new file mode 100644 index 0000000..c520305 --- /dev/null +++ b/package.nix @@ -0,0 +1,35 @@ +{ pkgs ? import { } }: +with pkgs; +let + version = "0.0.1"; + deps = [ ]; + nativeDeps = [ ]; +in +pkgs.buildGo119Module { + pname = "voc-telemetry"; + inherit version; + src = ./.; + buildInputs = [ + stdenv + ] ++deps; + nativeBuildInputs = [ + musl + ] ++nativeDeps; + tags = [ ]; + + CGO_ENABLED = 0; + ldflags = [ + "-s" "-w" + "-linkmode external" + "-extldflags '-static -L${musl}/lib'" + ]; + + allowGoReference = false; + #vendorSha256 = lib.fakeSha256; + vendorSha256 = "sha256-YFKyN+oV9MrjcvfehsGKgvAPvnHlOBGpSQpVdrOvUog="; + + meta = { + description = "TBA"; + homepage = "https://git.entr0py.de/garionion/voc-telemetry"; + }; +} \ No newline at end of file