文章目录
- 简介
- 安装
- 初试
- 添加Handler, Formatter, Filter
- 循环、保留、压缩
- 捕获异常
- 完整描述异常
- 结构化日志
- 时间格式
- 解析器
- 异步、线程安全、多进程安全
- PyCharm日志插件
- 封装
- 参考文献
简介
loguru,第三方库,轻松记日志,一个函数搞定。
安装
pip install loguru
初试
无需样板即可使用
from loguru import logger
logger.debug('调试消息')
logger.info('普通消息')
logger.warning('警告消息')
logger.error('错误消息')
logger.critical('严重错误消息')
logger.success('成功调用')
添加Handler, Formatter, Filter
无需繁琐地添加,只需要 add()
还原到标准输出 logger.remove()
from loguru import logger
print(logger.add('file_{time}.log', format="{name} {level} {message}", level="INFO", rotation='5 MB', encoding='utf-8')) # 根据时间为日志命名,每5MB新建一个
logger.debug('调试消息')
logger.info('普通消息')
logger.warning('警告消息')
logger.error('错误消息')
logger.critical('严重错误消息')
logger.remove() # 还原到标准输出
logger.debug('调试消息')
logger.info('普通消息')
logger.warning('警告消息')
logger.error('错误消息')
logger.critical('严重错误消息')
产生了新日志文件
循环、保留、压缩
- 循环,rotation,达到指定大小后建新日志。
- 保留,retention,定期清理。
- 压缩,compression,压缩节省空间。
from loguru import logger
logger.add("file_1.log", rotation="500 MB") # 自动循环过大的文件
logger.add("file_2.log", rotation="12:00") # 每天中午创建新文件
logger.add("file_3.log", rotation="1 week") # 一旦文件太旧进行循环
logger.add("file_X.log", retention="10 days") # 定期清理
logger.add("file_Y.log", compression="zip") # 压缩节省空间
查看详细配置
捕获异常
使用catch()
装饰器 或 上下文管理器
- 装饰器
from loguru import logger
@logger.catch
def func(x, y, z):
return 1 / (x + y + z)
if __name__ == '__main__':
func(0, 1, -1)
- 上下文管理器
from loguru import logger
def func(x, y, z):
return 1 / (x + y + z)
with logger.catch():
func(0, 1, -1)
输出
完整描述异常
Loguru允许显示整个堆栈跟踪,包括变量的值(使用了better-exceptions)
添加参数 backtrace=True
和 diagnose=True
from loguru import logger
logger.add('out.log', backtrace=True, diagnose=True, encoding='utf-8') # 注意!可能泄漏敏感数据
def func(a, b):
return a / b
def nested(c):
try:
func(5, c)
except ZeroDivisionError:
logger.exception("What?!")
nested(0)
结构化日志
保存为JSON格式,添加参数 serialize=True
from loguru import logger
logger.add('json.log', serialize=True, encoding='utf-8')
logger.debug('调试消息')
json.log
{"text": "2020-07-22 17:14:13.574 | DEBUG | __main__:<module>:4 - \u8c03\u8bd5\u6d88\u606f\n", "record": {"elapsed": {"repr": "0:00:00.009893", "seconds": 0.009893}, "exception": null, "extra": {}, "file": {"name": "test.py", "path": "D:/code/test/test.py"}, "function": "<module>", "level": {"icon": "\ud83d\udc1e", "name": "DEBUG", "no": 10}, "line": 4, "message": "\u8c03\u8bd5\u6d88\u606f", "module": "test", "name": "__main__", "process": {"id": 104568, "name": "MainProcess"}, "thread": {"id": 86560, "name": "MainThread"}, "time": {"repr": "2020-07-22 17:14:13.574082+08:00", "timestamp": 1595409253.574082}}}
通过 bind()
添加额外属性来结构化日志
from loguru import logger
logger.add("file.log", format="{extra[ip]} {extra[user]} {message}")
context_logger = logger.bind(ip="192.168.0.1", user="someone")
context_logger.info("Contextualize your logger easily")
context_logger.bind(user="someone_else").info("Inline binding of extra attribute")
context_logger.info("Use kwargs to add context during formatting: {user}", user="anybody")
file.log
192.168.0.1 someone Contextualize your logger easily
192.168.0.1 someone_else Inline binding of extra attribute
192.168.0.1 anybody Use kwargs to add context during formatting: anybod
结合 bind(special=True)
和 filter
对日志进行更细粒度的控制
from loguru import logger
logger.add("special.log", filter=lambda record: "special" in record["extra"])
logger.debug("This message is not logged to the file")
logger.bind(special=True).info("This message, though, is logged to the file!")
special.log
2020-07-22 17:06:40.998 | INFO | __main__:<module>:5 - This message, though, is logged to the file!
时间格式
from loguru import logger
logger.add('file.log', format='{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}', encoding='utf-8')
logger.debug('调试消息')
file.log
2020-07-22 17:18:08 | DEBUG | 调试消息
解析器
通常需要从日志中提取特定信息, parse()
可用处理日志和正则表达式。
# -*- coding: utf-8 -*-
from loguru import logger
from dateutil import parser
logger.add('file.log', format='{time} - {level.no} - {message}', encoding='utf-8')
logger.debug('调试消息')
pattern = r'(?P<time>.*) - (?P<level>[0-9]+) - (?P<message>.*)' # 带命名组的正则表达式
caster_dict = dict(time=parser.parse, level=int) # 匹配)
for i in logger.parse('file.log', pattern, cast=caster_dict):
print(i)
# {'time': datetime.datetime(2020, 7, 22, 17, 33, 12, 554282, tzinfo=tzoffset(None, 28800)), 'level': 10, 'message': '璋冭瘯娑堟伅'}
logger.parse()
没有参数 encoding
,本人测试解析中文会乱码
异步、线程安全、多进程安全
默认为线程安全,但不是异步或多进程安全的,添加参数 enqueue=True
即可:
logger.add("somefile.log", enqueue=True)
协程可用 complete()
等待
PyCharm日志插件
安装方法:File → Settings → Plugins → Marketplace 搜 Ideolog
test.log
DEBUG:root:调试信息
INFO:root:普通信息
WARNING:root:警告信息
ERROR:root:错误信息
CRITICAL:root:严重错误信息
2019-12-15 20:17:02 - MainThread - root - DEBUG - DEBUG.
2019-12-15 20:17:02 - MainThread - root - INFO - INFO.
2019-12-15 20:17:02 - MainThread - root - WARNING - WARNING.
2019-12-15 20:17:02 - MainThread - root - ERROR - ERROR.
2019-12-15 20:17:02 - MainThread - root - CRITICAL - CRITICAL.
设置格式
Pattern | Action |
\s*WARNING\s* | Highlight line |
\s*ERROR\s* | Highlight line+stripe |
\s*CRITICAL\s* | Highlight line+stripe |
\s*DEBUG\s* | Highlight line |
显示效果
封装
传入多个参数,一次记日志(str()
换成 repr()
会带上 ''
)
from loguru import logger
logger.add('{time:YYYY-MM-DD HHmmss}.log', format="{message}", rotation='5 MB', encoding='utf-8') # 根据时间为日志命名,每5MB新建一个
def info(*args):
logger.info(' '.join([str(i) for i in args]))
a = ('123', '345', None)
info(*a)
# 123 345 None
参考文献