add: Publish GHC runtime metrics to Prometheus metrics endpoint

This commit is contained in:
Michał Kłeczek
2026-05-03 11:41:02 +00:00
committed by Wolfgang Walther
parent c09394517d
commit 85d91e5c0a
7 changed files with 78 additions and 2 deletions
+1
View File
@@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. From versio
- Add `Vary` header to responses by @develop7 in #4609
- Add config `db-timezone-enabled` for optional querying of timezones by @taimoorzaeem in #4751
- Log schema cache queries timings on `log-level=debug` by @steve-chavez in #4805
- Add GHC runtime metrics to the metrics endpoint by @mkleczek in #4862
### Fixed
+4 -1
View File
@@ -45,7 +45,9 @@ filename
FreeBSD
fts
fullstack
GC
GeoJSON
GHC
Github
Google
grantor
@@ -147,6 +149,7 @@ RESTful
RLS
RPC
RSA
RTS
safeupdate
savepoint
schemas
@@ -200,4 +203,4 @@ webuser
wfts
www
debouncing
deduplicates
deduplicates
+39
View File
@@ -238,6 +238,45 @@ pgrst_jwt_cache_evictions_total
The total number of JWT cache evictions.
GHC Runtime Metrics
-------------------
PostgREST can also expose GHC runtime system metrics. These use the ``ghc_*``
prefix and include
`GHC RTS statistics <https://ghc.gitlab.haskell.org/ghc/doc/libraries/base-4.22.0.0-inplace/GHC-Stats.html#g:1>`_
for runtime allocation, garbage collection, memory, and CPU/elapsed time.
These are useful for monitoring PostgREST process health and diagnosing memory
pressure or GC behavior.
To expose these metrics, enable GHC RTS statistics when starting PostgREST:
.. code-block:: bash
postgrest +RTS -T -RTS
When enabled, the admin ``/metrics`` endpoint includes samples such as:
.. code-block:: text
# HELP ghc_gcs_total Total number of GCs
# TYPE ghc_gcs_total counter
ghc_gcs_total 1
# HELP ghc_allocated_bytes_total Total bytes allocated
# TYPE ghc_allocated_bytes_total counter
ghc_allocated_bytes_total 12345678
Other available GHC runtime metrics include:
- ``ghc_gcs_total``
- ``ghc_major_gcs_total``
- ``ghc_allocated_bytes_total``
- ``ghc_max_live_bytes``
- ``ghc_max_mem_in_use_bytes``
- ``ghc_mutator_cpu_seconds_total``
- ``ghc_gc_cpu_seconds_total``
- ``ghc_elapsed_seconds_total``
Traces
======
+1
View File
@@ -136,6 +136,7 @@ library
, parsec >= 3.1.11 && < 3.2
, postgresql-libpq >= 0.10
, prometheus-client >= 1.1.1 && < 1.2.0
, prometheus-metrics-ghc >= 1.0.1.2 && < 1.2
, protolude >= 0.3.1 && < 0.4
, regex-tdfa >= 1.2.2 && < 1.4
, retry >= 0.7.4 && < 0.10
+5 -1
View File
@@ -13,10 +13,13 @@ module PostgREST.Metrics
import qualified Data.ByteString.Lazy as LBS
import qualified Hasql.Pool.Observation as SQL
import Prometheus
import GHC.Stats (getRTSStatsEnabled)
import Prometheus
import qualified Prometheus.Metric.GHC as PMG
import PostgREST.Observation
import Protolude
data MetricsState =
@@ -34,6 +37,7 @@ data MetricsState =
init :: Int -> IO MetricsState
init configDbPoolSize = do
whenM getRTSStatsEnabled $ void $ register PMG.ghcMetrics
metricState <- MetricsState <$>
register (counter (Info "pgrst_db_pool_timeouts_total" "The total number of pool connection timeouts")) <*>
register (gauge (Info "pgrst_db_pool_available" "Available connections in the pool")) <*>
+4
View File
@@ -84,6 +84,7 @@ def run(
configpath=None,
stdin=None,
env=None,
args=None,
port=None,
admin_port=None,
host=None,
@@ -122,6 +123,9 @@ def run(
command = [POSTGREST_BIN]
env["HPCTIXFILE"] = hpctixfile()
if args:
command.extend(args)
if configpath:
command.append(configpath)
+24
View File
@@ -1693,6 +1693,30 @@ def test_admin_metrics(defaultenv):
assert "pgrst_db_pool_timeouts_total" in response.text
def test_admin_metrics_include_ghc_runtime_metrics(defaultenv):
"Should get GHC runtime metrics from the admin endpoint when RTS stats are enabled"
with run(env=defaultenv, args=["+RTS", "-T", "-RTS"], port=freeport()) as postgrest:
response = postgrest.admin.get("/metrics")
assert response.status_code == 200
assert "# HELP ghc_gcs_total Total number of GCs" in response.text
assert "# TYPE ghc_gcs_total counter" in response.text
assert re.search(r"^ghc_gcs_total \d+(?:\.\d+)?$", response.text, re.MULTILINE)
assert re.search(
r"^ghc_allocated_bytes_total \d+(?:\.\d+)?$", response.text, re.MULTILINE
)
def test_admin_metrics_exclude_ghc_runtime_metrics_by_default(defaultenv):
"Should not get GHC runtime metrics unless RTS stats are enabled"
with run(env=defaultenv, port=freeport()) as postgrest:
response = postgrest.admin.get("/metrics")
assert response.status_code == 200
assert "ghc_gcs_total" not in response.text
assert "ghc_allocated_bytes_total" not in response.text
def test_schema_cache_startup_load_with_in_db_config(defaultenv, metapostgrest):
"verify that the Schema Cache loads correctly at startup, using the in-db `pgrst.db_schemas` config"