"""统一日志系统:按模块分文件,带时间戳和级别,自动滚动。 用法: from core.logger import get_logger log = get_logger("task") # 写 logs/task.log + 控制台 log.info("开始任务") log.error("失败", exc_info=True) 模块划分: core — 核心程序(STF/adb/worker/task_manager) task — 任务执行(worker 业务逻辑) web — web_server 请求/管理 action — 操作执行(点赞/评论等) 所有日志同时输出到控制台和对应文件,logs/ 目录自动创建。 文件按 10MB 滚动,保留 5 个历史文件。 """ import os import logging from logging.handlers import RotatingFileHandler _LOG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "logs") os.makedirs(_LOG_DIR, exist_ok=True) # 已创建的 logger,避免重复添加 handler _LOGGERS = {} # 模块 → 文件名映射 _MODULE_FILES = { "core": "core.log", "task": "task.log", "web": "web.log", "action": "action.log", } _FORMAT = "%(asctime)s [%(levelname)s] [%(name)s] %(message)s" _DATE_FMT = "%Y-%m-%d %H:%M:%S" def get_logger(name="core"): """获取指定模块的 logger。 name: 模块名(core/task/web/action),决定写哪个文件。 也可传子模块名如 "task.generic",会归到 task.log。 返回配置好的 logging.Logger。 """ if name in _LOGGERS: return _LOGGERS[name] # 归类到对应文件:取顶层模块名 top = name.split(".")[0] filename = _MODULE_FILES.get(top, "core.log") log = logging.getLogger(name) log.setLevel(logging.DEBUG) # 避免向 root logger 传播导致重复输出 log.propagate = False fmt = logging.Formatter(_FORMAT, _DATE_FMT) # 文件 handler:10MB 滚动,保留 5 个 file_path = os.path.join(_LOG_DIR, filename) fh = RotatingFileHandler(file_path, maxBytes=10 * 1024 * 1024, backupCount=5, encoding="utf-8") fh.setLevel(logging.DEBUG) fh.setFormatter(fmt) # 控制台 handler ch = logging.StreamHandler() ch.setLevel(logging.INFO) ch.setFormatter(fmt) log.addHandler(fh) log.addHandler(ch) _LOGGERS[name] = log return log # 兼容旧代码的 print 风格:紧急排查时可临时用 def log_print(msg, level="info", module="core"): """print 的替代品,转发到 logging。""" log = get_logger(module) getattr(log, level, log.info)(msg)