go-http-metrics icon indicating copy to clipboard operation
go-http-metrics copied to clipboard

Middleware per route with the "chi" library

Open sneko opened this issue 3 years ago • 1 comments

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,

sneko avatar Feb 11 '22 15:02 sneko

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
}

slok avatar Feb 11 '22 17:02 slok