starlette_exporter
starlette_exporter copied to clipboard
`from_header` but for `Response`?
Is there any way to create a label based on response in starlette_exporter
?
My use-case is adding a hit-or-miss={hit,miss} label based on the x-fastapi-cache
header.
@lainiwa unfortunately, not at the moment. The custom labels are evaluated before the endpoint handler is called. Interesting idea- I'll report back if I can think of a good solution.
I tested the new helper function, and it seems it's now working for me:
Traceback (most recent call last):
File "/app/lainiwa/myproject/backend/.venv/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/lainiwa/myproject/backend/.venv/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/lainiwa/myproject/backend/.venv/lib/python3.11/site-packages/fastapi/applications.py", line 1054, in __call__
await super().__call__(scope, receive, send)
File "/app/lainiwa/myproject/backend/.venv/lib/python3.11/site-packages/starlette/applications.py", line 123, in __call__
await self.middleware_stack(scope, receive, send)
File "/app/lainiwa/myproject/backend/.venv/lib/python3.11/site-packages/starlette/middleware/errors.py", line 186, in __call__
raise exc
File "/app/lainiwa/myproject/backend/.venv/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
await self.app(scope, receive, _send)
File "/app/lainiwa/myproject/backend/.venv/lib/python3.11/site-packages/starlette_exporter/middleware.py", line 475, in __call__
self.request_count.labels(*labels).inc(**extra)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/lainiwa/myproject/backend/.venv/lib/python3.11/site-packages/prometheus_client/metrics.py", line 199, in labels
raise ValueError('Incorrect label count')
ValueError: Incorrect label count
That's how I was adding the middleware:
app.add_middleware(
PrometheusMiddleware,
app_name='api_production',
prefix='api',
filter_unhandled_paths=True,
labels={
"auth_token_full": lambda request: request.headers.get("authorization", ""),
# ...
"cache_status": from_response_header("X-FastAPI-Cache", allowed_values=("HIT", "MISS")),
},
)
app.add_route("/metrics", handle_metrics)
Is there some obvious problem with it, or would you want me to construct a full minimal reproducible snippet?
@lainiwa thanks for reporting back. I haven't been able to reproduce an error with your example yet but I'll keep looking at it.
I did notice from_response_header("X-FastAPI-Cache", allowed_values=("HIT", "MISS"))
did not work for me and I had to replace it with from_response_header("x-fastapi-cache", allowed_values=("HIT", "MISS"))
(lowercase header key) so there's at least one bug I can get started on for now.
The app I'm testing with is a real simple FastAPI app with the following handler func:
@app.get("/")
def index():
return JSONResponse({
"message": "test"
}, headers={"X-FastAPI-Cache": "HIT"})
I'll see if I can test with a better real-world example.
I'm able to reproduce the same error if I raise an unhandled exception in the handler. Do you think that's what's happening in your application? I opened #99 to handle that case, but let me know if you're seeing this happen outside of exceptions as well.
Hey, sorry for the slow response. Yes, seems those were unhandled exceptions of the app getting hidden by starlette_exporter. I upgraded 0.22.0 -> 0.23.0 and now the exceptions are being correctly surfaced again. Thank you!