slok / go-http-metrics

Go modular http middleware to measure HTTP requests independent of metrics backend (with Prometheus and OpenCensus as backend implementations) and http framework/library
Apache License 2.0
383 stars 71 forks source link

Middleware per route with the "chi" library #113

Open sneko opened 2 years ago

sneko commented 2 years ago

Hi @slok ,

When using http directly I do see how to set a specific handlerID for each route: https://github.com/slok/go-http-metrics/blob/master/examples/custom/main.go#L54-L57

But in the chi example there is none: https://github.com/slok/go-http-metrics/blob/master/examples/chi/main.go

Since your library seems not able take as entry a HandleFunc to return a HandleFunc, I guess I have to manage it with a more complex way with chi. Something like:

    r := chi.NewRouter()

    recorder := metrics.NewRecorder(metrics.Config{
        Registry:        reg,
        Prefix:          "exampleapp",
        DurationBuckets: []float64{1, 2.5, 5, 10, 20, 40, 80, 160, 320, 640},
    })
    mdlw := middleware.New(middleware.Config{
        Recorder:      recorder,
        GroupedStatus: true,
    })

    // Specific route
    r.Group(func(r chi.Router) {
        r.Use(std.HandlerProvider("my_specific_route", mdlw))

        r.Post("/", aaaaaaa)
    })

    return r

Is there a more simple way than embedding all my registered routes with Post / Get / ... inside individual groups?

Thank you,

slok commented 2 years ago

Hi @sneko

EDIT: Nevermind Its the same in the end, So I'm afraid... no, there isn't a simpler way :/ sorry

I'm not a chi user myself, but this would work for you? (I used the example that go-http-metrics has):

package main

import (
    "log"
    "net/http"
    "os"
    "os/signal"
    "syscall"
    "time"

    "github.com/go-chi/chi"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    metrics "github.com/slok/go-http-metrics/metrics/prometheus"
    "github.com/slok/go-http-metrics/middleware"
    "github.com/slok/go-http-metrics/middleware/std"
)

const (
    srvAddr     = ":8080"
    metricsAddr = ":8081"
)

func main() {
    // Create our middleware.
    mdlw := middleware.New(middleware.Config{
        Recorder: metrics.NewRecorder(metrics.Config{}),
    })

    // Create our router with the metrics middleware.
    r := chi.NewRouter()

    // Add paths.
    r.Route("/", func(r chi.Router) {
        r.Use(std.HandlerProvider("root", mdlw))
        r.Get("/", func(w http.ResponseWriter, r *http.Request) {
            time.Sleep(200 * time.Millisecond)
            w.WriteHeader(http.StatusOK)
        })
    })

    r.Route("/test1", func(r chi.Router) {
        r.Use(std.HandlerProvider("custom-id-test1", mdlw))
        r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) })
    })
    r.Route("/test1/test2", func(r chi.Router) {
        r.Use(std.HandlerProvider("custom-id-test12", mdlw))
        r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusAccepted) })
    })
    r.Route("/test1/test4", func(r chi.Router) {
        r.Use(std.HandlerProvider("custom-id-test14", mdlw))
        r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNonAuthoritativeInfo) })
    })
    r.Route("/test2", func(r chi.Router) {
        r.Use(std.HandlerProvider("custom-id-test2", mdlw))
        r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) })
    })
    r.Route("/test3", func(r chi.Router) {
        r.Use(std.HandlerProvider("custom-id-test3", mdlw))
        r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusResetContent) })
    })

    // Serve our handler.
    go func() {
        log.Printf("server listening at %s", srvAddr)
        if err := http.ListenAndServe(srvAddr, r); err != nil {
            log.Panicf("error while serving: %s", err)
        }
    }()

    // Serve our metrics.
    go func() {
        log.Printf("metrics listening at %s", metricsAddr)
        if err := http.ListenAndServe(metricsAddr, promhttp.Handler()); err != nil {
            log.Panicf("error while serving metrics: %s", err)
        }
    }()

    // Wait until some signal is captured.
    sigC := make(chan os.Signal, 1)
    signal.Notify(sigC, syscall.SIGTERM, syscall.SIGINT)
    <-sigC
}