Skip to content

Commit 6ce31b6

Browse files
committed
PYTHON-4557 - Add log message for retried commands
1 parent d1c1415 commit 6ce31b6

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

pymongo/asynchronous/mongo_client.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,13 @@
8989
_async_create_lock,
9090
_release_locks,
9191
)
92-
from pymongo.logger import _CLIENT_LOGGER, _log_client_error, _log_or_warn
92+
from pymongo.logger import (
93+
_CLIENT_LOGGER,
94+
_COMMAND_LOGGER,
95+
_debug_log,
96+
_log_client_error,
97+
_log_or_warn,
98+
)
9399
from pymongo.message import _CursorAddress, _GetMore, _Query
94100
from pymongo.monitoring import ConnectionClosedReason
95101
from pymongo.operations import (
@@ -2684,6 +2690,7 @@ def __init__(
26842690
self._deprioritized_servers: list[Server] = []
26852691
self._operation = operation
26862692
self._operation_id = operation_id
2693+
self._attempt_number = 0
26872694

26882695
async def run(self) -> T:
26892696
"""Runs the supplied func() and attempts a retry
@@ -2726,6 +2733,7 @@ async def run(self) -> T:
27262733
raise
27272734
self._retrying = True
27282735
self._last_error = exc
2736+
self._attempt_number += 1
27292737
else:
27302738
raise
27312739

@@ -2747,6 +2755,7 @@ async def run(self) -> T:
27472755
raise self._last_error from exc
27482756
else:
27492757
raise
2758+
self._attempt_number += 1
27502759
if self._bulk:
27512760
self._bulk.retrying = True
27522761
else:
@@ -2825,6 +2834,11 @@ async def _write(self) -> T:
28252834
# not support sessions raise the last error.
28262835
self._check_last_error()
28272836
self._retryable = False
2837+
if self._retrying:
2838+
_debug_log(
2839+
_COMMAND_LOGGER,
2840+
message=f"Retrying write attempt number {self._attempt_number}",
2841+
)
28282842
return await self._func(self._session, conn, self._retryable) # type: ignore
28292843
except PyMongoError as exc:
28302844
if not self._retryable:
@@ -2846,6 +2860,11 @@ async def _read(self) -> T:
28462860
):
28472861
if self._retrying and not self._retryable:
28482862
self._check_last_error()
2863+
if self._retrying:
2864+
_debug_log(
2865+
_COMMAND_LOGGER,
2866+
message=f"Retrying read attempt number {self._attempt_number}",
2867+
)
28492868
return await self._func(self._session, self._server, conn, read_pref) # type: ignore
28502869

28512870

pymongo/synchronous/mongo_client.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,13 @@
8181
_create_lock,
8282
_release_locks,
8383
)
84-
from pymongo.logger import _CLIENT_LOGGER, _log_client_error, _log_or_warn
84+
from pymongo.logger import (
85+
_CLIENT_LOGGER,
86+
_COMMAND_LOGGER,
87+
_debug_log,
88+
_log_client_error,
89+
_log_or_warn,
90+
)
8591
from pymongo.message import _CursorAddress, _GetMore, _Query
8692
from pymongo.monitoring import ConnectionClosedReason
8793
from pymongo.operations import (
@@ -2670,6 +2676,7 @@ def __init__(
26702676
self._deprioritized_servers: list[Server] = []
26712677
self._operation = operation
26722678
self._operation_id = operation_id
2679+
self._attempt_number = 0
26732680

26742681
def run(self) -> T:
26752682
"""Runs the supplied func() and attempts a retry
@@ -2712,6 +2719,7 @@ def run(self) -> T:
27122719
raise
27132720
self._retrying = True
27142721
self._last_error = exc
2722+
self._attempt_number += 1
27152723
else:
27162724
raise
27172725

@@ -2733,6 +2741,7 @@ def run(self) -> T:
27332741
raise self._last_error from exc
27342742
else:
27352743
raise
2744+
self._attempt_number += 1
27362745
if self._bulk:
27372746
self._bulk.retrying = True
27382747
else:
@@ -2811,6 +2820,11 @@ def _write(self) -> T:
28112820
# not support sessions raise the last error.
28122821
self._check_last_error()
28132822
self._retryable = False
2823+
if self._retrying:
2824+
_debug_log(
2825+
_COMMAND_LOGGER,
2826+
message=f"Retrying write attempt number {self._attempt_number}",
2827+
)
28142828
return self._func(self._session, conn, self._retryable) # type: ignore
28152829
except PyMongoError as exc:
28162830
if not self._retryable:
@@ -2832,6 +2846,11 @@ def _read(self) -> T:
28322846
):
28332847
if self._retrying and not self._retryable:
28342848
self._check_last_error()
2849+
if self._retrying:
2850+
_debug_log(
2851+
_COMMAND_LOGGER,
2852+
message=f"Retrying read attempt number {self._attempt_number}",
2853+
)
28352854
return self._func(self._session, self._server, conn, read_pref) # type: ignore
28362855

28372856

test/asynchronous/test_logger.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
import os
1717
from test import unittest
18-
from test.asynchronous import AsyncIntegrationTest
18+
from test.asynchronous import AsyncIntegrationTest, async_client_context
1919
from unittest.mock import patch
2020

2121
from bson import json_util
@@ -97,6 +97,21 @@ async def test_logging_without_listeners(self):
9797
await c.db.test.insert_one({"x": "1"})
9898
self.assertGreater(len(cm.records), 0)
9999

100+
@async_client_context.require_failCommand_fail_point
101+
async def test_logging_retry_read_attempts(self):
102+
await self.db.test.insert_one({"x": "1"})
103+
104+
async with self.fail_point(
105+
{"mode": {"times": 1}, "data": {"failCommands": ["find"], "closeConnection": True}}
106+
):
107+
with self.assertLogs("pymongo.command", level="DEBUG") as cm:
108+
await self.db.test.find_one({"x": "1"})
109+
110+
retry_messages = [
111+
r.getMessage() for r in cm.records if "Retrying read attempt" in r.getMessage()
112+
]
113+
self.assertEqual(len(retry_messages), 1)
114+
100115

101116
if __name__ == "__main__":
102117
unittest.main()

test/test_logger.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from __future__ import annotations
1515

1616
import os
17-
from test import IntegrationTest, unittest
17+
from test import IntegrationTest, client_context, unittest
1818
from unittest.mock import patch
1919

2020
from bson import json_util
@@ -96,6 +96,21 @@ def test_logging_without_listeners(self):
9696
c.db.test.insert_one({"x": "1"})
9797
self.assertGreater(len(cm.records), 0)
9898

99+
@client_context.require_failCommand_fail_point
100+
def test_logging_retry_read_attempts(self):
101+
self.db.test.insert_one({"x": "1"})
102+
103+
with self.fail_point(
104+
{"mode": {"times": 1}, "data": {"failCommands": ["find"], "closeConnection": True}}
105+
):
106+
with self.assertLogs("pymongo.command", level="DEBUG") as cm:
107+
self.db.test.find_one({"x": "1"})
108+
109+
retry_messages = [
110+
r.getMessage() for r in cm.records if "Retrying read attempt" in r.getMessage()
111+
]
112+
self.assertEqual(len(retry_messages), 1)
113+
99114

100115
if __name__ == "__main__":
101116
unittest.main()

0 commit comments

Comments
 (0)