mirror of
https://github.com/langchain-ai/deepagents.git
synced 2026-08-27 02:41:20 -04:00
5145ed1f82
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.
77 lines
2.7 KiB
Python
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)
|