Skip to content

Commit 65d6eed

Browse files
committed
PYTHON-5292 - Debug logs should only print on failed tests
1 parent 5b42ed8 commit 65d6eed

File tree

7 files changed

+77
-10
lines changed

7 files changed

+77
-10
lines changed

.evergreen/scripts/run_tests.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import json
4-
import logging
54
import os
65
import platform
76
import shutil
@@ -173,9 +172,6 @@ def run() -> None:
173172
handle_aws_lambda()
174173
return
175174

176-
if os.environ.get("DEBUG_LOG"):
177-
TEST_ARGS.extend(f"-o log_cli_level={logging.DEBUG} -o log_cli=1".split())
178-
179175
# Run local tests.
180176
ret = pytest.main(TEST_ARGS + sys.argv[1:])
181177
if ret != 0:

.evergreen/scripts/setup_tests.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"GREEN_FRAMEWORK",
3131
"NO_EXT",
3232
"MONGODB_API_VERSION",
33-
"DEBUG_LOG",
33+
"PYMONGO_DEBUG_LOG_PATH",
3434
"PYTHON_BINARY",
3535
"PYTHON_VERSION",
3636
"REQUIRE_FIPS",
@@ -464,9 +464,7 @@ def handle_test_env() -> None:
464464
UV_ARGS.append(f"--group {framework}")
465465

466466
else:
467-
# Use --capture=tee-sys so pytest prints test output inline:
468-
# https://docs.pytest.org/en/stable/how-to/capture-stdout-stderr.html
469-
TEST_ARGS = f"-v --capture=tee-sys --durations=5 {TEST_ARGS}"
467+
TEST_ARGS = f"-v --capture=no --show-capture=no --durations=5 {TEST_ARGS}"
470468
TEST_SUITE = TEST_SUITE_MAP.get(test_name)
471469
if TEST_SUITE:
472470
TEST_ARGS = f"-m {TEST_SUITE} {TEST_ARGS}"

pymongo/logger.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import enum
1717
import logging
18+
import logging.handlers
1819
import os
1920
import warnings
2021
from typing import Any
@@ -94,6 +95,46 @@ class _SDAMStatusMessage(str, enum.Enum):
9495
ConnectionClosedReason.IDLE: "Connection was idle too long",
9596
ConnectionCheckOutFailedReason.TIMEOUT: "Connection exceeded the specified timeout",
9697
}
98+
_DEBUG_LOG_HANDLER = None
99+
100+
101+
# Custom logging handler to ensure we only flush the buffered logs on a test failure
102+
class LoggingHandler(logging.handlers.MemoryHandler):
103+
def __init__(self, capacity=1000, target=None):
104+
super().__init__(capacity, logging.DEBUG, target, flushOnClose=False)
105+
self.original_capacity = capacity
106+
107+
def shouldFlush(self, record):
108+
if len(self.buffer) >= self.capacity:
109+
self.capacity = len(self.buffer) * 2
110+
return False
111+
112+
def flush(self):
113+
super().flush()
114+
self.capacity = self.original_capacity
115+
116+
def clear(self):
117+
self.buffer.clear()
118+
self.capacity = self.original_capacity
119+
120+
121+
if os.environ.get("DEBUG_LOG"):
122+
FORMAT = "%(levelname)s %(name)s %(message)s"
123+
handler = logging.StreamHandler()
124+
handler.setFormatter(logging.Formatter(FORMAT))
125+
_DEBUG_LOG_HANDLER = LoggingHandler(target=handler)
126+
127+
_COMMAND_LOGGER.setLevel(logging.DEBUG)
128+
_SERVER_SELECTION_LOGGER.setLevel(logging.DEBUG)
129+
_CONNECTION_LOGGER.setLevel(logging.DEBUG)
130+
_CLIENT_LOGGER.setLevel(logging.DEBUG)
131+
_SDAM_LOGGER.setLevel(logging.DEBUG)
132+
133+
_COMMAND_LOGGER.addHandler(_DEBUG_LOG_HANDLER)
134+
_SERVER_SELECTION_LOGGER.addHandler(_DEBUG_LOG_HANDLER)
135+
_CONNECTION_LOGGER.addHandler(_DEBUG_LOG_HANDLER)
136+
_CLIENT_LOGGER.addHandler(_DEBUG_LOG_HANDLER)
137+
_SDAM_LOGGER.addHandler(_DEBUG_LOG_HANDLER)
97138

98139

99140
def _log_client_error() -> None:

test/asynchronous/conftest.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,24 @@
88
import pytest
99
import pytest_asyncio
1010

11+
from pymongo.logger import _DEBUG_LOG_HANDLER
12+
1113
_IS_SYNC = False
1214

1315

16+
@pytest.hookimpl(hookwrapper=True)
17+
def pytest_runtest_makereport(item):
18+
if _DEBUG_LOG_HANDLER is not None:
19+
outcome = yield
20+
rep = outcome.get_result()
21+
if rep.when == "call" and rep.failed:
22+
_DEBUG_LOG_HANDLER.flush()
23+
else:
24+
_DEBUG_LOG_HANDLER.clear()
25+
else:
26+
yield
27+
28+
1429
@pytest.fixture(scope="session")
1530
def event_loop_policy():
1631
# The default asyncio loop implementation on Windows

test/asynchronous/test_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import time
3535
import uuid
3636
from typing import Any, Iterable, Type, no_type_check
37-
from unittest import mock
37+
from unittest import mock, skipIf
3838
from unittest.mock import patch
3939

4040
import pytest
@@ -629,6 +629,7 @@ def test_detected_environment_logging(self, mock_get_hosts):
629629
logs = [record.getMessage() for record in cm.records if record.name == "pymongo.client"]
630630
self.assertEqual(len(logs), 7)
631631

632+
@skipIf(os.environ.get("DEBUG_LOG"), "Enabling debug logs breaks this test")
632633
@patch("pymongo.asynchronous.srv_resolver._SrvResolver.get_hosts")
633634
async def test_detected_environment_warning(self, mock_get_hosts):
634635
with self._caplog.at_level(logging.WARN):

test/conftest.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,24 @@
66

77
import pytest
88

9+
from pymongo.logger import _DEBUG_LOG_HANDLER
10+
911
_IS_SYNC = True
1012

1113

14+
@pytest.hookimpl(hookwrapper=True)
15+
def pytest_runtest_makereport(item):
16+
if _DEBUG_LOG_HANDLER is not None:
17+
outcome = yield
18+
rep = outcome.get_result()
19+
if rep.when == "call" and rep.failed:
20+
_DEBUG_LOG_HANDLER.flush()
21+
else:
22+
_DEBUG_LOG_HANDLER.clear()
23+
else:
24+
yield
25+
26+
1227
@pytest.fixture(scope="session")
1328
def event_loop_policy():
1429
# The default asyncio loop implementation on Windows

test/test_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import time
3535
import uuid
3636
from typing import Any, Iterable, Type, no_type_check
37-
from unittest import mock
37+
from unittest import mock, skipIf
3838
from unittest.mock import patch
3939

4040
import pytest
@@ -622,6 +622,7 @@ def test_detected_environment_logging(self, mock_get_hosts):
622622
logs = [record.getMessage() for record in cm.records if record.name == "pymongo.client"]
623623
self.assertEqual(len(logs), 7)
624624

625+
@skipIf(os.environ.get("DEBUG_LOG"), "Enabling debug logs breaks this test")
625626
@patch("pymongo.synchronous.srv_resolver._SrvResolver.get_hosts")
626627
def test_detected_environment_warning(self, mock_get_hosts):
627628
with self._caplog.at_level(logging.WARN):

0 commit comments

Comments
 (0)