From 1fdb18c298efef277a53dea67c507004ba77650a Mon Sep 17 00:00:00 2001 From: Ankur Srivastava Date: Wed, 8 Jul 2020 17:11:02 +0200 Subject: [PATCH] Chores: - Added CHANGELOG.md - Added a method to support NewWith(..) to pass servicename, namespace and subsystem - fixed failing tests Signed-off-by: Ankur Srivastava --- CHANGELOG.md | 6 ++++++ README.md | 9 ++++++-- middleware.go | 25 ++++++++++++++++----- middleware_test.go | 54 +++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fdccd1d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +## Change Log +--- + +## [2020-07-08] - 0.3.0 +### Enhancements: +- Support a new method to provide a namespace and a subsystem for the service diff --git a/README.md b/README.md index 8f76bb6..01efb4b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # fiberprometheus - + Prometheus middleware for gofiber. ![Release](https://img.shields.io/github/release/ansrivas/fiberprometheus.svg) @@ -32,10 +32,12 @@ import ( func main() { app := fiber.New() + // This here will appear as a label, one can also use + // fiberprometheus.NewWith(servicename, namespace, subsystem ) prometheus := fiberprometheus.New("my-service-name") prometheus.RegisterAt(app, "/metrics") app.Use(prometheus.Middleware) - + app.Get("/", func(c *fiber.Ctx) { c.Send("Hello World") }) @@ -47,3 +49,6 @@ func main() { app.Listen(3000) } ``` +### Result +- Hit the default url at http://localhost:3000 +- Navigate to http://localhost:3000/metrics diff --git a/middleware.go b/middleware.go index 715d4fc..25f81ba 100644 --- a/middleware.go +++ b/middleware.go @@ -19,18 +19,17 @@ type FiberPrometheus struct { defaultURL string } -// New creates a new instance of FiberPrometheus middleware -func New(servicename string) *FiberPrometheus { +func create(servicename, namespace, subsystem string) *FiberPrometheus { counter := promauto.NewCounterVec( prometheus.CounterOpts{ - Name: "http_requests_total", + Name: prometheus.BuildFQName(namespace, subsystem, "requests_total"), Help: "Count all http requests by status code, method and path.", ConstLabels: prometheus.Labels{"service": servicename}, }, []string{"status_code", "method", "path"}, ) histogram := promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "http_request_duration_seconds", + Name: prometheus.BuildFQName(namespace, subsystem, "request_duration_seconds"), Help: "Duration of all HTTP requests by status code, method and path.", ConstLabels: prometheus.Labels{"service": servicename}, }, @@ -38,7 +37,7 @@ func New(servicename string) *FiberPrometheus { ) gauge := promauto.NewGaugeVec(prometheus.GaugeOpts{ - Name: "http_requests_in_progress_total", + Name: prometheus.BuildFQName(namespace, subsystem, "requests_in_progress_total"), Help: "All the requests in progress", ConstLabels: prometheus.Labels{"service": servicename}, }, []string{"method", "path"}) @@ -51,6 +50,22 @@ func New(servicename string) *FiberPrometheus { } } +// New creates a new instance of FiberPrometheus middleware +// servicename is available as a const label +func New(servicename string) *FiberPrometheus { + return create(servicename, "http", "") +} + +// NewWith creates a new instance of FiberPrometheus middleware but with an ability +// to pass namespace and a custom subsystem +// Here servicename is created as a constant-label for the metrics +// Namespace, subsystem get prefixed to the metrics. +// For e.g namespace = "my_app", subsyste = "http" then then metrics would be +// my_app_http_requests_total{...,"service": servicename} +func NewWith(servicename, namespace, subsystem string) *FiberPrometheus { + return create(servicename, namespace, subsystem) +} + func (ps *FiberPrometheus) handler(c *fiber.Ctx) { p := fasthttpadaptor.NewFastHTTPHandler(promhttp.Handler()) p(c.Fasthttp) diff --git a/middleware_test.go b/middleware_test.go index 4c024e9..fb0468e 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -49,13 +49,57 @@ func TestMiddleware(t *testing.T) { defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) - if !strings.Contains(string(body), `http_requests_total{method="GET",path="/",service="test-service",status_code="200"} 1`) { - t.Fail() + got := string(body) + want := `http_requests_total{method="GET",path="/",service="test-service",status_code="200"} 1` + if !strings.Contains(got, want) { + t.Errorf("got %s; want %s", got, want) } - if !strings.Contains(string(body), `http_request_duration_seconds_count{method="GET",path="/",service="test-service",status_code="200"} 1`) { - t.Fail() + + want = `http_request_duration_seconds_count{method="GET",path="/",service="test-service",status_code="200"} 1` + if !strings.Contains(got, want) { + t.Errorf("got %s; want %s", got, want) + } + + want = `http_requests_in_progress_total{method="GET",path="/",service="test-service"} 0` + if !strings.Contains(got, want) { + t.Errorf("got %s; want %s", got, want) + } - if !strings.Contains(string(body), `http_requests_in_progress_total{method="GET",path="/",service="test-service"} 0`) { +} + +func TestMiddlewareWithServiceName(t *testing.T) { + app := fiber.New() + + prometheus := NewWith("test-service", "my_service", "http") + prometheus.RegisterAt(app, "/metrics") + app.Use(prometheus.Middleware) + app.Get("/", func(c *fiber.Ctx) { + c.Send("Hello World") + }) + req := httptest.NewRequest("GET", "/", nil) + resp, _ := app.Test(req) + if resp.StatusCode != 200 { t.Fail() } + + req = httptest.NewRequest("GET", "/metrics", nil) + resp, _ = app.Test(req) + defer resp.Body.Close() + + body, _ := ioutil.ReadAll(resp.Body) + got := string(body) + want := `my_service_http_requests_total{method="GET",path="/",service="test-service",status_code="200"} 1` + if !strings.Contains(got, want) { + t.Errorf("got %s; want %s", got, want) + } + + want = `my_service_http_request_duration_seconds_count{method="GET",path="/",service="test-service",status_code="200"} 1` + if !strings.Contains(got, want) { + t.Errorf("got %s; want %s", got, want) + } + + want = `my_service_http_requests_in_progress_total{method="GET",path="/",service="test-service"} 0` + if !strings.Contains(got, want) { + t.Errorf("got %s; want %s", got, want) + } }