Have a question regarding Prometheus metrics in Tapir and ZIO. I have a simple code:
val metrics = PrometheusMetrics.default[Task]()
val options: ZioHttpServerOptions[Any] = ZioHttpServerOptions
.customiseInterceptors
.metricsInterceptor(metrics.metricsInterceptor())
.options
and it works correct when I call localhost:8080/metrics
, I see metrics.
But when I added default error handler:
val metrics = PrometheusMetrics.default[Task]()
def failureResponse(msg: String): ValuedEndpointOutput[_]=
ValuedEndpointOutput(jsonBody[MyFailure], MyFailure(msg))
val options: ZioHttpServerOptions[Any] = ZioHttpServerOptions
.customiseInterceptors
.metricsInterceptor(metrics.metricsInterceptor())
.defaultHandlers(failureResponse, notFoundWhenRejected = true)
.options
It doesn't work. Instead of metrics I see now error (404) which was caught during request to localhost:8080/metrics
. Honestly, don't know why. Is it possible to fix it somehow and keep error handler along with metrics interceptor?
EDIT: Metrics endpoint:
def metricsEndpoint = ZioHttpInterpreter(options).toHttp(metrics.metricsEndpoint)
CodePudding user response:
This problem is most probably due to separately interpreting the "main" endpoints and the metrics endpoint as ZIO Http's Http
value.
Consider the following:
val mainHttp = ZioHttpInterpreter(options).toHttp(mainEndpoints)
val metricsHttp = ZioHttpInterpreter(options).toHttp(metricsEndpoints)
Server.start(8080, mainHttp <> metricsHttp)
If the notFoundWhenRejected = true
option is used, when the request /metrics
comes in, it is first handled by mainHttp
. However, that value doesn't know how to handle this request - hence it is rejected. But as we specified the mentioned option, rejections are turned into 404s, hence the answer.
The default value for that option is false
. In this situation, the /metrics
request is rejected by the mainHttp
value, but this isn't converted into a 404 response, instead processing continues with metricsHttp
.
The proper solution, to have both /metrics
working, and the notFoundWhenRejected = true
option, is to interpret all endpoints at once. Then, the 404 will be returned only when none of the endpoint (neither the main, nor the metrics one) matches the request:
val http = ZioHttpInterpreter(options)
.toHttp(mainEndpoints metricsEndpoints)
Server.start(8080, http)