Files
mqqt-scrubber/internal/health/server.go
T

95 lines
2.1 KiB
Go

package health
import (
"context"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"strings"
"time"
)
type Server struct {
address string
server *http.Server
metrics func() any
}
func NewServer(address string, metrics func() any) *Server {
if address == "" {
return nil
}
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
})
mux.HandleFunc("/readyz", func(w http.ResponseWriter, _ *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{"status": "ready"})
})
mux.HandleFunc("/metrics", func(w http.ResponseWriter, _ *http.Request) {
if metrics == nil {
writeJSON(w, http.StatusOK, map[string]string{"status": "metrics_unavailable"})
return
}
w.Header().Set("Content-Type", "text/plain; version=0.0.4")
_, _ = w.Write([]byte(formatMetrics(metrics())))
})
return &Server{
address: address,
metrics: metrics,
server: &http.Server{
Addr: address,
Handler: mux,
ReadHeaderTimeout: 5 * time.Second,
},
}
}
func (server *Server) Start() {
if server == nil {
return
}
go func() {
slog.Info("health server started", "address", server.address)
if err := server.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
slog.Error("health server stopped with error", "error", err)
}
}()
}
func (server *Server) Shutdown(ctx context.Context) error {
if server == nil {
return nil
}
return server.server.Shutdown(ctx)
}
func writeJSON(w http.ResponseWriter, status int, value any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(value)
}
func formatMetrics(snapshot any) string {
encoded, err := json.Marshal(snapshot)
if err != nil {
return "mqqt_scrubber_metrics_encode_error 1\n"
}
var fields map[string]uint64
if err := json.Unmarshal(encoded, &fields); err != nil {
return "mqqt_scrubber_metrics_decode_error 1\n"
}
var builder strings.Builder
for key, value := range fields {
builder.WriteString(fmt.Sprintf("mqqt_scrubber_%s %d\n", key, value))
}
return builder.String()
}