From 15cb0c913324dde79f150b7ed8ac9ef1fab018d8 Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Thu, 8 Jan 2026 13:33:06 +0900 Subject: [PATCH 1/2] Harden tracing shutdown logging against closed handlers --- src/agents/tracing/provider.py | 17 +++++++++++ tests/test_tracing_provider_safe_debug.py | 37 +++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/test_tracing_provider_safe_debug.py diff --git a/src/agents/tracing/provider.py b/src/agents/tracing/provider.py index cd37d30ef2..1b91269524 100644 --- a/src/agents/tracing/provider.py +++ b/src/agents/tracing/provider.py @@ -1,5 +1,6 @@ from __future__ import annotations +import logging import os import threading import uuid @@ -17,7 +18,23 @@ def _safe_debug(message: str) -> None: """Best-effort debug logging that tolerates closed streams during shutdown.""" + + def _has_closed_stream_handler(log: logging.Logger) -> bool: + current: logging.Logger | None = log + while current is not None: + for handler in current.handlers: + stream = getattr(handler, "stream", None) + if stream is not None and getattr(stream, "closed", False): + return True + if not current.propagate: + break + current = current.parent + return False + try: + # Avoid emitting debug logs when any handler already owns a closed stream. + if _has_closed_stream_handler(logger): + return logger.debug(message) except Exception: # Avoid noisy shutdown errors when the underlying stream is already closed. diff --git a/tests/test_tracing_provider_safe_debug.py b/tests/test_tracing_provider_safe_debug.py new file mode 100644 index 0000000000..7b4b8bad93 --- /dev/null +++ b/tests/test_tracing_provider_safe_debug.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +import io +import logging + +from agents.tracing.provider import _safe_debug, logger + + +class _CapturingHandler(logging.Handler): + def __init__(self) -> None: + super().__init__() + self.records: list[logging.LogRecord] = [] + + def emit(self, record: logging.LogRecord) -> None: # pragma: no cover - trivial + self.records.append(record) + + +def test_safe_debug_skips_logging_when_handler_stream_closed() -> None: + original_handlers = logger.handlers[:] + original_propagate = logger.propagate + + closed_stream = io.StringIO() + closed_handler = logging.StreamHandler(closed_stream) + closed_stream.close() + + capturing_handler = _CapturingHandler() + + try: + logger.handlers = [closed_handler, capturing_handler] + logger.propagate = False + + _safe_debug("should not log") + + assert capturing_handler.records == [] + finally: + logger.handlers = original_handlers + logger.propagate = original_propagate From 0469f3cf2a8de5c79cd0648c0fab831d123a89bc Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Thu, 8 Jan 2026 13:38:53 +0900 Subject: [PATCH 2/2] fix mypy errors --- tests/test_tracing_provider_safe_debug.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_tracing_provider_safe_debug.py b/tests/test_tracing_provider_safe_debug.py index 7b4b8bad93..d49441171c 100644 --- a/tests/test_tracing_provider_safe_debug.py +++ b/tests/test_tracing_provider_safe_debug.py @@ -3,7 +3,8 @@ import io import logging -from agents.tracing.provider import _safe_debug, logger +from agents.logger import logger +from agents.tracing.provider import _safe_debug class _CapturingHandler(logging.Handler):