Skip to content

Commit 6a70876

Browse files
authored
Merge pull request #1603 from riwatt/preserve-lastresort-log
Preserve logs that LoggingPanel would previously overwrite
2 parents be5763a + a6ece27 commit 6a70876

File tree

3 files changed

+30
-1
lines changed

3 files changed

+30
-1
lines changed

debug_toolbar/panels/logging.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,24 @@ def emit(self, record):
4545
self.collector.collect(record)
4646

4747

48+
# Preserve Python's fallback log mechanism before adding ThreadTrackingHandler.
49+
50+
# If the root logger has no handlers attached then everything that reaches it goes
51+
# to the "handler of last resort".
52+
# So a Django app that doesn't explicitly configure the root logger actually logs
53+
# through logging.lastResort.
54+
# However, logging.lastResort is not used after ThreadTrackingHandler gets added to
55+
# the root logger below. This means that users who have LoggingPanel enabled might
56+
# find their logs are gone from their app as soon as they install DDT.
57+
# Explicitly adding logging.lastResort to logging.root's handler sidesteps this
58+
# potential confusion.
59+
# Note that if root has already been configured, or logging.lastResort has been
60+
# removed, then the configuration is unchanged, so users who configured their
61+
# logging aren't exposed to the opposite confusion of seeing extra log lines from
62+
# their app.
63+
if not logging.root.hasHandlers() and logging.lastResort is not None:
64+
logging.root.addHandler(logging.lastResort)
65+
4866
# We don't use enable/disable_instrumentation because logging is global.
4967
# We can't add thread-local logging handlers. Hopefully logging is cheap.
5068

tests/panels/test_logging.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from unittest.mock import patch
23

34
from debug_toolbar.panels.logging import (
45
MESSAGE_IF_STRING_REPRESENTATION_INVALID,
@@ -86,3 +87,10 @@ def view(request):
8687
self.assertEqual(
8788
MESSAGE_IF_STRING_REPRESENTATION_INVALID, records[0]["message"]
8889
)
90+
91+
@patch("sys.stderr")
92+
def test_fallback_logging(self, mock_stderr):
93+
# make sure the log reaches stderr even though logging set up
94+
# its own handler during its import
95+
self.logger.warning("hello")
96+
mock_stderr.write.assert_called_once_with("hello\n")

tests/settings.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111

1212
INTERNAL_IPS = ["127.0.0.1"]
1313

14-
LOGGING_CONFIG = None # avoids spurious output in tests
14+
LOGGING = { # avoids spurious output in tests
15+
"version": 1,
16+
"disable_existing_loggers": True,
17+
}
1518

1619

1720
# Application definition

0 commit comments

Comments
 (0)