Skip to content
Open
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
24 changes: 20 additions & 4 deletions launch/utilities/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,25 @@
import io, sys
from rich.console import Console

# A fresh TextIOWrapper around sys.stdout.buffer per setup_logger call closes
# the underlying buffer (= process stdout) once the wrapper is garbage
# collected after clean_logger removes the handler. The next setup_logger call
# in the same process (e.g. the organize stage after the setup stage) then
# fails with "ValueError: I/O operation on closed file". Share a single,
# never-collected console instead.
_shared_console: Console | None = None


def _get_shared_console() -> Console:
global _shared_console
if _shared_console is None:
# Wrap stdout in a UTF-8 TextIOWrapper; replace any bad chars defensively
utf8_stdout = io.TextIOWrapper(
sys.stdout.buffer, encoding="utf-8", errors="replace"
)
_shared_console = Console(file=utf8_stdout, soft_wrap=True)
return _shared_console


def setup_logger(instance_id: str, log_file: Path | list[Path], printing: bool = True) -> logging.Logger:
"""
Expand Down Expand Up @@ -43,10 +62,7 @@ def setup_logger(instance_id: str, log_file: Path | list[Path], printing: bool =
# logger.addHandler(ch)
# add rich handler
if printing:
# Wrap stdout in a UTF-8 TextIOWrapper; replace any bad chars defensively
utf8_stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
console = Console(file=utf8_stdout, soft_wrap=True)
rh = RichHandler(console=console, rich_tracebacks=True, show_path=False)
rh = RichHandler(console=_get_shared_console(), rich_tracebacks=True, show_path=False)
rh.setLevel(logging.INFO)
logger.addHandler(rh)
return logger
Expand Down