Source code for molecular_simulations.logging_config

"""Logging configuration module for molecular_simulations.

This module provides opt-in logging configuration for applications, CLIs,
and examples. Library code should not call this implicitly.
"""

from __future__ import annotations
import logging
import logging.config
import os
import socket
from datetime import datetime


[docs] def configure_logging( level: str | int | None = None, to_file: str | None = None, fmt: str | None = None, ) -> None: """Configure logging for the application. Opt-in configuration for apps/CLIs/examples. Library code should *not* call this implicitly. Args: level: The logging level. Can be a string (e.g., 'INFO', 'DEBUG') or an integer. If None, uses the MS_LOG_LEVEL environment variable or defaults to 'INFO'. to_file: Path to a log file. If None, uses the MS_LOG_FILE environment variable. If neither is set, logs only to console. fmt: Log message format string. If None, uses the MS_LOG_FMT environment variable or a default format including hostname, PID, and MPI rank. Example: >>> configure_logging(level='DEBUG', to_file='simulation.log') """ level = (level or os.getenv("MS_LOG_LEVEL") or "INFO") fmt = fmt or os.getenv("MS_LOG_FMT") or ( "%(asctime)s | %(levelname)s | %(name)s | %(message)s " "[host=%(hostname)s pid=%(process)d rank=%(mpirank)s]" ) class _ContextFilter(logging.Filter): """Filter that adds hostname and MPI rank to log records.""" def filter(self, record: logging.LogRecord) -> bool: """Add context information to the log record. Args: record: The log record to modify. Returns: Always returns True to allow the record to be logged. """ record.hostname = socket.gethostname() # Fill MPI rank if available; else 0 try: from mpi4py import MPI # noqa: WPS433 record.mpirank = MPI.COMM_WORLD.Get_rank() except Exception: record.mpirank = 0 return True handlers = { "console": { "class": "logging.StreamHandler", "level": level, "filters": ["ctx"], "formatter": "standard", } } if to_file or os.getenv("MS_LOG_FILE"): handlers["file"] = { "class": "logging.handlers.RotatingFileHandler", "level": level, "filters": ["ctx"], "formatter": "standard", "filename": to_file or os.getenv("MS_LOG_FILE"), "maxBytes": 10 * 1024 * 1024, "backupCount": 3, "encoding": "utf-8", } config = { "version": 1, "disable_existing_loggers": False, "filters": {"ctx": {"()": _ContextFilter}}, "formatters": {"standard": {"format": fmt}}, "handlers": handlers, "root": {"level": level, "handlers": list(handlers)}, } logging.config.dictConfig(config)