Skip to content
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

Unexpected handling of exc_info in structlog v24 when using .exception #590

Open
jf2 opened this issue Jan 23, 2024 · 1 comment
Open

Unexpected handling of exc_info in structlog v24 when using .exception #590

jf2 opened this issue Jan 23, 2024 · 1 comment
Labels

Comments

@jf2
Copy link

jf2 commented Jan 23, 2024

Hi.

The new handling of the exception level has introduced a somewhat surprising behaviour.

To reproduce

import sys
import structlog


def custom_exception_processor(logger, name, event_dict):
    if "exc_info" in event_dict:
        exc_type, exc_value, exc_tb = sys.exc_info()
        if exc_value is not None:
            event_dict["event"] = str(exc_value)
        del event_dict["exc_info"]
    return event_dict


structlog.configure(processors=[custom_exception_processor,
                                structlog.stdlib.add_log_level,
                                structlog.stdlib.add_logger_name,
                                structlog.dev.ConsoleRenderer(),
                                structlog.stdlib.ProcessorFormatter.wrap_for_formatter],
                    wrapper_class=structlog.stdlib.BoundLogger,
                    logger_factory=structlog.stdlib.LoggerFactory())
logger = structlog.getLogger("test_logger")
try:
    raise ValueError("test")
except ValueError:
    logger.exception("test", exc_info=True)

I would expect the output to simply read:

[error    ] test                           [test_logger]

Instead, it reads:

[error    ] test                           [test_logger]
Traceback (most recent call last):
  File "inconsistent_exc_info.py", line 23, in <module>
    raise ValueError("test")
ValueError: test

The problem is that the wrapped python logger has a default value of exc_info=True for .exception, which does not get overridden.
Not entirely sure whose responsibility it is (processor or bound logger) to handle this case.

It happens here:

# structlog/_base.py:116 (BoundLoggerBase._process_event)

...
        for proc in self._processors:
            event_dict = proc(self._logger, method_name, event_dict)

        if isinstance(event_dict, (str, bytes, bytearray)):
            return (event_dict,), {}

The returned empty dictionary allows the exc_info to be set to True within the Python logger.

Note that in my reproduction example above, it also does not help if I force the event_dict['exc_info'] = False

Happy to hear your thoughts.

@hynek hynek added the stdlib label Feb 5, 2024
@hynek
Copy link
Owner

hynek commented Feb 5, 2024

Hm, yeah this is a weird interplay that's as you write is not quite clear how it should be resolved.

A short-term fix for you is using error() instead of exception(), I guess.

Looks like we've got a similar problem solve on ProcessorFormatter in the form of keep_exc_info.

My best guess is that it should be an option on stdlib.BoundLogger to treat exc_info differently?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants