echo-contrib icon indicating copy to clipboard operation
echo-contrib copied to clipboard

Disable certain prometheus metrics

Open ivanovaleksandar opened this issue 2 years ago • 3 comments

Hi all

Is there a way to disable certain type of metrics at the moment? For example, disable request_size_bytes_bucket or just completely disable histograms for any type of metric.

In my case, i am doing a proxy type of a setup with at least 20 routes, so having histogram, bytes, etc generates tons of metrics.

ivanovaleksandar avatar Feb 01 '24 12:02 ivanovaleksandar

Nope, requests_total, request_duration_seconds, response_size_bytes, request_size_bytes are built in.

but if you are OK not having histograms then it leaves you only with requests_total as this is counter. You could strip down the middleware to something like that and add your custom metrics if needed.

func myPrometheusRoute() echo.HandlerFunc {
	gatherer := prometheus.DefaultGatherer
	h := promhttp.HandlerFor(gatherer, promhttp.HandlerOpts{DisableCompression: true})

	if r, ok := gatherer.(prometheus.Registerer); ok {
		h = promhttp.InstrumentMetricHandler(r, h)
	}

	return func(c echo.Context) error {
		h.ServeHTTP(c.Response(), c.Request())
		return nil
	}
}

func myPrometheusMW() (echo.MiddlewareFunc, error) {
	requestCount := prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: "",
			Subsystem: "MY_APP",
			Name:      "requests_total",
			Help:      "How many HTTP requests processed, partitioned by status code and HTTP method.",
		},
		[]string{"code", "method", "host", "url"},
	)
	if err := prometheus.DefaultRegisterer.Register(requestCount); err != nil {
		return nil, err
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			err := next(c)
			status := c.Response().Status
			if err != nil {
				var httpError *echo.HTTPError
				if errors.As(err, &httpError) {
					status = httpError.Code
				}
				if status == 0 || status == http.StatusOK {
					status = http.StatusInternalServerError
				}
			}

			url := c.Path() // contains route path ala `/users/:id`
			if url == "" {
				// as of Echo v4.10.1 path is empty for 404 cases (when router did not find any matching routes)
				// in this case we use actual path from request to have some distinction in Prometheus
				url = c.Request().URL.Path
			}

			requestCount.WithLabelValues(
				strconv.Itoa(status),
				c.Request().Method,
				c.Request().Host,
				url,
			).Inc()
			return err
		}
	}, nil
}

This is https://github.com/labstack/echo-contrib/tree/master/echoprometheus stripped down

aldas avatar Feb 01 '24 12:02 aldas

NB: you might need custom registry. This does not contain prometheus own default metrics

customRegistry := prometheus.NewRegistry() // create custom registry for your custom metrics

and make sure that you Route takes that registry in as gatherer

e.GET("/metrics", myPrometheusRoute(customRegistry))

and myPrometheusMW needs to use that same customRegistry to register metrics

aldas avatar Feb 01 '24 12:02 aldas

@aldas thank you for providing a workaround. I replicated almost the same locally, but was wondering if there is something that I am missing here.

Anyways, is it something that you want implemented? I mean, the optional disabling of these types of metrics.

ivanovaleksandar avatar Feb 01 '24 13:02 ivanovaleksandar