Skip to content

Commit c9a625c

Browse files
authored
feat: Log PoolRequest and PoolRequestFullfilled observations (#3925)
1 parent 1a287ed commit c9a625c

File tree

4 files changed

+59
-20
lines changed

4 files changed

+59
-20
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1616
- #3747, Allow `not_null` value for the `is` operator - @taimoorzaeem
1717
- #2255, Apply `to_tsvector()` explicitly to the full-text search filtered column (excluding `tsvector` types) - @laurenceisla
1818
- #1578, Log the main SQL query to stderr at the current `log-level` when `log-query=main-query` - @laurenceisla
19+
- #3903, Log connection pool borrows on `log-level=debug` - @taimoorzaeem
1920

2021
### Fixed
2122

src/PostgREST/Logger.hs

+6-4
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,12 @@ observationLogger loggerState logLevel obs = case obs of
9494
-- Does not log SQL when it's empty (for OPTIONS requests or for the default OpenAPI output)
9595
when (sql /= mempty && shouldLogResponse logLevel status) $ do
9696
logWithZTime loggerState $ observationMessage o
97-
PoolRequest ->
98-
pure ()
99-
PoolRequestFullfilled ->
100-
pure ()
97+
o@PoolRequest ->
98+
when (logLevel >= LogDebug) $ do
99+
logWithZTime loggerState $ observationMessage o
100+
o@PoolRequestFullfilled ->
101+
when (logLevel >= LogDebug) $ do
102+
logWithZTime loggerState $ observationMessage o
101103
o ->
102104
logWithZTime loggerState $ observationMessage o
103105

src/PostgREST/Observation.hs

+4-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,10 @@ observationMessage = \case
142142
SQL.ReleaseConnectionTerminationReason -> "release"
143143
SQL.NetworkErrorConnectionTerminationReason _ -> "network error" -- usage error is already logged, no need to repeat the same message.
144144
)
145-
_ -> mempty
145+
PoolRequest ->
146+
"Trying to borrow a connection from pool"
147+
PoolRequestFullfilled ->
148+
"Borrowed a connection from the pool"
146149
where
147150
showMillis :: Double -> Text
148151
showMillis x = toS $ showFFloat (Just 1) (x * 1000) ""

test/io/test_io.py

+48-15
Original file line numberDiff line numberDiff line change
@@ -683,13 +683,16 @@ def test_pool_acquisition_timeout(level, defaultenv, metapostgrest):
683683
assert data["message"] == "Timed out acquiring connection from connection pool."
684684

685685
# ensure the message appears on the logs as well
686-
output = sorted(postgrest.read_stdout(nlines=3))
686+
output = sorted(postgrest.read_stdout(nlines=10))
687687

688688
if level == "crit":
689689
assert len(output) == 0
690690
else:
691-
assert " 504 " in output[0]
692-
assert "Timed out acquiring connection from connection pool." in output[2]
691+
assert any(" 504 " in line for line in output)
692+
assert any(
693+
"Timed out acquiring connection from connection pool." in line
694+
for line in output
695+
)
693696

694697

695698
def test_change_statement_timeout_held_connection(defaultenv, metapostgrest):
@@ -974,9 +977,9 @@ def test_log_level(level, defaultenv):
974977
output[2],
975978
)
976979

977-
assert len(output) == 5
978-
assert "Connection" and "is available" in output[3]
979-
assert "Connection" and "is used" in output[4]
980+
assert len(output) == 7
981+
assert any("Connection" and "is available" in line for line in output)
982+
assert any("Connection" and "is used" in line for line in output)
980983

981984

982985
@pytest.mark.parametrize("level", ["crit", "error", "warn", "info", "debug"])
@@ -1023,13 +1026,15 @@ def test_log_query(level, defaultenv):
10231026
assert re.match(infinite_recursion_5xx_regx, output[5])
10241027
assert len(output) == 6
10251028
elif level == "debug":
1026-
output_ok = postgrest.read_stdout(nlines=8)
1027-
assert re.match(root_2xx_regx, output_ok[2])
1028-
assert re.match(get_2xx_regx, output_ok[6])
1029-
assert len(output_ok) == 8
1030-
output_err = postgrest.read_stdout(nlines=4)
1031-
assert re.match(infinite_recursion_5xx_regx, output_err[3])
1032-
assert len(output_err) == 4
1029+
output_root = postgrest.read_stdout(nlines=6)
1030+
assert re.match(root_2xx_regx, output_root[4])
1031+
assert len(output_root) == 6
1032+
output_get = postgrest.read_stdout(nlines=6)
1033+
assert re.match(get_2xx_regx, output_get[4])
1034+
assert len(output_get) == 6
1035+
output_err = postgrest.read_stdout(nlines=6)
1036+
assert re.match(infinite_recursion_5xx_regx, output_err[5])
1037+
assert len(output_err) == 6
10331038

10341039

10351040
def test_no_pool_connection_required_on_bad_http_logic(defaultenv):
@@ -1570,13 +1575,13 @@ def test_db_error_logging_to_stderr(level, defaultenv, metapostgrest):
15701575
assert response.status_code == 500
15711576

15721577
# ensure the message appears on the logs
1573-
output = sorted(postgrest.read_stdout(nlines=4))
1578+
output = sorted(postgrest.read_stdout(nlines=6))
15741579

15751580
if level == "crit":
15761581
assert len(output) == 0
15771582
elif level == "debug":
15781583
assert " 500 " in output[0]
1579-
assert "canceling statement due to statement timeout" in output[3]
1584+
assert "canceling statement due to statement timeout" in output[5]
15801585
else:
15811586
assert " 500 " in output[0]
15821587
assert "canceling statement due to statement timeout" in output[1]
@@ -1767,3 +1772,31 @@ def test_pgrst_log_503_client_error_to_stderr(defaultenv):
17671772
log_message = '{"code":"PGRST001","details":"no connection to the server\\n","hint":null,"message":"Database client error. Retrying the connection."}\n'
17681773

17691774
assert any(log_message in line for line in output)
1775+
1776+
1777+
@pytest.mark.parametrize("level", ["crit", "error", "warn", "info", "debug"])
1778+
def test_log_pool_req_observation(level, defaultenv):
1779+
"PostgREST should log PoolRequest and PoolRequestFullfilled observation when log-level=debug"
1780+
1781+
env = {**defaultenv, "PGRST_LOG_LEVEL": level, "PGRST_JWT_SECRET": SECRET}
1782+
1783+
headers = jwtauthheader({"role": "postgrest_test_author"}, SECRET)
1784+
1785+
pool_req = "Trying to borrow a connection from pool"
1786+
pool_req_fullfill = "Borrowed a connection from the pool"
1787+
1788+
with run(env=env) as postgrest:
1789+
1790+
postgrest.session.get("/authors_only", headers=headers)
1791+
1792+
if level == "debug":
1793+
output = postgrest.read_stdout(nlines=4)
1794+
assert pool_req in output[0]
1795+
assert pool_req_fullfill in output[3]
1796+
assert len(output) == 4
1797+
elif level == "info":
1798+
output = postgrest.read_stdout(nlines=4)
1799+
assert len(output) == 1
1800+
else:
1801+
output = postgrest.read_stdout(nlines=4)
1802+
assert len(output) == 0

0 commit comments

Comments
 (0)