-
-
Notifications
You must be signed in to change notification settings - Fork 273
Description
Hello everyone!
Before I describe the issue, let me provide some context.
Main issue:
I encountered an error when attempting to call logger.exception outside an except block without including any information about an exception. For example:
from structlog import getLogger
logger = getLogger()
logger.exception('test')
This code raises the following error:
Traceback (most recent call last):
File "/home/amiter/coding/structlog/amiter.py", line 3, in <module>
bl.exception('test_exception')
File "/home/amiter/coding/structlog/src/structlog/_log_levels.py", line 94, in exception
return self.error(event, **kw)
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/amiter/coding/structlog/src/structlog/_log_levels.py", line 169, in meth
return self._proxy_to_logger(name, event, **kw)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/amiter/coding/structlog/src/structlog/_base.py", line 204, in _proxy_to_logger
args, kw = self._process_event(method_name, event, event_kw)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/amiter/coding/structlog/src/structlog/_base.py", line 159, in _process_event
event_dict = proc(self._logger, method_name, event_dict)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/amiter/coding/structlog/src/structlog/dev.py", line 426, in __call__
self._exception_formatter(sio, exc_info)
File "/home/amiter/coding/structlog/src/structlog/dev.py", line 191, in rich_traceback
Traceback.from_exception(*exc_info, show_locals=True)
File "/home/amiter/coding/structlog/.venv/lib/python3.11/site-packages/rich/traceback.py", line 335, in from_exception
rich_traceback = cls.extract(
^^^^^^^^^^^^
File "/home/amiter/coding/structlog/.venv/lib/python3.11/site-packages/rich/traceback.py", line 406, in extract
exc_type=safe_str(exc_type.__name__),
^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute '__name__'. Did you mean: '__ne__'?
I find this error message confusing because it seems like an internal bug.
It is clear that moving the logger call inside the try/except block resolves the issue. Additionally, including information about the exception using constructions like logger.exception('test', exc_info=False) or logger.exception('test', exc_info=ZeroDivisionError()) also prevents the error.
The cause of the AttributeError is that the code blocks in stdlib.BoundLogger.exception() and _log_levels.exception() set exc_info to True using kw.setdefault("exc_info", True), even when there is no exc_info in sys.exc_info(). Subsequently, the processors._figure_out_exc_info() function runs the following code:
def _figure_out_exc_info(v: Any) -> ExcInfo:
"""
Depending on the Python version will try to do the smartest thing possible
to transform *v* into an ``exc_info`` tuple.
"""
if isinstance(v, BaseException):
return (v.__class__, v, v.__traceback__)
if isinstance(v, tuple):
return v # type: ignore[return-value]
if v:
return sys.exc_info() # type: ignore[return-value]
return v
Because sys.exc_info() is blank we get tuple with value (None, None, None) and then the following code raises AttributeError, that I showed above.
Tests-related issue:
Furthermore, I noticed that some tests in the structlog library ignore this unexpected behavior. For instance, the tests TestBoundLogger.test_exception_exc_info() and TestFilteringLogger.test_exception() use BoundLogger(ReturnLogger(), [], {}) and do not check this case.
Solution
To address this issue, I would like to create a pull request to fix the problem. However, I would appreciate your advice on the following questions:
- The standard library logging module allows calling logger.exception() without any additional arguments, and it does not raise any exceptions. Should we follow the same behavior in structlog, or maybe should we raise an exception when sys.exc_info() is empty?
- Should I add new tests to ensure that logger.exception("test") works correctly even when there is no additional information about the exception, or should I modify existing tests to cover this case?
Thank you for your attention, and I look forward to your feedback.