-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
logging: propagate errors during log message emits #7231
Conversation
Currently, a bad logging call, e.g. logger.info('oops', 'first', 2) triggers the default logging handling, which is printing an error to stderr but otherwise continuing. For regular programs this behavior makes sense, a bad log message shouldn't take down the program. But during tests, it is better not to skip over such mistakes, but propagate them to the user.
Relevant doc is here: https://docs.python.org/3/library/logging.html#logging.Handler.handleError |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
@@ -737,6 +753,10 @@ def emit(self, record): | |||
self._section_name_shown = True | |||
super().emit(record) | |||
|
|||
def handleError(self, record: logging.LogRecord) -> None: | |||
# Handled by LogCaptureHandler. | |||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to change those pass
to a docstring to "trick" coverage 😁
def handleError(self, record: logging.LogRecord) -> None:
"""Handled by LogCaptureHandler."""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hehe I didn't know it would trick it.
Actually it really isn't covered so I prefer not to. I don't think it worth covering really, but if someone ever wants 100% coverage, they'd need to :)
If lineno is set to None in the LogRecord, pytest's logging formatting fails: tests/unit/utils/test_log.py:418: in test_empty_message log.qt_message_handler(QtCore.QtDebugMsg, self.Context(), "") qutebrowser/utils/log.py:508: in qt_message_handler qt.handle(record) /usr/lib/python3.8/logging/__init__.py:1587: in handle self.callHandlers(record) /usr/lib/python3.8/logging/__init__.py:1649: in callHandlers hdlr.handle(record) /usr/lib/python3.8/logging/__init__.py:950: in handle self.emit(record) ../../pytest/src/_pytest/logging.py:326: in emit super().emit(record) /usr/lib/python3.8/logging/__init__.py:1089: in emit self.handleError(record) /usr/lib/python3.8/logging/__init__.py:1081: in emit msg = self.format(record) /usr/lib/python3.8/logging/__init__.py:925: in format return fmt.format(record) ../../pytest/src/_pytest/logging.py:89: in format return super().format(record) /usr/lib/python3.8/logging/__init__.py:667: in format s = self.formatMessage(record) /usr/lib/python3.8/logging/__init__.py:636: in formatMessage return self._style.format(record) ../../pytest/src/_pytest/logging.py:185: in format return self._fmt % record.__dict__ E TypeError: %d format: a number is required, not NoneType According to typeshed, lineno should never be None: https://github.com/python/typeshed/blob/028f0d52931fe1f96bb25d066186961159c1f801/stdlib/2and3/logging/__init__.pyi#L386 Thus, this is our fault, not pytest's. However, before pytest 6.0.0, pytest did not surface logging errors: pytest-dev/pytest#7231 pytest-dev/pytest@b13fcb2 Thus, we never noticed something was going wrong here.
If lineno is set to None in the LogRecord, pytest's logging formatting fails: tests/unit/utils/test_log.py:418: in test_empty_message log.qt_message_handler(QtCore.QtDebugMsg, self.Context(), "") qutebrowser/utils/log.py:508: in qt_message_handler qt.handle(record) /usr/lib/python3.8/logging/__init__.py:1587: in handle self.callHandlers(record) /usr/lib/python3.8/logging/__init__.py:1649: in callHandlers hdlr.handle(record) /usr/lib/python3.8/logging/__init__.py:950: in handle self.emit(record) ../../pytest/src/_pytest/logging.py:326: in emit super().emit(record) /usr/lib/python3.8/logging/__init__.py:1089: in emit self.handleError(record) /usr/lib/python3.8/logging/__init__.py:1081: in emit msg = self.format(record) /usr/lib/python3.8/logging/__init__.py:925: in format return fmt.format(record) ../../pytest/src/_pytest/logging.py:89: in format return super().format(record) /usr/lib/python3.8/logging/__init__.py:667: in format s = self.formatMessage(record) /usr/lib/python3.8/logging/__init__.py:636: in formatMessage return self._style.format(record) ../../pytest/src/_pytest/logging.py:185: in format return self._fmt % record.__dict__ E TypeError: %d format: a number is required, not NoneType According to typeshed, lineno should never be None: https://github.com/python/typeshed/blob/028f0d52931fe1f96bb25d066186961159c1f801/stdlib/2and3/logging/__init__.pyi#L386 Thus, this is our fault, not pytest's. However, before pytest 6.0.0, pytest did not surface logging errors: pytest-dev/pytest#7231 pytest-dev/pytest@b13fcb2 Thus, we never noticed something was going wrong here. (cherry picked from commit e206d34) Make mypy happy It doesn't know about QMessageLogContext.lineno being Optional[int] rather than int. (cherry picked from commit 4136c84)
Fixes #6433.
Currently, a bad logging call, e.g.
triggers the default logging handling, which is printing an error to
stderr but otherwise continuing.
For regular programs this behavior makes sense, a bad log message
shouldn't take down the program. But during tests, it is better not to
skip over such mistakes, but propagate them to the user.