__author__ = 'Wendell Jones' import logging from logging.handlers import RotatingFileHandler import time from datetime import datetime, timedelta import os from glob import glob import math as m class Logger: def __init__(self): pass def __del__(self): pass class LPrint: def __init__(self, log_dir, force_rotate): self.log_dir = log_dir self.logfile = os.path.join(log_dir, 'dbsync.log') self.setup_logfile() self.cleanup_old_logs() self.check_log_size(force_rotate) def setup_logfile(self): """Ensure the logfile exists and is ready for use.""" os.makedirs(self.log_dir, exist_ok=True) with open(self.logfile, 'a'): os.utime(self.logfile, None) def cleanup_old_logs(self): """Remove log files older than 14 days.""" logfile_list = glob(f'{self.logfile}.*') date_limit = datetime.today() - timedelta(days=14) for log in logfile_list: timestamp = datetime.fromtimestamp(os.path.getmtime(log)) if timestamp < date_limit: os.remove(log) def check_log_size(self, force_rotate): """Check the log file size and rotate if necessary.""" log_size = os.path.getsize(self.logfile) print(f'Logfile Size: {log_size} ({self.humanbytes(log_size)})') if force_rotate or log_size > 10_000_000: # 10 MB self.rotate_logs() def rotate_logs(self): """Rotate the log file.""" from logrotater import LogRotate # Assuming logrotater is a custom module rotater = LogRotate(prefix=self.logfile, verbose=True) try: rotater.rotate() except FileExistsError as e: print(f'Unable to overwrite archive log: {e}. Deleting old logs.') for log in glob(f'{self.logfile}.*'): try: os.remove(log) except Exception as e: print(f'Unable to delete {log}: {e}') def start_log(self): """Initialize logging.""" logging.basicConfig(filename=self.logfile, level=logging.DEBUG) def logprint(self, loglevel, logmessage): """Log a message with a timestamp.""" logstamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') log_message = f'{logstamp}: {logmessage}' loglevel = loglevel.lower() if loglevel == 'debug': logging.debug(log_message) elif loglevel == 'warning': logging.warning(log_message) elif loglevel == 'info': logging.info(log_message) else: logging.error(f'Unknown log level: {loglevel}. Message: {logmessage}') def screenprint(self, loglevel, logmessage): """Log a message with a timestamp.""" logstamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') log_message = f'{logstamp}: {logmessage}' loglevel = loglevel.lower() if loglevel == 'debug': logging.debug(log_message) print(f"{log_message}") elif loglevel == 'warning': logging.warning(log_message) print(f"{log_message}") elif loglevel == 'info': logging.info(log_message) print(f"{log_message}") else: logging.error(f'Unknown log level: {loglevel}. Message: {logmessage}') def create_rotating_log(self, logpath, max_bytes=10_000_000, backup_count=5): """Create a rotating log handler.""" logger = logging.getLogger("Rotating Log") logger.setLevel(logging.INFO) handler = RotatingFileHandler(logpath, maxBytes=max_bytes, backupCount=backup_count) logger.addHandler(handler) @staticmethod def humanbytes(size, binary=False, precision=2): """Convert bytes to a human-readable format.""" multiples = ["B", "k{}B", "M{}B", "G{}B", "T{}B", "P{}B", "E{}B", "Z{}B", "Y{}B"] base = 1024 if binary else 1000 multiple = m.trunc(m.log2(size) / m.log2(base)) if size > 0 else 0 value = size / m.pow(base, multiple) if size > 0 else 0 suffix = multiples[multiple].format("i" if binary else "") return f"{value:.{precision}f} {suffix}" def __del__(self): pass