文章目录

  • 简介
  • 安装
  • 初试
  • 添加Handler, Formatter, Filter
  • 循环、保留、压缩
  • 捕获异常
  • 完整描述异常
  • 结构化日志
  • 时间格式
  • 解析器
  • 异步、线程安全、多进程安全
  • PyCharm日志插件
  • 封装
  • 参考文献


简介

loguru,第三方库,轻松记日志,一个函数搞定。

apache python 日志分析 python 日志库_logging


安装

pip install loguru


初试

无需样板即可使用

from loguru import logger

logger.debug('调试消息')
logger.info('普通消息')
logger.warning('警告消息')
logger.error('错误消息')
logger.critical('严重错误消息')
logger.success('成功调用')

apache python 日志分析 python 日志库_日志_02


添加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('严重错误消息')

产生了新日志文件

apache python 日志分析 python 日志库_logging_03


循环、保留、压缩

  • 循环,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)

输出

apache python 日志分析 python 日志库_python_04


完整描述异常

Loguru允许显示整个堆栈跟踪,包括变量的值(使用了better-exceptions

添加参数 backtrace=Truediagnose=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)

apache python 日志分析 python 日志库_logging_05


结构化日志

保存为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

apache python 日志分析 python 日志库_日志_06


显示效果

apache python 日志分析 python 日志库_日志_07


封装

传入多个参数,一次记日志(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


参考文献

  1. Delgan/loguru: Python logging made (stupidly) simple
  2. loguru documentation