I'm trying to register the Prometheus handler to track some metrics from the application I'm writing but I cannot find a way. I managed to to the following:
package main
import (
"github.com/gofiber/fiber"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/valyala/fasthttp/fasthttpadaptor"
func main() {
app := fiber.New()
p := fasthttpadaptor.NewFastHTTPHandler(promhttp.Handler())
app.Get("/metrics", func(c *fiber.Ctx) {
p(c.Fasthttp)
})
app.Get("/", func(c *fiber.Ctx){
c.Send("Hello, World!")
})
app.Get("/404", func(c *fiber.Ctx){
c.Status(4040).Send("Where did I put it?")
})
app.Listen(3000)
}
And it does respond to the requests on /metrics with some data that seems reasonable. Only problem it doesn't seem to count the responses correctly.
(the two endpoints / and /404 are there exactly to try it).
Thanks for opening your first issue here! 馃帀 Be sure to follow the issue template!
ps: Brilliant work, BTW 馃槃
@ganglio, make sure you are using the latest version:
go get -u github.com/gofiber/fiber
When I run your code I get the following output, could you tell me what variable is missing/incorrect?
package main
import (
"github.com/gofiber/fiber"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/valyala/fasthttp/fasthttpadaptor"
)
func main() {
app := fiber.New()
p := fasthttpadaptor.NewFastHTTPHandler(promhttp.Handler())
app.Get("/metrics", func(c *fiber.Ctx) {
p(c.Fasthttp)
})
app.Get("/", func(c *fiber.Ctx) {
c.Send("Hello, World!")
})
app.Get("/404", func(c *fiber.Ctx) {
c.Status(404).Send("You just lost us an unpaid employee.")
})
app.Listen(3000)
}
http://localhost:3000/metrics
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
go_gc_duration_seconds{quantile="0.5"} 0
go_gc_duration_seconds{quantile="0.75"} 0
go_gc_duration_seconds{quantile="1"} 0
go_gc_duration_seconds_sum 0
go_gc_duration_seconds_count 0
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 9
# HELP go_info Information about the Go environment.
# TYPE go_info gauge
go_info{version="go1.13.5"} 1
# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes 1.166264e+06
# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed.
# TYPE go_memstats_alloc_bytes_total counter
go_memstats_alloc_bytes_total 1.166264e+06
# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table.
# TYPE go_memstats_buck_hash_sys_bytes gauge
go_memstats_buck_hash_sys_bytes 1.443579e+06
# HELP go_memstats_frees_total Total number of frees.
# TYPE go_memstats_frees_total counter
go_memstats_frees_total 222
# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started.
# TYPE go_memstats_gc_cpu_fraction gauge
go_memstats_gc_cpu_fraction 0
# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata.
# TYPE go_memstats_gc_sys_bytes gauge
go_memstats_gc_sys_bytes 2.240512e+06
# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use.
# TYPE go_memstats_heap_alloc_bytes gauge
go_memstats_heap_alloc_bytes 1.166264e+06
# HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used.
# TYPE go_memstats_heap_idle_bytes gauge
go_memstats_heap_idle_bytes 6.4397312e+07
# HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use.
# TYPE go_memstats_heap_inuse_bytes gauge
go_memstats_heap_inuse_bytes 2.2528e+06
# HELP go_memstats_heap_objects Number of allocated objects.
# TYPE go_memstats_heap_objects gauge
go_memstats_heap_objects 4380
# HELP go_memstats_heap_released_bytes Number of heap bytes released to OS.
# TYPE go_memstats_heap_released_bytes gauge
go_memstats_heap_released_bytes 6.4397312e+07
# HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system.
# TYPE go_memstats_heap_sys_bytes gauge
go_memstats_heap_sys_bytes 6.6650112e+07
# HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection.
# TYPE go_memstats_last_gc_time_seconds gauge
go_memstats_last_gc_time_seconds 0
# HELP go_memstats_lookups_total Total number of pointer lookups.
# TYPE go_memstats_lookups_total counter
go_memstats_lookups_total 0
# HELP go_memstats_mallocs_total Total number of mallocs.
# TYPE go_memstats_mallocs_total counter
go_memstats_mallocs_total 4602
# HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures.
# TYPE go_memstats_mcache_inuse_bytes gauge
go_memstats_mcache_inuse_bytes 13888
# HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system.
# TYPE go_memstats_mcache_sys_bytes gauge
go_memstats_mcache_sys_bytes 16384
# HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures.
# TYPE go_memstats_mspan_inuse_bytes gauge
go_memstats_mspan_inuse_bytes 25160
# HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system.
# TYPE go_memstats_mspan_sys_bytes gauge
go_memstats_mspan_sys_bytes 32768
# HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place.
# TYPE go_memstats_next_gc_bytes gauge
go_memstats_next_gc_bytes 4.473924e+06
# HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations.
# TYPE go_memstats_other_sys_bytes gauge
go_memstats_other_sys_bytes 1.051133e+06
# HELP go_memstats_stack_inuse_bytes Number of bytes in use by the stack allocator.
# TYPE go_memstats_stack_inuse_bytes gauge
go_memstats_stack_inuse_bytes 458752
# HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator.
# TYPE go_memstats_stack_sys_bytes gauge
go_memstats_stack_sys_bytes 458752
# HELP go_memstats_sys_bytes Number of bytes obtained from system.
# TYPE go_memstats_sys_bytes gauge
go_memstats_sys_bytes 7.189324e+07
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
go_threads 8
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1024
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 8
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 1.0747904e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.58230736989e+09
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 5.82090752e+08
# HELP process_virtual_memory_max_bytes Maximum amount of virtual memory available in bytes.
# TYPE process_virtual_memory_max_bytes gauge
process_virtual_memory_max_bytes -1
# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served.
# TYPE promhttp_metric_handler_requests_in_flight gauge
promhttp_metric_handler_requests_in_flight 1
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 0
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0
@Fenny if you keep requesting /metrics you'll see the promhttp_metric_handler_requests_total{code="200"} increase.
It doesn't happen if you query / or /404 (do it a number of times as the metric increase by 1 every time you request the /metrics endpoint.
From what I understand, the promhttp is used as a wrapper around a router. In the case of Fiber it's only added as a single route thus, while it measures correctly the health of the application (memory, goroutines, etc) it doesn't count the requests correctly.
Ok, I managed to make it work 馃槃
package middlewares
import (
"fmt"
"github.com/gofiber/fiber"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/valyala/fasthttp/fasthttpadaptor"
)
var (
p = fasthttpadaptor.NewFastHTTPHandler(
promhttp.HandlerFor(
prometheus.DefaultGatherer,
promhttp.HandlerOpts{
// Opt into OpenMetrics to support exemplars.
EnableOpenMetrics: true,
},
),
)
errCnt = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "promhttp_metric_handler_errors_total",
Help: "Total number of internal errors encountered by the promhttp metric handler.",
},
[]string{"status", "method", "path"},
)
)
func init() {
prometheus.MustRegister(errCnt)
}
func PrometheusHandler(c *fiber.Ctx) {
p(c.Fasthttp)
}
func Prometheus(c *fiber.Ctx) {
sc := c.Fasthttp.Response.StatusCode()
me := c.Fasthttp.Method()
pa := c.Fasthttp.Path()
errCnt.WithLabelValues(fmt.Sprintf("%d", sc), string(me), string(pa)).Add(1)
c.Next()
}
Only caveat is that all the routes must have a defer c.Next() and the config looks like this:
...
app.Get("/metrics", middlewares.PrometheusHandler)
app.Get("/", func(c *fiber.Ctx) {
defer c.Next()
c.Send("馃悵")}
)
app.Use(middlewares.Prometheus)
app.Listen(3000)
...
It would be amazing to have support for "afterwares" that are always executed after everything.
We have to think about that, but maybe its better to fix this in a wrapper for Prometheus.
PS: You have a bug in your code: 馃悵
@Fenny any updates on this?
We have to think about that, but maybe its better to fix this in a wrapper for Prometheus.
PS: You have a bug in your code:
馃悵
@Fenny I have implemented the prometheus middleware with some basic defaults here.
https://github.com/ansrivas/fiberprometheus
Most helpful comment
@Fenny I have implemented the prometheus middleware with some basic defaults here.
https://github.com/ansrivas/fiberprometheus