AttributeError: 'BytesLogger' object has no attribute 'name'
There is an example at https://www.structlog.org/en/25.4.0/performance.html about how to use structlog with orjson:
import logging
import orjson
import structlog
structlog.configure(
cache_logger_on_first_use=True,
wrapper_class=structlog.make_filtering_bound_logger(logging.INFO),
processors=[
structlog.contextvars.merge_contextvars,
structlog.processors.add_log_level,
structlog.processors.format_exc_info,
structlog.processors.TimeStamper(fmt="iso", utc=True),
structlog.processors.JSONRenderer(serializer=orjson.dumps),
],
logger_factory=structlog.BytesLoggerFactory(),
)
And it works perfectly:
log = structlog.get_logger('my_logger')
log.info('test') # prints {"event":"test","level":"info","timestamp":"2025-07-18T07:58:55.479135Z"}
However, if I add processor structlog.stdlib.add_logger_name to include logger name it stops working:
Traceback (most recent call last):
File "/home/kxepal/projects/example.py", line 20, in <module>
log.info('test')
File "/home/kxepal/projects/venv/lib/python3.12/site-packages/structlog/_native.py", line 144, in meth
return self._proxy_to_logger(name, event, **kw)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kxepal/projects/venv/lib/python3.12/site-packages/structlog/_base.py", line 222, in _proxy_to_logger
args, kw = self._process_event(method_name, event, event_kw)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kxepal/projects/venv/lib/python3.12/site-packages/structlog/_base.py", line 173, in _process_event
event_dict = proc(self._logger, method_name, event_dict)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kxepal/projects/venv/lib/python3.12/site-packages/structlog/stdlib.py", line 832, in add_logger_name
event_dict["logger"] = logger.name
^^^^^^^^^^^
AttributeError: 'BytesLogger' object has no attribute 'name'
Full example to reproduce an issue:
import logging
import orjson
import structlog
structlog.configure(
cache_logger_on_first_use=True,
wrapper_class=structlog.make_filtering_bound_logger(logging.INFO),
processors=[
structlog.stdlib.add_logger_name,
structlog.contextvars.merge_contextvars,
structlog.processors.add_log_level,
structlog.processors.format_exc_info,
structlog.processors.TimeStamper(fmt="iso", utc=True),
structlog.processors.JSONRenderer(serializer=orjson.dumps),
],
logger_factory=structlog.BytesLoggerFactory(),
)
log = structlog.get_logger('my_logger')
log.info('test')
How would I get logger name into records using BytesLoggerFactory?
Generally speaking, you can't use processors from the stdlib module if you don't use stdlib integration.
Looking at the code after years, the logic is a bit convoluted in order to stay consistent with stdlib: we currently pass the name of the logger to logging.Logger and subsequently look at the logger.
We probably should feed the name into initial_values instead, but I'm not sure how to do that in a backwards-compatible way, though. :(
So it's probably easier to do something like this, even tho it makes me wanna throw up:
diff --git src/structlog/_output.py src/structlog/_output.py
index b1612de..0be1eeb 100644
--- src/structlog/_output.py
+++ src/structlog/_output.py
@@ -256,12 +256,15 @@ class BytesLogger:
.. versionadded:: 20.2.0
"""
- __slots__ = ("_file", "_flush", "_lock", "_write")
+ __slots__ = ("_file", "_flush", "_lock", "_write", "name")
- def __init__(self, file: BinaryIO | None = None):
+ def __init__(
+ self, file: BinaryIO | None = None, *, name: str | None = None
+ ):
self._file = file or sys.stdout.buffer
self._write = self._file.write
self._flush = self._file.flush
+ self.name = name
self._lock = _get_lock_for_file(self._file)
@@ -345,4 +348,4 @@ class BytesLoggerFactory:
self._file = file
def __call__(self, *args: Any) -> BytesLogger:
- return BytesLogger(self._file)
+ return BytesLogger(self._file, name=args[0])