mattermost-push-proxy-router/server.go
Felipe M. 8a4b11281d
feat: add Prometheus metrics endpoint
Expose /metrics with counters for routed requests, routing errors,
upstream outcomes, and upstream latency histograms. Instrument the
router and proxy forwarding path and document the new metrics.
2026-07-27 08:38:28 +02:00

87 lines
2.2 KiB
Go

package main
import (
"encoding/json"
"io"
"log"
"net/http"
)
func runServer() {
cfg, err := LoadConfig()
if err != nil {
log.Fatal(err)
}
metrics := NewMetrics(nil)
proxy := NewProxy(cfg, metrics)
mux := http.NewServeMux()
mux.HandleFunc("GET /", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
_, _ = w.Write([]byte("Mattermost Push Proxy Router\n"))
})
mux.HandleFunc("GET /version", func(w http.ResponseWriter, _ *http.Request) {
writeJSON(w, map[string]string{"version": version})
})
mux.HandleFunc("GET /health", handleHealth)
mux.Handle("GET /metrics", metrics.Handler())
mux.HandleFunc("POST /api/v1/send_push", func(w http.ResponseWriter, r *http.Request) {
handleRoute(w, r, proxy, cfg, "/api/v1/send_push")
})
mux.HandleFunc("POST /api/v1/ack", func(w http.ResponseWriter, r *http.Request) {
handleRoute(w, r, proxy, cfg, "/api/v1/ack")
})
addr := ":" + cfg.Port
log.Printf("Push proxy router listening on %s", addr)
for _, route := range cfg.Routes {
log.Printf("Route %v -> %s", route.Prefixes, route.URL)
}
if err := http.ListenAndServe(addr, mux); err != nil {
log.Fatal(err)
}
}
func handleRoute(w http.ResponseWriter, r *http.Request, proxy *Proxy, cfg Config, path string) {
body, err := io.ReadAll(r.Body)
if err != nil {
proxy.metrics.incRoutingError("read_body")
writePushError(w, "failed to read request body")
return
}
platform, err := extractPlatform(body)
if err != nil {
proxy.metrics.incRoutingError(routingErrorReason(err))
writePushError(w, err.Error())
return
}
backend, ok := cfg.BackendForPlatform(platform)
if !ok {
proxy.metrics.incRoutingError("unknown_platform")
writePushError(w, "no backend configured for platform="+platform)
return
}
proxy.metrics.incRequest(routePathLabel(path), platform)
log.Printf("route platform=%s path=%s backend=%s", platform, path, backend)
proxy.Forward(w, r, backend, path, body, platform)
}
func handleHealth(w http.ResponseWriter, _ *http.Request) {
writeJSON(w, map[string]string{"status": "ok"})
}
func writeJSON(w http.ResponseWriter, v any) {
w.Header().Set("Content-Type", "application/json")
enc := json.NewEncoder(w)
enc.SetEscapeHTML(false)
_ = enc.Encode(v)
}