From 32c05716b6e6a690181642ed26ebbf838aa68ca1 Mon Sep 17 00:00:00 2001 From: Toshinori Sugita Date: Sat, 13 Aug 2022 12:45:27 +0900 Subject: [PATCH 1/7] Add bucket conf --- middleware.go | 30 +++++++++++++++++--- middleware_test.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/middleware.go b/middleware.go index 24e44d5..cafe6e7 100644 --- a/middleware.go +++ b/middleware.go @@ -2,6 +2,9 @@ package chiprometheus import ( "net/http" + "os" + "strconv" + "strings" "time" "github.com/go-chi/chi/v5" @@ -10,12 +13,14 @@ import ( ) var ( - defaultBuckets = []float64{300, 1200, 5000} + bucketsConfig = []float64{300, 1200, 5000} ) const ( - RequestsCollectorName = "chi_requests_total" - LatencyCollectorName = "chi_request_duration_milliseconds" + // EnvChiPrometheusLatencyBuckets represents an environment variable, which is formatted like "100,200,300,400" as string + EnvChiPrometheusLatencyBuckets = "CHI_PROMETHEUS_LATENCY_BUCKETS" + RequestsCollectorName = "chi_requests_total" + LatencyCollectorName = "chi_request_duration_milliseconds" ) // Middleware is a handler that exposes prometheus metrics for the number of requests, @@ -25,8 +30,25 @@ type Middleware struct { latency *prometheus.HistogramVec } +func setBucket() { + var buckets []float64 + conf, ok := os.LookupEnv(EnvChiPrometheusLatencyBuckets) + if ok { + for _, v := range strings.Split(conf, ",") { + f64v, err := strconv.ParseFloat(v, 64) + if err != nil { + panic(err) + } + buckets = append(buckets, f64v) + } + bucketsConfig = buckets + } +} + // New returns a new prometheus middleware for the provided service name. func New(name string) *Middleware { + setBucket() + var m Middleware m.requests = prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -39,7 +61,7 @@ func New(name string) *Middleware { Name: LatencyCollectorName, Help: "Time spent on the request partitioned by status code, method and HTTP path.", ConstLabels: prometheus.Labels{"service": name}, - Buckets: defaultBuckets, + Buckets: bucketsConfig, }, []string{"code", "method", "path"}) return &m diff --git a/middleware_test.go b/middleware_test.go index 7ef43a7..bdb4f20 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -5,6 +5,7 @@ import ( "net/http" "net/http/httptest" "net/url" + "os" "strings" "testing" "time" @@ -175,3 +176,73 @@ func TestMiddleware_HandlerWithCustomRegistry(t *testing.T) { t.Errorf("body should contain Go runtime metrics from GoCollector") } } + +func TestMiddleware_HandlerWithBucketEnv(t *testing.T) { + key := chiprometheus.EnvChiPrometheusLatencyBuckets + if err := os.Setenv(key, "101,201"); err != nil { + t.Fatalf("failed to set %s", key) + } + t.Cleanup(func() { _ = os.Unsetenv(key) }) + + r := chi.NewRouter() + m := chiprometheus.New("test") + m.MustRegisterDefault() + t.Cleanup(func() { + for _, c := range m.Collectors() { + prometheus.Unregister(c) + } + }) + r.Use(m.Handler) + r.Handle("/metrics", promhttp.Handler()) + r.Get("/healthz", testHandler) + + paths := [][]string{ + {"healthz"}, + {"metrics"}, + } + rec := httptest.NewRecorder() + for _, p := range paths { + u, err := url.JoinPath(testHost, p...) + if err != nil { + t.Error(err) + } + req, err := http.NewRequest("GET", u, nil) + if err != nil { + t.Error(err) + } + r.ServeHTTP(rec, req) + } + body := rec.Body.String() + + if !strings.Contains(body, chiprometheus.RequestsCollectorName) { + t.Errorf("body should contain request total entry '%s'", chiprometheus.RequestsCollectorName) + } + if !strings.Contains(body, chiprometheus.LatencyCollectorName) { + t.Errorf("body should contain request duration entry '%s'", chiprometheus.LatencyCollectorName) + } + + healthzCount101 := `path="/healthz",service="test",le="101"` + healthzCount201 := `path="/healthz",service="test",le="201"` + healthzCountInf := `path="/healthz",service="test",le="+Inf"` + healthzCount300 := `path="/healthz",service="test",le="300"` + healthzCount1200 := `path="/healthz",service="test",le="1200"` + healthzCount5000 := `path="/healthz",service="test",le="5000"` + if !strings.Contains(body, healthzCount101) { + t.Errorf("body should contain healthz count summary '%s'", healthzCount101) + } + if !strings.Contains(body, healthzCount201) { + t.Errorf("body should contain healthz count summary '%s'", healthzCount201) + } + if !strings.Contains(body, healthzCountInf) { + t.Errorf("body should contain healthz count summary '%s'", healthzCountInf) + } + if strings.Contains(body, healthzCount300) { + t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount300) + } + if strings.Contains(body, healthzCount1200) { + t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount1200) + } + if strings.Contains(body, healthzCount5000) { + t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount5000) + } +} From 37d9ae6fca3b7766a0d661d3a8a4928aec5aadda Mon Sep 17 00:00:00 2001 From: Toshinori Sugita Date: Sat, 13 Aug 2022 12:57:22 +0900 Subject: [PATCH 2/7] Test invalid env --- middleware_test.go | 146 ++++++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 60 deletions(-) diff --git a/middleware_test.go b/middleware_test.go index bdb4f20..a83fb74 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -21,7 +21,7 @@ import ( const testHost = "http://localhost" func TestMiddleware_MustRegisterDefault(t *testing.T) { - t.Run("must panic without collectors", func(t *testing.T) { + t.Run("without collectors", func(t *testing.T) { defer func() { if r := recover(); r == nil { t.Errorf("must have panicked") @@ -31,7 +31,7 @@ func TestMiddleware_MustRegisterDefault(t *testing.T) { m.MustRegisterDefault() }) - t.Run("must not panic with collectors", func(t *testing.T) { + t.Run("with collectors", func(t *testing.T) { defer func() { if r := recover(); r != nil { t.Errorf("must not have panicked") @@ -179,70 +179,96 @@ func TestMiddleware_HandlerWithCustomRegistry(t *testing.T) { func TestMiddleware_HandlerWithBucketEnv(t *testing.T) { key := chiprometheus.EnvChiPrometheusLatencyBuckets - if err := os.Setenv(key, "101,201"); err != nil { - t.Fatalf("failed to set %s", key) - } - t.Cleanup(func() { _ = os.Unsetenv(key) }) - r := chi.NewRouter() - m := chiprometheus.New("test") - m.MustRegisterDefault() - t.Cleanup(func() { - for _, c := range m.Collectors() { - prometheus.Unregister(c) + t.Run("with invalid env", func(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("must have panicked") + } + }() + if err := os.Setenv(key, "invalid value"); err != nil { + t.Fatalf("failed to set %s", key) } + t.Cleanup(func() { _ = os.Unsetenv(key) }) + chiprometheus.New("test") }) - r.Use(m.Handler) - r.Handle("/metrics", promhttp.Handler()) - r.Get("/healthz", testHandler) - paths := [][]string{ - {"healthz"}, - {"metrics"}, - } - rec := httptest.NewRecorder() - for _, p := range paths { - u, err := url.JoinPath(testHost, p...) - if err != nil { - t.Error(err) + t.Run("with valid env", func(t *testing.T) { + defer func() { + if r := recover(); r != nil { + t.Errorf("must not have panicked") + } + }() + if err := os.Setenv(key, "invalid value"); err != nil { + t.Fatalf("failed to set %s", key) } - req, err := http.NewRequest("GET", u, nil) - if err != nil { - t.Error(err) + t.Cleanup(func() { _ = os.Unsetenv(key) }) + + if err := os.Setenv(key, "101,201"); err != nil { + t.Fatalf("failed to set %s", key) } - r.ServeHTTP(rec, req) - } - body := rec.Body.String() + t.Cleanup(func() { _ = os.Unsetenv(key) }) - if !strings.Contains(body, chiprometheus.RequestsCollectorName) { - t.Errorf("body should contain request total entry '%s'", chiprometheus.RequestsCollectorName) - } - if !strings.Contains(body, chiprometheus.LatencyCollectorName) { - t.Errorf("body should contain request duration entry '%s'", chiprometheus.LatencyCollectorName) - } + r := chi.NewRouter() + m := chiprometheus.New("test") + m.MustRegisterDefault() + t.Cleanup(func() { + for _, c := range m.Collectors() { + prometheus.Unregister(c) + } + }) + r.Use(m.Handler) + r.Handle("/metrics", promhttp.Handler()) + r.Get("/healthz", testHandler) - healthzCount101 := `path="/healthz",service="test",le="101"` - healthzCount201 := `path="/healthz",service="test",le="201"` - healthzCountInf := `path="/healthz",service="test",le="+Inf"` - healthzCount300 := `path="/healthz",service="test",le="300"` - healthzCount1200 := `path="/healthz",service="test",le="1200"` - healthzCount5000 := `path="/healthz",service="test",le="5000"` - if !strings.Contains(body, healthzCount101) { - t.Errorf("body should contain healthz count summary '%s'", healthzCount101) - } - if !strings.Contains(body, healthzCount201) { - t.Errorf("body should contain healthz count summary '%s'", healthzCount201) - } - if !strings.Contains(body, healthzCountInf) { - t.Errorf("body should contain healthz count summary '%s'", healthzCountInf) - } - if strings.Contains(body, healthzCount300) { - t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount300) - } - if strings.Contains(body, healthzCount1200) { - t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount1200) - } - if strings.Contains(body, healthzCount5000) { - t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount5000) - } + paths := [][]string{ + {"healthz"}, + {"metrics"}, + } + rec := httptest.NewRecorder() + for _, p := range paths { + u, err := url.JoinPath(testHost, p...) + if err != nil { + t.Error(err) + } + req, err := http.NewRequest("GET", u, nil) + if err != nil { + t.Error(err) + } + r.ServeHTTP(rec, req) + } + body := rec.Body.String() + + if !strings.Contains(body, chiprometheus.RequestsCollectorName) { + t.Errorf("body should contain request total entry '%s'", chiprometheus.RequestsCollectorName) + } + if !strings.Contains(body, chiprometheus.LatencyCollectorName) { + t.Errorf("body should contain request duration entry '%s'", chiprometheus.LatencyCollectorName) + } + + healthzCount101 := `path="/healthz",service="test",le="101"` + healthzCount201 := `path="/healthz",service="test",le="201"` + healthzCountInf := `path="/healthz",service="test",le="+Inf"` + healthzCount300 := `path="/healthz",service="test",le="300"` + healthzCount1200 := `path="/healthz",service="test",le="1200"` + healthzCount5000 := `path="/healthz",service="test",le="5000"` + if !strings.Contains(body, healthzCount101) { + t.Errorf("body should contain healthz count summary '%s'", healthzCount101) + } + if !strings.Contains(body, healthzCount201) { + t.Errorf("body should contain healthz count summary '%s'", healthzCount201) + } + if !strings.Contains(body, healthzCountInf) { + t.Errorf("body should contain healthz count summary '%s'", healthzCountInf) + } + if strings.Contains(body, healthzCount300) { + t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount300) + } + if strings.Contains(body, healthzCount1200) { + t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount1200) + } + if strings.Contains(body, healthzCount5000) { + t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount5000) + } + }) } From 67c3ddfc9f1c61714ae0e6cedc9cdebf8d104dbe Mon Sep 17 00:00:00 2001 From: Toshinori Sugita Date: Sat, 13 Aug 2022 13:10:33 +0900 Subject: [PATCH 3/7] Refactor TestMiddleware_HandlerWithBucketEnv --- middleware_test.go | 57 +++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/middleware_test.go b/middleware_test.go index a83fb74..4196b39 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -199,10 +199,19 @@ func TestMiddleware_HandlerWithBucketEnv(t *testing.T) { t.Errorf("must not have panicked") } }() - if err := os.Setenv(key, "invalid value"); err != nil { - t.Fatalf("failed to set %s", key) + + tests := map[string]struct { + body string + want bool + }{ + "le 101": {`path="/healthz",service="test",le="101"`, true}, + "le 201": {`path="/healthz",service="test",le="201"`, true}, + "le +Inf": {`path="/healthz",service="test",le="+Inf"`, true}, + // default values should be overwritten + "le 300": {`path="/healthz",service="test",le="300"`, false}, + "le 1200": {`path="/healthz",service="test",le="1200"`, false}, + "le 5000": {`path="/healthz",service="test",le="1200"`, false}, } - t.Cleanup(func() { _ = os.Unsetenv(key) }) if err := os.Setenv(key, "101,201"); err != nil { t.Fatalf("failed to set %s", key) @@ -237,38 +246,18 @@ func TestMiddleware_HandlerWithBucketEnv(t *testing.T) { } r.ServeHTTP(rec, req) } - body := rec.Body.String() - - if !strings.Contains(body, chiprometheus.RequestsCollectorName) { - t.Errorf("body should contain request total entry '%s'", chiprometheus.RequestsCollectorName) - } - if !strings.Contains(body, chiprometheus.LatencyCollectorName) { - t.Errorf("body should contain request duration entry '%s'", chiprometheus.LatencyCollectorName) - } + got := rec.Body.String() - healthzCount101 := `path="/healthz",service="test",le="101"` - healthzCount201 := `path="/healthz",service="test",le="201"` - healthzCountInf := `path="/healthz",service="test",le="+Inf"` - healthzCount300 := `path="/healthz",service="test",le="300"` - healthzCount1200 := `path="/healthz",service="test",le="1200"` - healthzCount5000 := `path="/healthz",service="test",le="5000"` - if !strings.Contains(body, healthzCount101) { - t.Errorf("body should contain healthz count summary '%s'", healthzCount101) - } - if !strings.Contains(body, healthzCount201) { - t.Errorf("body should contain healthz count summary '%s'", healthzCount201) - } - if !strings.Contains(body, healthzCountInf) { - t.Errorf("body should contain healthz count summary '%s'", healthzCountInf) - } - if strings.Contains(body, healthzCount300) { - t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount300) - } - if strings.Contains(body, healthzCount1200) { - t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount1200) - } - if strings.Contains(body, healthzCount5000) { - t.Errorf("body should NOT contain healthz count summary '%s'", healthzCount5000) + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + if tt.want && !strings.Contains(got, tt.body) { + t.Fatalf("body should contain %s", tt.body) + } else if !tt.want && strings.Contains(got, tt.body) { + t.Fatalf("body should NOT contain %s", tt.body) + } + }) } }) } From c8f95d859e5003a136b82cdcbf590900c09c4c37 Mon Sep 17 00:00:00 2001 From: Toshinori Sugita Date: Sat, 13 Aug 2022 13:18:42 +0900 Subject: [PATCH 4/7] Refactor TestMiddleware_Handler --- middleware_test.go | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/middleware_test.go b/middleware_test.go index 4196b39..20e8525 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -62,6 +62,17 @@ func testHandler(w http.ResponseWriter, r *http.Request) { } func TestMiddleware_Handler(t *testing.T) { + tests := map[string]struct { + body string + want bool + }{ + "request header": {chiprometheus.RequestsCollectorName, true}, + "latency header": {chiprometheus.LatencyCollectorName, true}, + "bob": {`chi_request_duration_milliseconds_count{code="OK",method="GET",path="/users/bob",service="test"} 1`, false}, + "alice": {`chi_request_duration_milliseconds_count{code="OK",method="GET",path="/users/alice",service="test"} 1`, false}, + "path variable": {`chi_request_duration_milliseconds_count{code="OK",method="GET",path="/users/{firstName}",service="test"} 2`, true}, + } + r := chi.NewRouter() m := chiprometheus.New("test") m.MustRegisterDefault() @@ -93,30 +104,18 @@ func TestMiddleware_Handler(t *testing.T) { } r.ServeHTTP(rec, req) } - body := rec.Body.String() + got := rec.Body.String() - if !strings.Contains(body, chiprometheus.RequestsCollectorName) { - t.Errorf("body should contain request total entry '%s'", chiprometheus.RequestsCollectorName) - } - if !strings.Contains(body, chiprometheus.LatencyCollectorName) { - t.Errorf("body should contain request duration entry '%s'", chiprometheus.LatencyCollectorName) - } - - healthzCount := `chi_request_duration_milliseconds_count{code="OK",method="GET",path="/healthz",service="test"} 1` - bobCount := `chi_request_duration_milliseconds_count{code="OK",method="GET",path="/users/bob",service="test"} 1` - aliceCount := `chi_request_duration_milliseconds_count{code="OK",method="GET",path="/users/alice",service="test"} 1` - aggregatedCount := `chi_request_duration_milliseconds_count{code="OK",method="GET",path="/users/{firstName}",service="test"} 2` - if !strings.Contains(body, healthzCount) { - t.Errorf("body should contain healthz count summary '%s'", healthzCount) - } - if strings.Contains(body, bobCount) { - t.Errorf("body should NOT contain Bob count summary '%s'", bobCount) - } - if strings.Contains(body, aliceCount) { - t.Errorf("body should NOT contain Alice count summary '%s'", aliceCount) - } - if !strings.Contains(body, aggregatedCount) { - t.Errorf("body should contain first name count summary '%s'", aggregatedCount) + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + if tt.want && !strings.Contains(got, tt.body) { + t.Fatalf("body should contain %s", tt.body) + } else if !tt.want && strings.Contains(got, tt.body) { + t.Fatalf("body should NOT contain %s", tt.body) + } + }) } } From a201a95eebe69b81afd6cedfc4ac7a209bcdc9fe Mon Sep 17 00:00:00 2001 From: Toshinori Sugita Date: Sat, 13 Aug 2022 13:57:01 +0900 Subject: [PATCH 5/7] Refactor TestMiddleware_HandlerWithCustomRegistry --- middleware_test.go | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/middleware_test.go b/middleware_test.go index 20e8525..eedc942 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -57,7 +57,7 @@ func TestMiddleware_Collectors(t *testing.T) { } func testHandler(w http.ResponseWriter, r *http.Request) { - time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond) + time.Sleep(time.Duration(rand.Intn(5)) * time.Millisecond) w.WriteHeader(http.StatusOK) } @@ -120,6 +120,15 @@ func TestMiddleware_Handler(t *testing.T) { } func TestMiddleware_HandlerWithCustomRegistry(t *testing.T) { + tests := map[string]struct { + want string + }{ + "request header": {chiprometheus.RequestsCollectorName}, + "latency header": {chiprometheus.LatencyCollectorName}, + "bob": {"promhttp_metric_handler_requests_total"}, + "alice": {"go_goroutines"}, + } + r := chi.NewRouter() reg := prometheus.NewRegistry() if err := reg.Register(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})); err != nil { @@ -138,7 +147,6 @@ func TestMiddleware_HandlerWithCustomRegistry(t *testing.T) { promh := promhttp.InstrumentMetricHandler( reg, promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), ) - r.Use(m.Handler) r.Handle("/metrics", promh) r.Get("/healthz", testHandler) @@ -159,20 +167,16 @@ func TestMiddleware_HandlerWithCustomRegistry(t *testing.T) { } r.ServeHTTP(rec, req) } - body := rec.Body.String() - - if !strings.Contains(body, chiprometheus.RequestsCollectorName) { - t.Errorf("body should contain request total entry '%s'", chiprometheus.RequestsCollectorName) - } - if !strings.Contains(body, chiprometheus.LatencyCollectorName) { - t.Errorf("body should contain request duration entry '%s'", chiprometheus.LatencyCollectorName) - } + got := rec.Body.String() - if !strings.Contains(body, "promhttp_metric_handler_requests_total") { - t.Error("body should contain promhttp_metric_handler_requests_total from ProcessCollector") - } - if !strings.Contains(body, "go_goroutines") { - t.Errorf("body should contain Go runtime metrics from GoCollector") + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + if !strings.Contains(got, tt.want) { + t.Fatalf("body should contain %s", tt.want) + } + }) } } From b8070ee649ad037f6da7ced6b7a56a3071d872a8 Mon Sep 17 00:00:00 2001 From: Toshinori Sugita Date: Sat, 13 Aug 2022 14:03:39 +0900 Subject: [PATCH 6/7] Refactor makeRequest --- middleware_test.go | 62 +++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/middleware_test.go b/middleware_test.go index eedc942..c203c91 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -61,6 +61,23 @@ func testHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } +func makeRequest(t *testing.T, r *chi.Mux, paths [][]string) string { + t.Helper() + rec := httptest.NewRecorder() + for _, p := range paths { + u, err := url.JoinPath(testHost, p...) + if err != nil { + t.Error(err) + } + req, err := http.NewRequest("GET", u, nil) + if err != nil { + t.Error(err) + } + r.ServeHTTP(rec, req) + } + return rec.Body.String() +} + func TestMiddleware_Handler(t *testing.T) { tests := map[string]struct { body string @@ -85,26 +102,13 @@ func TestMiddleware_Handler(t *testing.T) { r.Handle("/metrics", promhttp.Handler()) r.Get("/healthz", testHandler) r.Get("/users/{firstName}", testHandler) - paths := [][]string{ {"healthz"}, {"users", "bob"}, {"users", "alice"}, {"metrics"}, } - rec := httptest.NewRecorder() - for _, p := range paths { - u, err := url.JoinPath(testHost, p...) - if err != nil { - t.Error(err) - } - req, err := http.NewRequest("GET", u, nil) - if err != nil { - t.Error(err) - } - r.ServeHTTP(rec, req) - } - got := rec.Body.String() + got := makeRequest(t, r, paths) for name, tt := range tests { tt := tt @@ -150,24 +154,11 @@ func TestMiddleware_HandlerWithCustomRegistry(t *testing.T) { r.Use(m.Handler) r.Handle("/metrics", promh) r.Get("/healthz", testHandler) - paths := [][]string{ {"healthz"}, {"metrics"}, } - rec := httptest.NewRecorder() - for _, p := range paths { - u, err := url.JoinPath(testHost, p...) - if err != nil { - t.Error(err) - } - req, err := http.NewRequest("GET", u, nil) - if err != nil { - t.Error(err) - } - r.ServeHTTP(rec, req) - } - got := rec.Body.String() + got := makeRequest(t, r, paths) for name, tt := range tests { tt := tt @@ -232,24 +223,11 @@ func TestMiddleware_HandlerWithBucketEnv(t *testing.T) { r.Use(m.Handler) r.Handle("/metrics", promhttp.Handler()) r.Get("/healthz", testHandler) - paths := [][]string{ {"healthz"}, {"metrics"}, } - rec := httptest.NewRecorder() - for _, p := range paths { - u, err := url.JoinPath(testHost, p...) - if err != nil { - t.Error(err) - } - req, err := http.NewRequest("GET", u, nil) - if err != nil { - t.Error(err) - } - r.ServeHTTP(rec, req) - } - got := rec.Body.String() + got := makeRequest(t, r, paths) for name, tt := range tests { tt := tt From faef36d344de4210029218a065e64b25c88ac8e7 Mon Sep 17 00:00:00 2001 From: Toshinori Sugita Date: Sat, 13 Aug 2022 14:13:21 +0900 Subject: [PATCH 7/7] Add config to readme --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 9e1bbf8..fbf5573 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,17 @@ chi-prometheus is used as a middleware. It also supports both a default registry r.Get("/healthz", [YOUR HandlerFunc]) ``` +### Configuration + +Latency histogram bucket is configurable with `CHI_PROMETHEUS_LATENCY_BUCKETS`. Default values are `300, 1200, 5000` (milliseconds). + +You can override them as follows; + +```shell +# comma separated string value +CHI_PROMETHEUS_LATENCY_BUCKETS="100,200,300,400" +``` + ## Install ```console