Skip to content

Traceback when using stdlib.filter_by_level with Python Standard Logging Library #542

@abramjstamper

Description

@abramjstamper

Just started using structlog recently; I've have found it's a great library to work with. Appreciate your all your hard work!

I'm using it both for internal logging library and for formatting the root python logging library's messages. Both are printing JSON to stdout. I get a traceback when I try to use structlog.stdlib.filter_by_level. Actually, I run into several similar tracebacks for several processors from the structlog.stdlib library. With these processors commented out, I am able to successfully encode JSON logs to the console from 3rd party libraries using the built in Python logger.

However, I was hoping to utilize the additional processors listed in the documentation. I checked for similar issues in GH and the documentation on integrating with the stdlib python logger, but didn't find any solutions. I'm hoping to understand if there was any insight here on something I'm doing wrong - configuring the python standard library to use structlog or if I'm using the processors incorrectly? Otherwise, I think this might be a bug with structlog.

After some review of the stack trace, I think the issue may comes from isEnabeldFor not being available on whatever object structlog.stdlib.ProcessorFormatter provides as it seems to only exist on structlog.stdlib.BoundLogger.

dev:api logs  api:   File "/root/.pyenv/versions/3.8.12/lib/python3.8/logging/__init__.py", line 1085, in emit
dev:api logs  api:     msg = self.format(record)
dev:api logs  api:   File "/root/.pyenv/versions/3.8.12/lib/python3.8/logging/__init__.py", line 929, in format
dev:api logs  api:     return fmt.format(record)
dev:api logs  api:   File "/root/.pyenv/versions/3.8/lib/python3.8/site-packages/structlog/stdlib.py", line 1046, in format
dev:api logs  api:     ed = p(logger, meth_name, ed)
dev:api logs  api:   File "/root/.pyenv/versions/3.8/lib/python3.8/site-packages/structlog/stdlib.py", line 744, in filter_by_level
dev:api logs  api:     if logger.isEnabledFor(_NAME_TO_LEVEL[method_name]):
dev:api logs  api: AttributeError: 'NoneType' object has no attribute 'isEnabledFor'

I'm attempting to configure it like this for each logger instance respectively.

# internal application logging
internal_processors = [
    structlog.contextvars.merge_contextvars,
    structlog.processors.add_log_level,
    structlog.processors.UnicodeDecoder(),
    structlog.processors.StackInfoRenderer(),
    structlog.processors.dict_tracebacks,
    structlog.processors.TimeStamper(fmt="iso", utc=True),
    structlog.processors.EventRenamer(to="message"),
    structlog.processors.CallsiteParameterAdder(<omitted>),
    structlog.processors.JSONRenderer(serializer=dumps)
]

structlog.configure(
    cache_logger_on_first_use=True,
    wrapper_class=structlog.make_filtering_bound_logger(20),
    processors=internal_processors,
    logger_factory=structlog.BytesLoggerFactory(),
)


# stdlib python logging
formatter = structlog.stdlib.ProcessorFormatter(
    processors=[
        structlog.stdlib.PositionalArgumentsFormatter(),
        # structlog.stdlib.filter_by_level,
        structlog.stdlib.add_log_level,
        structlog.stdlib.add_logger_name,
        # structlog.stdlib.ExtraAdder,
        # structlog.stdlib.StackInfoRenderer,
        structlog.processors.TimeStamper(fmt="iso", utc=True),
        structlog.processors.EventRenamer(to="message"),
        structlog.stdlib.ProcessorFormatter.remove_processors_meta,
        structlog.processors.JSONRenderer(),
    ],
)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
root_logger = logging.getLogger()
root_logger.addHandler(handler)
root_logger.setLevel(logging.INFO)```

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions