Source code for nxbrew_dl.util.log_utils

import logging
import os
import re
import sys
from logging.handlers import RotatingFileHandler

import colorlog
import logredactor

DATE_FMT = "%Y-%m-%d %H:%M:%S"


[docs] class NXBrewLogger(logging.Logger): def __init__( self, name="NXBrew", log_level="INFO", log_dir="log", max_logs=9, ): """Intialise a custom logging class This one will do a nice colorlog out to the terminal, and also save a log to file with sensitive info redacted Args: name (str): The name of the logger. Defaults to "NXBrew". log_level (str): Logging level. Defaults to "INFO" log_dir (str): The directory to save logs to. Defaults to "log" max_logs (int): The maximum number of logs to save. Defaults to 9 """ super().__init__(name, log_level) if log_level.lower() not in ["debug", "info", "critical"]: log_level = "INFO" print(f"Defaulting to {log_level}") self.name = name self.log_level = log_level self.log_dir = log_dir self.max_logs = max_logs self.redact_patterns = [] self.redact_filter = None # Initialise the logger self.propagate = False self.file_handler = None self.console_handler = None self.get_logger()
[docs] def get_logger(self): """Initialise the logging to file, and the GUI logger""" self.setLevel(self.log_level.upper()) self.console_handler = self.get_gui_logger() self.file_handler = self.get_file_logger() # Overwrite previous logger if exists self.handlers.clear() self.addHandler(self.console_handler) self.addHandler(self.file_handler)
[docs] def get_file_logger( self, ): """Initialise logging to a file, moving files if necessary""" # Create the log directory if it doesn't exist if not os.path.exists(self.log_dir): os.makedirs(self.log_dir) # Define the log file path, and sanitize if needs be log_file = os.path.join(self.log_dir, f"{self.name}.log") # Check if log file already exists if os.path.isfile(log_file): for i in range(self.max_logs - 1, 0, -1): old_log = os.path.join(self.log_dir, f"{self.name}.log.{i}") new_log = os.path.join(self.log_dir, f"{self.name}.log.{i + 1}") if os.path.exists(old_log): if os.path.exists(new_log): os.remove(new_log) os.rename(old_log, new_log) os.rename(log_file, os.path.join(self.log_dir, f"{self.name}.log.1")) # Define the log message format for the log files logfile_formatter = logging.Formatter( fmt="[%(asctime)s] %(levelname)s: %(message)s", datefmt=DATE_FMT, ) # Create a RotatingFileHandler for log files handler = RotatingFileHandler( log_file, delay=True, mode="w", backupCount=self.max_logs ) handler.setFormatter(logfile_formatter) self.addHandler(handler) return handler
[docs] def get_gui_logger(self): """Get the GUI logger""" # Set up the handler handler = colorlog.StreamHandler(sys.stdout) handler.setFormatter( colorlog.ColoredFormatter( "%(log_color)s[%(asctime)s] %(levelname)s: %(message)s", datefmt=DATE_FMT, ) ) self.addHandler(handler) return handler
[docs] def update_redact_filter( self, redact_pattern, ): """Update the redact patterns, update the redact filter Args: redact_pattern (str): The regex pattern to redact. Any special regex characters are automatically escaped so this should be input as a literal string """ # Update redact patterns self.redact_patterns.append(re.compile(re.escape(redact_pattern))) # Remove the filter if it already exists if self.redact_filter is not None: self.handlers[1].removeFilter(self.redact_filter) # Create the new filter and add it, but only to the file handler self.redact_filter = logredactor.RedactingFilter( patterns=self.redact_patterns, default_mask="[REDACTED]", ) self.handlers[1].addFilter(self.redact_filter)