Skip to content

Prometheus

Echo Prometheus middleware generates Prometheus metrics for HTTP requests.

Add the required module:

Terminal window
go get github.com/labstack/echo-prometheus

Add the Prometheus middleware and a route to serve the gathered metrics:

e := echo.New()
e.Use(echoprometheus.NewMiddleware("myapp")) // adds middleware to gather metrics
e.GET("/metrics", echoprometheus.NewHandler()) // adds route to serve gathered metrics

Serve metrics from the same server that gathers them:

package main
import (
"net/http"
echoprometheus "github.com/labstack/echo-prometheus"
"github.com/labstack/echo/v5"
)
func main() {
e := echo.New()
e.Use(echoprometheus.NewMiddleware("myapp")) // adds middleware to gather metrics
e.GET("/metrics", echoprometheus.NewHandler()) // adds route to serve gathered metrics
e.GET("/hello", func(c *echo.Context) error {
return c.String(http.StatusOK, "hello")
})
if err := e.Start(":8080"); err != nil {
e.Logger.Error("failed to start server", "error", err)
}
}

Serve metrics on a separate port:

func main() {
e := echo.New() // this Echo instance will serve routes on port 8080
e.Use(echoprometheus.NewMiddleware("myapp")) // adds middleware to gather metrics
go func() {
metrics := echo.New() // this Echo will run on separate port 8081
metrics.GET("/metrics", echoprometheus.NewHandler()) // adds route to serve gathered metrics
if err := metrics.Start(":8081"); err != nil {
e.Logger.Error("failed to start metrics server", "error", err)
}
}()
e.GET("/hello", func(c *echo.Context) error {
return c.String(http.StatusOK, "hello")
})
if err := e.Start(":8080"); err != nil {
e.Logger.Error("failed to start server", "error", err)
}
}

Sample output (for the first example):

Terminal window
curl http://localhost:8080/metrics
# HELP echo_request_duration_seconds The HTTP request latencies in seconds.
# TYPE echo_request_duration_seconds summary
echo_request_duration_seconds_sum 0.41086482
echo_request_duration_seconds_count 1
# HELP echo_request_size_bytes The HTTP request sizes in bytes.
# TYPE echo_request_size_bytes summary
echo_request_size_bytes_sum 56
echo_request_size_bytes_count 1
# HELP echo_requests_total How many HTTP requests processed, partitioned by status code and HTTP method.
# TYPE echo_requests_total counter
echo_requests_total{code="200",host="localhost:8080",method="GET",url="/"} 1
# HELP echo_response_size_bytes The HTTP response sizes in bytes.
# TYPE echo_response_size_bytes summary
echo_response_size_bytes_sum 61
echo_response_size_bytes_count 1
...

Use custom metrics with the Prometheus default registry:

package main
import (
"log"
echoprometheus "github.com/labstack/echo-prometheus"
"github.com/labstack/echo/v5"
"github.com/prometheus/client_golang/prometheus"
)
func main() {
e := echo.New() // this Echo instance will serve routes on port 8080
customCounter := prometheus.NewCounter( // create a new counter metric
prometheus.CounterOpts{
Name: "custom_requests_total",
Help: "How many HTTP requests processed, partitioned by status code and HTTP method.",
},
)
if err := prometheus.Register(customCounter); err != nil { // register the counter with the default registry
log.Fatal(err)
}
e.Use(echoprometheus.NewMiddlewareWithConfig(echoprometheus.MiddlewareConfig{
AfterNext: func(c *echo.Context, err error) {
customCounter.Inc() // increment the counter after every request
},
}))
e.GET("/metrics", echoprometheus.NewHandler()) // register a route to serve gathered metrics
if err := e.Start(":8080"); err != nil {
e.Logger.Error("failed to start server", "error", err)
}
}

Or create your own registry and register custom metrics with it:

package main
import (
"log"
echoprometheus "github.com/labstack/echo-prometheus"
"github.com/labstack/echo/v5"
"github.com/prometheus/client_golang/prometheus"
)
func main() {
e := echo.New() // this Echo instance will serve routes on port 8080
customRegistry := prometheus.NewRegistry() // create a custom registry for your custom metrics
customCounter := prometheus.NewCounter( // create a new counter metric
prometheus.CounterOpts{
Name: "custom_requests_total",
Help: "How many HTTP requests processed, partitioned by status code and HTTP method.",
},
)
if err := customRegistry.Register(customCounter); err != nil { // register the counter with the custom registry
log.Fatal(err)
}
e.Use(echoprometheus.NewMiddlewareWithConfig(echoprometheus.MiddlewareConfig{
AfterNext: func(c *echo.Context, err error) {
customCounter.Inc() // increment the counter after every request
},
Registerer: customRegistry, // use the custom registry instead of the default Prometheus registry
}))
e.GET("/metrics", echoprometheus.NewHandlerWithConfig(echoprometheus.HandlerConfig{Gatherer: customRegistry})) // serve metrics from the custom registry
if err := e.Start(":8080"); err != nil {
e.Logger.Error("failed to start server", "error", err)
}
}

A skipper can be passed to avoid generating metrics for certain URLs:

