structlog icon indicating copy to clipboard operation
structlog copied to clipboard

Improving make_filtering_bound_logger's compatibility with the stdlib logger

Open segfault opened this issue 3 years ago • 3 comments

While trying to use structlog as a drop in for the stdlib logger usage in slack_bolt, I encountered a variety of errors stemming from missing wrapper implementations.

Error example:

AttributeError: 'BoundLoggerFilteringAtDebug' object has no attribute 'disabled'

The root cause appears to be make_filtering_bound_logger's usage of BoundLoggerBase instead of the fully implemented BoundLogger. BoundLogger itself is missing the filters wrapper, but that is trivial to fix. BoundLoggerBase is missing all of the wrapper logic and that appears intentional.

With an analog to BoundLogger implemented I am able to use structlog as a drop-in replacement for the standard logger.

I'll be tying in a pull request with a proposed solution.

segfault avatar Nov 14 '22 02:11 segfault

Let's discuss this here, before delving into #470.

What you're doing there is basically re-implementing parts of our stdlib integration.

I'm sympathetic to wanting a true drop-in replacement, but that's what literally what https://www.structlog.org/en/latest/api.html#structlog.stdlib.BoundLogger is for (along with all the goodies).


If you want to gradually switch away from stdlib APIs, but use the faster loggers from make_filtering_bound_logger now, I would suspect the best way would be to create a logger using make_filtering_bound_logger and then add stub methods that can still be called, but don't do any anything.

Does that make sense? Essentially:

import structlog
import logging


FL = structlog.make_filtering_bound_logger(logging.INFO)


class StubFilteringLogger(FL):
    @property
    def disabled(self):
        return False


structlog.configure(wrapper_class=StubFilteringLogger)

logger = structlog.get_logger()

logger.info("hi", disabled=logger.disabled)

I might be open to add such a stub logger to structlog, but I'm not sure if it's possible those stubs make universally useful?

hynek avatar Nov 14 '22 08:11 hynek

So my intent was to we-use the existing implementation instead of mirroring the behavior in order to get something that would be performant when filtering leveled log messages but compatible with stdlib logger use I'm encountering "in the wild".

I started with generating my ownStubFilteringLogger but quickly found myself effectively re-implementing everything in stdlib.BoundLogger.

Alternatively would a make_filtering_stdlib_bound_logger be acceptable? Ultimately the intent here is just to swap the base class and hopefully use all of the same existing well-optimized/tested code.

segfault avatar Nov 14 '22 15:11 segfault

I should note that my use case here isn't gradual replacement. It's supporting third party libraries and frameworks that use the stdlib logger interface. If I had control I'd just use structlog natively everywhere.

segfault avatar Nov 14 '22 15:11 segfault