Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions shared/logging/src/airflow_shared/logging/structlog.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,24 +203,38 @@ def maker(logger: WrappedLogger, *args, **kwargs):
return maker


# structlog >= 26.1.0 added a `name` slot + kwarg to BytesLogger
# (hynek/structlog#786). Detect it once so we can avoid a redundant slot and
# forward `name` through the parent init. The same detection is applied to
# WriteLogger so the analogous upstream change lands without a regression.
_BYTES_LOGGER_HAS_NAME = "name" in getattr(structlog.BytesLogger, "__slots__", ())
_WRITE_LOGGER_HAS_NAME = "name" in getattr(structlog.WriteLogger, "__slots__", ())


class NamedBytesLogger(structlog.BytesLogger):
__slots__ = ("name",)
__slots__ = () if _BYTES_LOGGER_HAS_NAME else ("name",)

def __init__(self, name: str | None = None, file: BinaryIO | None = None):
self.name = name
if file is not None:
file = make_file_io_non_caching(file)
super().__init__(file)
if _BYTES_LOGGER_HAS_NAME:
super().__init__(file, name=name) # type: ignore[call-arg]
else:
super().__init__(file)
self.name = name


class NamedWriteLogger(structlog.WriteLogger):
__slots__ = ("name",)
__slots__ = () if _WRITE_LOGGER_HAS_NAME else ("name",)

def __init__(self, name: str | None = None, file: TextIO | None = None):
self.name = name
if file is not None:
file = make_file_io_non_caching(file)
super().__init__(file)
if _WRITE_LOGGER_HAS_NAME:
super().__init__(file, name=name) # type: ignore[call-arg]
else:
super().__init__(file)
self.name = name


LogOutputType = TypeVar("LogOutputType", bound=TextIO | BinaryIO)
Expand Down
21 changes: 21 additions & 0 deletions shared/logging/tests/logging/test_structlog.py
Original file line number Diff line number Diff line change
Expand Up @@ -707,3 +707,24 @@ def test_dict_positional_arg_formatting(structlog_config, get_logger, message, a

written = json.load(bio)
assert written["event"] == expected_event


def test_named_bytes_logger_preserves_name():
"""
structlog 26.1.0 (hynek/structlog#786) gives ``BytesLogger`` its own ``name``
slot and sets ``self.name`` in ``__init__``; older releases do not. This test
runs against whichever version is installed and pins the contract that the
supplied name survives construction on both.
"""
from airflow_shared.logging.structlog import NamedBytesLogger

assert NamedBytesLogger("my.logger").name == "my.logger"
assert NamedBytesLogger().name is None


def test_named_write_logger_preserves_name():
"""Same contract for NamedWriteLogger in case structlog mirrors #786 for WriteLogger."""
from airflow_shared.logging.structlog import NamedWriteLogger

assert NamedWriteLogger("my.logger").name == "my.logger"
assert NamedWriteLogger().name is None
Loading