ansrivas / fiberprometheus

prometheus middleware for Fiber

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

incorrect path when using groups

FedeBev opened this issue · comments

Hi there,
thanks for this work!

When using a.Group the path is not correct.

With the following app

app := fiber.New()

prometheus := fiberprometheus.NewWithLabels(labels, strings.ReplaceAll(Component, "-", "_"), "http")
prometheus.RegisterAt(app, "/metrics")
app.Use(prometheus.Middleware)

public := app.Group("/public")

public.Get("/somepath", func(c *fiber.Ctx) error {
   ...
})

The following metrics are created when calling GET /public/somepath

lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="2e-09"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="5e-09"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="1e-08"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="2e-08"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="5e-08"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="1e-07"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="2e-07"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="5e-07"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="1e-06"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="2e-06"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="5e-06"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="1e-05"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="2e-05"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="5e-05"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.0001"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.0002"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.0005"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.001"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.002"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.005"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.01"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.02"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.05"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.1"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.2"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.5"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="1"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="2"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="5"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="10"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="15"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="20"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="30"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="+Inf"} 1
lessons_cdn_http_request_duration_seconds_sum{build="development",method="GET",path="/public",status_code="401",version="development"} 8.253e-05
lessons_cdn_http_request_duration_seconds_count{build="development",method="GET",path="/public",status_code="401",version="development"} 1

I'd expect to see /public/somepath in the path label.

Thanks!

Hey @FedeBev, thanks for reporting this.
So, in your example I just moved the middleware mount a bit later, please try and see if this solves your issue.

	prometheus := fiberprometheus.New("my-service-name")

	public := app.Group("/public")  // Here declared the Group before calling RegisterAt and app.Use

	prometheus.RegisterAt(app, "/metrics")
	app.Use(prometheus.Middleware)

	public.Get("/somepath", func(c *fiber.Ctx) error {
		return c.SendString("Hello World from somepath")
	})

And corresponding to that, I can see the following:

http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="1e-09"} 0
http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="2e-09"} 0
http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="5e-09"} 0
http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="1e-08"} 0
http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="2e-08"} 0
http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="5e-08"} 0
http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="1e-07"} 0
http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="2e-07"} 0
http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="5e-07"} 0
http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="1e-06"} 0
http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="2e-06"} 0
http_request_duration_seconds_bucket{method="GET",path="/public/somepath",service="my-service-name",status_code="200",le="5e-06"} ```

Interesting, I tried your suggestion but I'm still seeing the same

app := fiber.New()

public := app.Group("/public")
admin := app.Group("/admin")

prometheus := fiberprometheus.NewWithLabels(labels, strings.ReplaceAll(Component, "-", "_"), "http")
prometheus.RegisterAt(app, "/metrics")

app.Use(prometheus.Middleware)

public.Get("/somepath", func(c *fiber.Ctx) error {
   ...
})
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.0001"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.0002"} 0
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.0005"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.001"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.002"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.005"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.01"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.02"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.05"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.1"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.2"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="0.5"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="1"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="2"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="5"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="10"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="15"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="20"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="30"} 1
lessons_cdn_http_request_duration_seconds_bucket{build="development",method="GET",path="/public",status_code="401",version="development",le="+Inf"} 1

This is certainly strange, here is the complete example, can you please try this:

package main

import (
	"github.com/ansrivas/fiberprometheus/v2"  // v2.6.1
	"github.com/gofiber/fiber/v2"    // v2.48.0
)

func main() {
	app := fiber.New()

	public := app.Group("/public")
	admin := app.Group("/admin")

	prometheus := fiberprometheus.NewWithLabels(map[string]string{
		"component": "fiberprometheus",
	}, "somesystem", "http")

	prometheus.RegisterAt(app, "/metrics")
	app.Use(prometheus.Middleware)

	public.Get("/somepath", func(c *fiber.Ctx) error {
		return c.SendString("Hello World from somepath")
	})
	admin.Get("/adminpath", func(c *fiber.Ctx) error {
		return c.SendString("Hello World from adminpath")
	})

	app.Listen(":3000")
}
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/admin/adminpath",status_code="200",le="1"} 1
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/admin/adminpath",status_code="200",le="2"} 1
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/admin/adminpath",status_code="200",le="5"} 1
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/admin/adminpath",status_code="200",le="10"} 1
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/admin/adminpath",status_code="200",le="15"} 1
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/admin/adminpath",status_code="200",le="20"} 1
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/admin/adminpath",status_code="200",le="30"} 1
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/admin/adminpath",status_code="200",le="+Inf"} 1
somesystem_http_request_duration_seconds_sum{component="fiberprometheus",method="GET",path="/admin/adminpath",status_code="200"} 2.1273e-05
somesystem_http_request_duration_seconds_count{component="fiberprometheus",method="GET",path="/admin/adminpath",status_code="200"} 1
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/public/somepath",status_code="200",le="1e-09"} 0
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/public/somepath",status_code="200",le="2e-09"} 0
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/public/somepath",status_code="200",le="5e-09"} 0
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/public/somepath",status_code="200",le="1e-08"} 0
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/public/somepath",status_code="200",le="2e-08"} 0
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/public/somepath",status_code="200",le="5e-08"} 0
somesystem_http_request_duration_seconds_bucket{component="fiberprometheus",method="GET",path="/public/somepath",status_code="200",le="1e-07"} 0

I think I got what's going on

I think I was able to identify when the path is not correct (at least some cases)

  • let's say public app has a middleware before the routes, if that middleware returns, the path is gonna be only /public
public := app.Group("/public")

prometheus := fiberprometheus.NewWithLabels(labels, strings.ReplaceAll(Component, "-", "_"), "http")
prometheus.RegisterAt(app, "/metrics")
app.Use(prometheus.Middleware)

// if this returns, the path in the metric is /public instead of /lesson/:id/:page
public.Use(auth.Middleware(datasource)) 
public.Get("/lesson/:id/:page", func(c *fiber.Ctx) error {})
  • if a default 404 is returned by fiber because a path does not exists path will be /

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days.

This issue was closed because it has been stalled for 10 days with no activity.

Heya!

I've noticed this as well with one of my apps. The comment above was what I noticed as well, the / paths were all cache hits for me.

I've added a test here, that makes it super clear. https://github.com/Fesaa/fiberprometheus/commit/e748341c6afd9aada719e7aa50c318fc51a0aaa9

I'm looking around a bit, but am not seeing a solution without changes within fiber at the moment.

Am planning to look a bit longer as it annoys me a lot as it makes my grafana graphs wrong 😄

@FedeBev @Fesaa I submitted a PR that includes the new cache metrics from @Fesaa and also fixes the issues @FedeBev was running into with the path's. I also fixed a concurrency issues happening with the default global registry.

This middleware is going to be migrated to https://github.com/gofiber/contrib in the next week or so. Maintenance will be done by the GoFiber team (I'm one of the maintainers).

@FedeBev @Fesaa Migration has started and is being tracked here gofiber/contrib#1032

I have a TODO list of tasks before making a first release. Basically trying to make the middleware easier to use and more feature complete.