chemgraph-loop / src /chemgraph /utils /logging_config.py
rockyaaos's picture
ChemGraph Loop: guarded real-agent API (EMT/TBLite single-point energy)
c509967 verified
Raw
History Blame Contribute Delete
3.04 kB
import logging
import sys
import warnings
_LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
def setup_logger(name=None, level=logging.INFO):
"""Set up a logger with consistent formatting.
This function configures a logger with a standard format that includes
timestamp, logger name, log level, and message. It ensures that handlers
are not duplicated if the logger already exists.
Parameters
----------
name : str, optional
Logger name. If None, returns the root logger, by default None
level : int, optional
Logging level (e.g., logging.INFO, logging.DEBUG), by default logging.INFO
Returns
-------
logging.Logger
Configured logger instance with the specified name and level
Notes
-----
The logger format includes:
- Timestamp
- Logger name
- Log level
- Message
"""
logger = logging.getLogger(name)
if not logger.handlers: # Only add handler if none exists
handler = logging.StreamHandler(sys.stderr)
formatter = logging.Formatter(_LOG_FORMAT)
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(level)
# Prevent double logging when the root logger is also configured by callers (e.g., Streamlit).
logger.propagate = False
return logger
def configure_logging(level: int = logging.WARNING) -> None:
"""Set the log level for all ``chemgraph.*`` loggers.
Call this once early in the CLI entry point to control verbosity
for the entire package. The level applies to the ``"chemgraph"``
namespace logger and is propagated to every already-created child
logger (e.g. ``chemgraph.models.openai``,
``chemgraph.graphs.single_agent``).
Parameters
----------
level : int
A :mod:`logging` level constant (e.g. ``logging.WARNING``,
``logging.INFO``, ``logging.DEBUG``).
"""
# Configure the root "chemgraph" namespace logger.
root = logging.getLogger("chemgraph")
root.setLevel(level)
if not root.handlers:
handler = logging.StreamHandler(sys.stderr)
formatter = logging.Formatter(_LOG_FORMAT)
handler.setFormatter(formatter)
root.addHandler(handler)
# Propagate the level to any already-created child loggers so that
# modules imported before this call also respect the new level.
manager = logging.Logger.manager
for name, logger_ref in manager.loggerDict.items():
if isinstance(logger_ref, logging.Logger) and name.startswith("chemgraph."):
logger_ref.setLevel(level)
for handler in logger_ref.handlers:
handler.setLevel(level)
# Suppress noisy third-party warnings when not in verbose mode.
if level > logging.INFO:
warnings.filterwarnings("ignore", category=UserWarning, module=r"langchain.*")
else:
# Re-enable if user asks for verbose output.
warnings.filterwarnings("default", category=UserWarning, module=r"langchain.*")