package main
import (
"net/http"
"strings"
echoprometheus "github.com/labstack/echo-prometheus"
"github.com/labstack/echo/v5"
)
func main() {
e := echo.New() // this Echo instance will serve routes on port 8080
mwConfig := echoprometheus.MiddlewareConfig{
Skipper: func(c *echo.Context) bool {
return strings.HasPrefix(c.Path(), "/testurl")
}, // does not gather metrics on routes starting with `/testurl`
}
e.Use(echoprometheus.NewMiddlewareWithConfig(mwConfig)) // adds middleware to gather metrics
e.GET("/metrics", echoprometheus.NewHandler()) // adds route to serve gathered metrics
e.GET("/", func(c *echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
if err := e.Start(":8080"); err != nil {
e.Logger.Error("failed to start server", "error", err)
}
}

Modify the default echoprometheus metric definitions:

package main
import (
"net/http"
echoprometheus "github.com/labstack/echo-prometheus"
"github.com/labstack/echo/v5"
"github.com/prometheus/client_golang/prometheus"
)
func main() {
e := echo.New() // this Echo instance will serve routes on port 8080
e.Use(echoprometheus.NewMiddlewareWithConfig(echoprometheus.MiddlewareConfig{
// Labels of default metrics can be modified or added with the `LabelFuncs` function.
LabelFuncs: map[string]echoprometheus.LabelValueFunc{
"scheme": func(c *echo.Context, err error) string { // additional custom label
return c.Scheme()
},
"host": func(c *echo.Context, err error) string { // overrides the default 'host' label value
return "y_" + c.Request().Host
},
},
// The `echoprometheus` middleware registers the following metrics by default:
// - Histogram: request_duration_seconds
// - Histogram: response_size_bytes
// - Histogram: request_size_bytes
// - Counter: requests_total
// which can be modified with the `HistogramOptsFunc` and `CounterOptsFunc` functions.
HistogramOptsFunc: func(opts prometheus.HistogramOpts) prometheus.HistogramOpts {
if opts.Name == "request_duration_seconds" {
opts.Buckets = []float64{1000.0, 10_000.0, 100_000.0, 1_000_000.0} // 1KB, 10KB, 100KB, 1MB
}
return opts
},
CounterOptsFunc: func(opts prometheus.CounterOpts) prometheus.CounterOpts {
if opts.Name == "requests_total" {
opts.ConstLabels = prometheus.Labels{"my_const": "123"}
}
return opts
},
})) // adds middleware to gather metrics
e.GET("/metrics", echoprometheus.NewHandler()) // adds route to serve gathered metrics
e.GET("/hello", func(c *echo.Context) error {
return c.String(http.StatusOK, "hello")
})
if err := e.Start(":8080"); err != nil {
e.Logger.Error("failed to start server", "error", err)
}
}

MiddlewareConfig · github.com/labstack/[email protected]

Fields from package source
FieldTypeDescriptionSource
Skipper middleware.Skipper Skipper defines a function to skip middleware. L44
Namespace string Namespace is components of the fully-qualified name of the Metric (created by joining Namespace,Subsystem and Name components with "_") Optional L48
Subsystem string Subsystem is components of the fully-qualified name of the Metric (created by joining Namespace,Subsystem and Name components with "_") Defaults to: "echo" L52
LabelFuncs map[string]LabelValueFunc LabelFuncs allows adding custom labels in addition to default labels. When key has same name with default label it replaces default one. L56
HistogramOptsFunc func(opts prometheus.HistogramOpts) prometheus.HistogramOpts HistogramOptsFunc allows to change options for metrics of type histogram before metric is registered to Registerer L59
CounterOptsFunc func(opts prometheus.CounterOpts) prometheus.CounterOpts CounterOptsFunc allows to change options for metrics of type counter before metric is registered to Registerer L62
Registerer prometheus.Registerer Registerer sets the prometheus.Registerer instance the middleware will register these metrics with. Defaults to: prometheus.DefaultRegisterer L66
BeforeNext func(c *echo.Context) BeforeNext is callback that is executed before next middleware/handler is called. Useful for case when you have own metrics that need data to be stored for AfterNext. L70
AfterNext func(c *echo.Context, err error) AfterNext is callback that is executed after next middleware/handler returns. Useful for case when you have own metrics that need incremented/observed. L74
DoNotUseRequestPathFor404 bool If DoNotUseRequestPathFor404 is true, all 404 responses (due to non-matching route) will have the same `url` label and thus won't generate new metrics. L80
Functions from package source
TypeSource
func NewMiddleware(subsystem string) echo.MiddlewareFunc L137
func NewMiddlewareWithConfig(config MiddlewareConfig) echo.MiddlewareFunc L142

HandlerConfig · github.com/labstack/[email protected]

Fields from package source
FieldTypeDescriptionSource
Gatherer prometheus.Gatherer Gatherer sets the prometheus.Gatherer instance the middleware will use when generating the metric endpoint handler. Defaults to: prometheus.DefaultGatherer L90
Functions from package source
TypeSource
func NewHandler() echo.HandlerFunc L115
func NewHandlerWithConfig(config HandlerConfig) echo.HandlerFunc L120

PushGatewayConfig · github.com/labstack/[email protected]

Fields from package source
FieldTypeDescriptionSource
PushGatewayURL string PushGatewayURL is push gateway URL in format http://domain:port L96
PushInterval time.Duration PushInterval in ticker interval for pushing gathered metrics to the Gateway Defaults to: 1 minute L100
Gatherer prometheus.Gatherer Gatherer sets the prometheus.Gatherer instance the middleware will use when generating the metric endpoint handler. Defaults to: prometheus.DefaultGatherer L104
ErrorHandler func(err error) error ErrorHandler is function that is called when errors occur. When callback returns error StartPushGateway also returns. L107
ClientTransport http.RoundTripper ClientTransport specifies the mechanism by which individual HTTP POST requests are made. Defaults to: http.DefaultTransport L111
Functions from package source
TypeSource
func RunPushGatewayGatherer(ctx context.Context, config PushGatewayConfig) error L382