Source code for metobs_toolkit.backend_collection.loggingmodule

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Logging utilities for the MetObs Toolkit.

Provides functions to add file and stream handlers to the toolkit logger.

Created on Fri Aug  2 14:23:30 2024

@author: thoverga
"""

import os
import logging
from datetime import datetime
from os import PathLike

from metobs_toolkit.settings_collection.settings import Settings

logger = logging.getLogger("<metobs_toolkit>")


[docs] def add_FileHandler( filepath: str | PathLike, setlvl: str = Settings.get("log_level"), logformat: str = Settings.get("log_format"), clearlog: bool = True, ) -> None: """ Add a FileHandler to the Toolkit logger. A FileHandler directs the logs generated by the `metobs_toolkit` to a file. Parameters ---------- filepath : str | PathLike Path of the target log file. setlvl : {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}, optional The logger level for the FileHandler. See https://docs.python.org/3/library/logging.html#levels for more details. The default is "DEBUG". logformat : str, optional The format of the log messages. The default is "LOG:: %(levelname)s - %(message)s". clearlog : bool, optional If True, the `trglogfile` is cleared before adding the FileHandler. The default is True. Returns ------- None Notes ----- This function checks existing handlers to avoid duplicate FileHandlers for the same file. If a FileHandler already exists for the same file path with the same or more restrictive (higher) log level, no new handler is added. Log levels in order of restrictiveness: DEBUG < INFO < WARNING < ERROR < CRITICAL. """ # Lazy import to avoid circular dependency from metobs_toolkit.io_collection.filewriters import fmt_output_filepath filepath = fmt_output_filepath( filepath=filepath, default_filename="metobs_toolkit.log", overwrite=clearlog ) rootlog = logging.getLogger("<metobs_toolkit>") # Convert target level to numeric value for comparison target_level = getattr(logging, setlvl.upper()) # Normalize the target file path for comparison target_path = os.path.abspath(filepath) # Check if FileHandler already exists for same file at same or higher level for handler in rootlog.handlers: if isinstance(handler, logging.FileHandler): # Compare normalized file paths existing_path = os.path.abspath(handler.baseFilename) if existing_path == target_path and handler.level <= target_level: rootlog.debug( f"FileHandler already exists for file '{filepath}' " f"at level {logging.getLevelName(handler.level)} " f"(<= {setlvl.upper()}). No new FileHandler added." ) return None # Create the Handler for logging data to a file - will be inherited for children file_handler = logging.FileHandler(filename=filepath) file_handler.setLevel(setlvl.upper()) # set handler level # Create a Formatter for formatting the log messages file_logger_formatter = logging.Formatter(logformat) file_handler.setFormatter(file_logger_formatter) # Add the Handler to the Logger rootlog.addHandler(file_handler) # Ensure the root logger level allows messages to reach the handler rootlog.setLevel(logging.DEBUG) rootlog.debug(f"FileHandler set at {datetime.now()}")
[docs] def add_StreamHandler( setlvl: str = Settings.get("log_level"), logformat: str = Settings.get("log_format") ) -> None: """ Add a StreamHandler to the Toolkit logger. A StreamHandler directs the logs generated by the `metobs_toolkit` to `sys.stderr`. Parameters ---------- setlvl : str, optional The logger level for the StreamHandler. Must be one of ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]. See https://docs.python.org/3/library/logging.html#levels for more details. Default is "DEBUG". logformat : str, optional The format string for log messages. Default is "LOG:: %(levelname)s - %(message)s". Returns ------- None Notes ----- This function checks existing handlers to avoid duplicate StreamHandlers. If a StreamHandler already exists with the same or more restrictive (higher) log level, no new handler is added. Log levels in order of restrictiveness: DEBUG < INFO < WARNING < ERROR < CRITICAL. """ # Get rootlogger rootlog = logging.getLogger("<metobs_toolkit>") rootlog.setLevel(logging.DEBUG) # set rootlogger on debug # Convert target level to numeric value for comparison target_level = getattr(logging, setlvl.upper()) # Check if StreamHandler already exists at same or higher level for handler in rootlog.handlers: if isinstance(handler, logging.StreamHandler) and not isinstance( handler, logging.FileHandler ): if handler.level <= target_level: rootlog.debug( f"StreamHandler already exists at level {logging.getLevelName(handler.level)} " f"(<= {setlvl.upper()}). No new StreamHandler added." ) return None # Create StreamHandler streamhandler = logging.StreamHandler() streamhandler.setLevel(setlvl.upper()) stream_logger_formatter = logging.Formatter(logformat) streamhandler.setFormatter(stream_logger_formatter) # Add the Handler to the Logger rootlog.addHandler(streamhandler) rootlog.info(f"StreamHandler set at {datetime.now()}")