Files
deepagents/libs/code/deepagents_code/_debug.py
T
Mason Daugherty 5145ed1f82 fix(code): centralize debug logging setup to package root (#3650)
Move `configure_debug_logging` from individual modules to the package
root in `__init__.py` so all child loggers inherit the same file handler
via propagation. This eliminates duplicate handler attachments when
multiple modules import the debug helper, and makes the logging
configuration idempotent across reloads.
2026-05-28 15:52:22 -04:00

77 lines
2.7 KiB
Python

"""Shared debug-logging configuration for verbose file-based tracing.
When the `DEEPAGENTS_CODE_DEBUG` environment variable is set, modules that handle
streaming or remote communication can enable detailed file-based logging. This
helper centralizes the setup so the env-var name, file path, and format are
defined in one place.
"""
from __future__ import annotations
import logging
import os
import sys
from pathlib import Path
from deepagents_code._env_vars import DEBUG, DEBUG_FILE, is_env_truthy
_DEBUG_HANDLER_ATTR = "_deepagents_code_debug_handler"
def configure_debug_logging(target: logging.Logger) -> None:
"""Attach a file handler to *target* when `DEEPAGENTS_CODE_DEBUG` is set.
Intended to be called once on the `deepagents_code` package logger; child
module loggers reach the same file via propagation, so individual modules do
not configure logging themselves.
The log file defaults to `'/tmp/deepagents_debug.log'` but can be overridden
with `DEEPAGENTS_CODE_DEBUG_FILE`. The handler appends (`mode='a'`) so logs
are preserved across separate process runs. Calling this again with the same
resolved path is a no-op: the existing tagged handler is reused rather than
stacking duplicates. If the resolved path changes, the stale handler is
closed and replaced.
Does nothing when `DEEPAGENTS_CODE_DEBUG` is not truthy (see `is_env_truthy`).
Args:
target: Logger to configure.
"""
if not is_env_truthy(DEBUG):
return
debug_path = Path(
os.environ.get(
DEBUG_FILE,
"/tmp/deepagents_debug.log", # noqa: S108
)
)
for existing in list(target.handlers):
if not (
isinstance(existing, logging.FileHandler)
and getattr(existing, _DEBUG_HANDLER_ATTR, False)
):
continue
if Path(existing.baseFilename) == debug_path:
# Already configured for this path; reuse rather than duplicate.
target.setLevel(logging.DEBUG)
return
# The debug path changed; drop the stale handler before re-attaching so
# we don't leak its file descriptor or fan logs out to two files.
target.removeHandler(existing)
existing.close()
try:
handler = logging.FileHandler(str(debug_path), mode="a")
except OSError as exc:
print( # noqa: T201
f"Warning: could not open debug log file {debug_path}: {exc}",
file=sys.stderr,
)
return
setattr(handler, _DEBUG_HANDLER_ATTR, True)
handler.setLevel(logging.DEBUG)
handler.setFormatter(logging.Formatter("%(asctime)s %(name)s %(message)s"))
target.addHandler(handler)
target.setLevel(logging.DEBUG)