From dfe5ba3863daa51aac8b64074e840dab8f1abe18 Mon Sep 17 00:00:00 2001 From: Taimoor Zaeem Date: Wed, 20 Aug 2025 23:18:44 +0500 Subject: [PATCH] fix(admin): metrics endpoint not responding with Content-Type header The prometheus metrics text format requires `Content-Type` header for correct scraping which fails otherwise. Closes #4271. Signed-off-by: Taimoor Zaeem --- CHANGELOG.md | 1 + docs/references/observability.rst | 5 +++++ src/PostgREST/Admin.hs | 3 ++- test/io/test_io.py | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8e64fd8d..8d3e392a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Fix OpenAPI broken docs link by @taimoorzaeem in #4080 - Fix OpenAPI specification incorrectly exposing GET methods for volatile functions by @joelonsql in #4174 - Fix empty spread embeddings return unexpected SQL error by @taimoorzaeem in #3887 +- Fix `/metrics` endpoint not responding with `Content-Type` header by @taimoorzaeem in #4271 ### Changed diff --git a/docs/references/observability.rst b/docs/references/observability.rst index 5266d8b19..f73890b80 100644 --- a/docs/references/observability.rst +++ b/docs/references/observability.rst @@ -128,6 +128,11 @@ The ``metrics`` endpoint on the :ref:`admin_server` endpoint provides metrics in curl "http://localhost:3001/metrics" +.. code-block:: http + + HTTP/1.1 200 OK + Content-Type: text/plain; charset=utf-8 + # HELP pgrst_schema_cache_query_time_seconds The query time in seconds of the last schema cache load # TYPE pgrst_schema_cache_query_time_seconds gauge pgrst_schema_cache_query_time_seconds 1.5937927e-2 diff --git a/src/PostgREST/Admin.hs b/src/PostgREST/Admin.hs index c9fb8c5f8..d0486984b 100644 --- a/src/PostgREST/Admin.hs +++ b/src/PostgREST/Admin.hs @@ -16,6 +16,7 @@ import Network.Socket.ByteString import PostgREST.AppState (AppState) import PostgREST.Config (AppConfig (..)) +import PostgREST.MediaType (MediaType (..), toContentType) import PostgREST.Metrics (metricsToText) import PostgREST.Network (resolveHost) import PostgREST.Observation (Observation (..)) @@ -58,7 +59,7 @@ admin appState req respond = do respond $ Wai.responseLBS HTTP.status200 [] (maybe mempty JSON.encode sCache) ["metrics"] -> do mets <- metricsToText - respond $ Wai.responseLBS HTTP.status200 [] mets + respond $ Wai.responseLBS HTTP.status200 [toContentType MTTextPlain] mets -- Content-Type is required for prometheus compliance _ -> respond $ Wai.responseLBS HTTP.status404 [] mempty diff --git a/test/io/test_io.py b/test/io/test_io.py index 33c7d781e..a2b1152f8 100644 --- a/test/io/test_io.py +++ b/test/io/test_io.py @@ -1730,6 +1730,7 @@ def test_admin_metrics(defaultenv): with run(env=defaultenv, port=freeport()) as postgrest: response = postgrest.admin.get("/metrics") assert response.status_code == 200 + assert response.headers["Content-Type"] == "text/plain; charset=utf-8" assert "pgrst_schema_cache_query_time_seconds" in response.text assert 'pgrst_schema_cache_loads_total{status="SUCCESS"}' in response.text assert "pgrst_db_pool_max" in response.text