Files
bci_algo/logs/log.py
2026-06-11 08:04:08 +08:00

122 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)