8.0 KiB
8.0 KiB
MyLog 日志系统技术文档
本文档描述了一个基于 Python 的轻量级日志管理系统 MyLog 与 LogMan,用于实现灵活的日志记录和分类控制。该系统支持多类别日志输出、动态注册日志处理器,并结合全局数据管理模块 public_data 实现单例模式的日志管理。
目录
概述
本日志系统提供以下功能:
- 支持按日志级别/类别(如
SYSError,APPInfo,DEBUG1等)进行过滤。 - 可动态添加、删除或修改日志处理器(logger)。
- 使用统一入口函数
mylog()记录消息。 - 日志自动写入文件
./log/my.log。 - 基于
public_data全局变量存储日志管理器实例,避免重复初始化。
依赖模块
| 模块名 | 用途说明 |
|---|---|
os |
路径拼接、文件操作 |
datetime |
获取当前时间用于日志时间戳 |
PublicData |
全局数据容器,保存共享对象(如 ProgramPath, mylog 实例) |
folderUtils.mkdir |
自动创建目录(确保日志目录存在) |
⚠️ 注意:
PublicData和folderUtils是项目自定义模块,需保证其可用性。
核心常量
AllCatelogs = [
'SYSError',
'SYSWarn',
'APPError',
'APPWarn',
'APPInfo',
'DEBUG1',
'DEBUG2',
'DEBUG3',
'DEBUG4',
'DEBUG5',
]
- 作用:预定义所有允许的日志类别(日志等级/标签)。
- 说明:
- 分为系统级 (
SYS*) 和应用级 (APP*)。 DEBUG1到DEBUG5可用于不同级别的调试信息输出。- 所有日志操作必须使用这些类别之一,否则将被忽略。
- 分为系统级 (
类说明
MyLog
一个简单的日志写入类,负责将日志消息追加到指定路径的文件中。
构造函数
def __init__(self, path)
- 参数:
path(str): 日志根目录路径,默认为'.'(当前目录)
方法
setLogPath(path='.')
设置日志存储路径,并自动创建 log 子目录。
- 参数:
path(str): 新的日志根目录路径
- 行为:
- 将路径保存至
self.myLogPath - 创建
{path}/log/目录(若不存在)
- 将路径保存至
- 注意:此方法存在逻辑错误 —— 缩进问题导致
logp和mkdir(logp)不在方法体内(见注意事项)
__call__(msg='')
使对象可调用,用于写入一条日志。
- 参数:
msg(str): 要写入的消息
- 行为:
- 构造日志文件路径:
{self.myLogPath}/log/my.log - 以追加模式打开文件
- 写入格式化的时间戳 + 消息
- 关闭文件
- 构造日志文件路径:
- 时间格式:
YYYY-MM-DD HH:MM:SS <message>
示例输出:
2025-04-05 10:30:45 User login successful
LogMan(日志管理器)
用于集中管理和分发日志消息到多个日志处理器(logger),支持基于类别的条件触发。
构造函数
def __init__()
- 初始化两个属性:
self.logers: 字典,存储注册的日志处理器self.catelogs: 当前允许的日志类别列表(初始为AllCatelogs)
方法
addCatelog(catelog)
添加新的日志类别到允许列表。
- 参数:
catelog(str): 要添加的类别名称
- 行为:
- 若类别不在
self.catelogs中,则追加
- 若类别不在
addLoger(name, func, catelog)
注册一个新的日志处理器。
- 参数:
name(str): 处理器唯一标识名func(callable): 可调用对象(如MyLog实例),用于实际写日志catelog(str 或 list of str): 此处理器监听的日志类别
- 行为:
- 若
catelog非列表,则转换为列表 - 过滤掉不在
self.catelogs中的非法类别 - 构建日志器字典并存入
self.logers[name]
- 若
delLoger(name)
删除已注册的日志处理器。
- 参数:
name(str): 要删除的日志处理器名称
- 行为:
- 若存在则从
self.logers中移除
- 若存在则从
setCatelog(name, catelog)
更改某个日志处理器所监听的类别。
- 参数:
name(str): 已注册的日志处理器名称catelog(str 或 list of str): 新的监听类别
- 行为:
- 类别合法性检查与过滤后更新配置
__call__(msg='', catelog='APPInfo')
使对象可调用,作为日志分发中心。
- 参数:
msg(str): 日志内容catelog(str): 日志所属类别(默认'APPInfo')
- 行为:
- 遍历所有注册的日志处理器
- 如果该处理器监听了当前
catelog,则调用其func(msg)
- 用途:实现“发布-订阅”式日志分发机制
函数说明
mylog(s, catelog='APPInfo')
全局日志接口函数,用户应通过此函数记录日志。
参数
s(str): 日志消息catelog(str): 日志类别(必须是AllCatelogs中的一项)
返回值
- 返回
LogMan.__call__()的结果(无显式返回值)
行为流程
- 尝试从
public_data获取已存在的logman实例 - 若未找到:
- 获取程序运行路径
ProgramPath(也来自public_data) - 若路径不存在,抛出异常
- 创建
MyLog实例,指向该路径 - 创建
LogMan实例 - 注册名为
'mylog'的日志处理器,绑定MyLog实例,并监听所有类别 - 将
logman实例存回public_data,实现单例
- 获取程序运行路径
- 调用
logman(s, catelog)分发日志
✅ 优点:首次调用自动初始化,后续调用复用实例,线程不安全但适用于单线程场景。
使用示例
# 记录一条普通应用信息
mylog("程序启动完成")
# 记录警告信息
mylog("磁盘空间不足", catelog='APPWarn')
# 记录系统错误
mylog("数据库连接失败", catelog='SYSError')
# 记录调试信息
mylog("变量x的值为: 123", catelog='DEBUG2')
日志将写入文件:./log/my.log,内容类似:
2025-04-05 10:30:45 程序启动完成
2025-04-05 10:31:12 磁盘空间不足
2025-04-05 10:31:15 数据库连接失败
2025-04-05 10:31:16 变量x的值为: 123
注意事项
-
❗ 缩进错误:
def setLogPath(self, path='.'): self.myLogPath = path logp = os.path.join(path, 'log') mkdir(logp)上述代码中
logp=...和mkdir(...)不在方法体内部!这会导致语法错误或运行时错误。
✅ 正确写法应为:def setLogPath(self, path='.'): self.myLogPath = path logp = os.path.join(path, 'log') mkdir(logp) -
📁 目录权限:
- 确保程序对目标路径有写权限,否则
open()将失败。
- 确保程序对目标路径有写权限,否则
-
🔐 线程安全:
- 当前实现未考虑多线程并发写日志的问题,可能造成日志混乱。
- 建议在高并发环境下增加文件锁或改用标准库
logging模块。
-
💾 性能考量:
- 每次写日志都打开/关闭文件,频繁 I/O 可能影响性能。
- 可优化为缓存文件句柄或异步写入。
-
🔧 扩展建议:
- 支持按日期分割日志文件(如
my_2025-04-05.log) - 添加日志级别阈值控制(如仅输出
>= APPWarn的日志) - 替换为 Python 标准
logging模块以获得更强大功能
- 支持按日期分割日志文件(如
总结
本日志系统虽然简单,但具备基本的分类、注册、分发能力,适合小型项目快速集成。通过 public_data 实现了全局单例管理,降低了使用复杂度。但在健壮性、性能和可维护性方面仍有提升空间。
建议在生产环境中替换为 Python 内置的 logging 模块,或在此基础上完善异常处理与资源管理机制。