import os from pathlib import Path from datetime import datetime, timedelta import logging from logging.handlers import RotatingFileHandler import inspect from PubLibrary.InifileHelper import IniRead # 全局配置 console_output = IniRead('system', 'console_output', '1') log_level = IniRead('system', 'algo_log_level', 'INFO') log_once_cache = set() logger_cache = {} LOG_RETENTION_DAYS = 3 LOG_PATH_STR = IniRead('system', 'algo_log_path', "d:/Program Files/64chn_Decoder/logs") LOG_DIR = Path(LOG_PATH_STR) # 自动补全路径分隔符,创建目录(不存在则新建,避免写日志报错) LOG_DIR.mkdir(parents=True, exist_ok=True) # 如需字符串格式路径 LOG_DIR_STR = str(LOG_DIR) + "\\" LOG_FILE_PREFIX = 'algo_log_' # 日志格式:时间 - 日志器名 - 级别 - 文件名:行号 - 函数名 - 日志内容 LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' DATE_FORMAT = '%Y-%m-%d %H:%M:%S' def clean_old_logs(): """清理超过指定天数的旧日志文件""" try: if not os.path.exists(LOG_DIR): return expire_date = datetime.now() - timedelta(days=LOG_RETENTION_DAYS) for filename in os.listdir(LOG_DIR): if not filename.startswith(LOG_FILE_PREFIX) or not filename.endswith('.log'): continue date_str = filename[len(LOG_FILE_PREFIX):-4] try: file_date = datetime.strptime(date_str, '%Y-%m-%d') if file_date < expire_date: file_path = os.path.join(LOG_DIR, filename) os.remove(file_path) print(f"清理过期日志: {file_path}") except ValueError: continue except Exception as e: print(f"清理旧日志异常: {str(e)}") def init_module_logger(logger_name): """初始化日志器 + 清理旧日志""" os.makedirs(LOG_DIR, exist_ok=True) clean_old_logs() current_date = datetime.now().strftime("%Y-%m-%d") log_file = os.path.join(LOG_DIR, f"{LOG_FILE_PREFIX}{current_date}.log") if logger_name in logger_cache: return logger_cache[logger_name] logger = logging.getLogger(logger_name) logger.setLevel(log_level) if logger.handlers: logger_cache[logger_name] = logger return logger # 文件输出处理器 file_handler = RotatingFileHandler( log_file, maxBytes=10 * 1024 * 1024, backupCount=10, encoding='utf-8' ) formatter = logging.Formatter(LOG_FORMAT, datefmt=DATE_FORMAT) file_handler.setFormatter(formatter) logger.addHandler(file_handler) # 控制台输出 if console_output: console_handler = logging.StreamHandler() console_handler.setFormatter(formatter) logger.addHandler(console_handler) logger_cache[logger_name] = logger return logger def algo_log(content, level="INFO", record_once=False): """ 日志入口函数 自动记录:调用文件名、代码行号、所在函数 """ # 回溯栈帧,获取真正调用 algo_log 的代码位置 # f_back(1) -> algo_log 自身,f_back(2) -> 业务调用处 frame = inspect.currentframe().f_back.f_back if not frame: file_name = "unknown" else: file_name = os.path.basename(frame.f_code.co_filename) logger = init_module_logger(file_name) # 单次日志去重 if record_once: log_key = f"{level.upper()}_{content}" if log_key in log_once_cache: return log_once_cache.add(log_key) # 日志级别分发 level_upper = level.upper() log_map = { "DEBUG": logger.debug, "WARNING": logger.warning, "ERROR": logger.error, "FATAL": logger.fatal, "INFO": logger.info } log_func = log_map.get(level_upper, logger.info) log_func(content)