Python 日志记录-loguru

Python 日志记录-loguru

使用logging模块时

用python写代码时,logging模块最基本的几行配置,如下:

import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

logger.info('this is another debug message')
logger.warning('this is another debug message')
logger.error('this is another debug message')
logger.info('this is another debug message')

执行结果如下:
img

引言 loguru

如果想更简洁,可用loguru库

loguru默认的输出格式是上面的内容,有时间、级别、模块名、行号以及日志信息,不需要手动创建 logger,直接使用即可,另外其输出还是彩色的,看起来会更加友好。

官方文档

安装

pip install loguru
1

日志级别

Level name Severity value Logger method
TRACE 5 logger.trace
DEBUG 10 logger.debug
INFO 20 logger.info
SUCCESS 25 logger.success
WARNING 30 logger.warning
ERROR 40 logger.error
CRITICAL 50 logger.critical

简单测试下

from loguru import logger

logger.debug("debug")
logger.info("info")
logger.success("success")
logger.warning("warning")
logger.error("error")
logger.critical("critical")
12345678

输出结果

img

logger.add()
#参数:
  sys.stdout-在控制台输出,如果不想在控制台输出,直接写文件名即可 ../haha.log
  level:日志的级别。 debug,info,warning,error
  encoding='utf-8' 如果输出日志到文件中时,需要指定此参数
  format:日志的输出格式'[{time}][{level}][{file}:line{line}:function_name:{function}] || mesg = {message}'
  enqueue:什么方式写日志 True为异步,false为同步
  rotation:超过多少就生成一个新的日志文件,可设置大小
  retention:多长时间后会删除以前产生的日志,当前的日志不会受影响

特性

简介

此函数应用于注册接收器,这些接收器负责管理使用记录字典上下文化的日志消息。接收器可以采用多种形式:简单函数、字符串路径、类似文件的对象、协程函数或内置处理程序。

请注意:可以使用remove()函数来删除以前添加的处理程序。

例子:

import sys
from loguru import logger


logger.add("test.log", format="{time} {level} {message}", filter="", level="INFO", encoding="utf-8")
logger.debug("debug")
logger.info("info")
logger.success("success")
logger.warning("warning")
logger.error("error")
logger.critical("critical")
1234567891011

效果,输出日志到test.log文件

2022-07-27T17:14:36.393072+0800 INFO info
2022-07-27T17:14:36.394068+0800 SUCCESS success
2022-07-27T17:14:36.395066+0800 WARNING warning
2022-07-27T17:14:36.396063+0800 ERROR error
2022-07-27T17:14:36.397060+0800 CRITICAL critical
12345

rotation/retension/compression

官方介绍:loguru.logger — loguru documentation

rotation:指示何时应关闭当前记录的文件并创建新文件,可以是文件大小/每天的时间点/时间间隔等。

logger.add("test1.log", rotation="500 MB") # 日志文件超过500M创建新的文件
logger.add("test2.log", rotation="12:00")  # 每天中午12点创建新的日志文件
logger.add("test3.log", rotation="1 week") # 当前使用的日志文件超过1周,创建新的日志文件
123

retension:指示合适应该删除旧文件。

logger.add("test4.log", retention="10 days") # 超过十天的日志文件删除
1

compression:日志文件在关闭时应转换为的压缩或归档格式。

logger.add("test5.log", compression="zip") # 日志文件关闭后,使用zip进行压缩
1
50m一个文件,保留3个文件
logger.add('sync_inc.log', level='INFO', encoding="utf-8", rotation="50 MB", retention=3)

异常捕获

使用catch()装饰器或者上下文管理器可以捕获异常,确保任何错误都能够记录到log日志中。

装饰器

from loguru import logger

@logger.catch
def test(x, y, z):
    return 1 / (x + y + z)
test(0, 1, -1)
1234567

上下文装饰器

from loguru import logger


def test(x, y, z):
    return 1 / (x + y + z)
with logger.catch():
    test(0, 1, -1) 
12345678

输出结果
img

完全描述性异常

记录代码中发生的异常对于跟踪BUG非常重要,loguru允许显示整个堆栈跟踪(包括变量值)来帮助定位BUG原因。

logger.add("out.log", backtrace=True, diagnose=True)  # Caution, may leak sensitive data in prod

def func(a, b):
    return a / b
def nested(c):
    try:
        func(5, c)
    except ZeroDivisionError:
        logger.exception("What?!")
nested(0)
123456789101112

输出结果
img

自定义颜色

logger.add(sys.stdout, colorize=True, format="<red>{time}</red> <level>{message}</level>")
logger.debug("debug")
logger.info("info")
logger.success("success")
logger.warning("warning")
logger.error("error")
logger.critical("critical")
1234567

输出结果
img

异步/线程安全/多进程安全

默认情况下,添加到log的所有接收器都是线程安全的,但他们不是多进程安全的。如果需要实现多进程安全,异步记录日志,需要添加一个enqueue参数:

logger.add("test.log", enqueue = True)
1

结构化日志记录

将消息转化为json字符串以便于传递或者解析,可以使用serialize来配置:

logger.add("test.log", serialize=True, encoding="utf-8")
logger.debug("debug")
logger.info("info")
logger.success("success")
logger.warning("warning")
logger.error("error")
logger.critical("critical")
1234567

输出结果

{"text": "2022-07-28 11:25:44.434 | DEBUG    | __main__:<module>:43 - debug\n", "record": {"elapsed": {"repr": "0:00:00.127658", "seconds": 0.127658}, "exception": null, "extra": {}, "file": {"name": "logutil.py", "path": "e:\\GitPorject\\ZanguS1\\ZanguRecorder\\common\\logutil.py"}, "function": "<module>", "level": {"icon": "🐞", "name": "DEBUG", "no": 10}, "line": 43, "message": "debug", "module": "logutil", "name": "__main__", "process": {"id": 15768, "name": "MainProcess"}, "thread": {"id": 10228, "name": "MainThread"}, "time": {"repr": "2022-07-28 11:25:44.434074+08:00", "timestamp": 1658978744.434074}}}
{"text": "2022-07-28 11:25:44.436 | INFO     | __main__:<module>:44 - info\n", "record": {"elapsed": {"repr": "0:00:00.129653", "seconds": 0.129653}, "exception": null, "extra": {}, "file": {"name": "logutil.py", "path": "e:\\GitPorject\\ZanguS1\\ZanguRecorder\\common\\logutil.py"}, "function": "<module>", "level": {"icon": "ℹ️", "name": "INFO", "no": 20}, "line": 44, "message": "info", "module": "logutil", "name": "__main__", "process": {"id": 15768, "name": "MainProcess"}, "thread": {"id": 10228, "name": "MainThread"}, "time": {"repr": "2022-07-28 11:25:44.436069+08:00", "timestamp": 1658978744.436069}}}
{"text": "2022-07-28 11:25:44.438 | SUCCESS  | __main__:<module>:45 - success\n", "record": {"elapsed": {"repr": "0:00:00.131648", "seconds": 0.131648}, "exception": null, "extra": {}, "file": {"name": "logutil.py", "path": "e:\\GitPorject\\ZanguS1\\ZanguRecorder\\common\\logutil.py"}, "function": "<module>", "level": {"icon": "✔️", "name": "SUCCESS", "no": 25}, "line": 45, "message": "success", "module": "logutil", "name": "__main__", "process": {"id": 15768, "name": "MainProcess"}, "thread": {"id": 10228, "name": "MainThread"}, "time": {"repr": "2022-07-28 11:25:44.438064+08:00", "timestamp": 1658978744.438064}}}
{"text": "2022-07-28 11:25:44.439 | WARNING  | __main__:<module>:46 - warning\n", "record": {"elapsed": {"repr": "0:00:00.132645", "seconds": 0.132645}, "exception": null, "extra": {}, "file": {"name": "logutil.py", "path": "e:\\GitPorject\\ZanguS1\\ZanguRecorder\\common\\logutil.py"}, "function": "<module>", "level": {"icon": "⚠️", "name": "WARNING", "no": 30}, "line": 46, "message": "warning", "module": "logutil", "name": "__main__", "process": {"id": 15768, "name": "MainProcess"}, "thread": {"id": 10228, "name": "MainThread"}, "time": {"repr": "2022-07-28 11:25:44.439061+08:00", "timestamp": 1658978744.439061}}}
{"text": "2022-07-28 11:25:44.440 | ERROR    | __main__:<module>:47 - error\n", "record": {"elapsed": {"repr": "0:00:00.133642", "seconds": 0.133642}, "exception": null, "extra": {}, "file": {"name": "logutil.py", "path": "e:\\GitPorject\\ZanguS1\\ZanguRecorder\\common\\logutil.py"}, "function": "<module>", "level": {"icon": "❌", "name": "ERROR", "no": 40}, "line": 47, "message": "error", "module": "logutil", "name": "__main__", "process": {"id": 15768, "name": "MainProcess"}, "thread": {"id": 10228, "name": "MainThread"}, "time": {"repr": "2022-07-28 11:25:44.440058+08:00", "timestamp": 1658978744.440058}}}
{"text": "2022-07-28 11:25:44.442 | CRITICAL | __main__:<module>:48 - critical\n", "record": {"elapsed": {"repr": "0:00:00.135637", "seconds": 0.135637}, "exception": null, "extra": {}, "file": {"name": "logutil.py", "path": "e:\\GitPorject\\ZanguS1\\ZanguRecorder\\common\\logutil.py"}, "function": "<module>", "level": {"icon": "☠️", "name": "CRITICAL", "no": 50}, "line": 48, "message": "critical", "module": "logutil", "name": "__main__", "process": {"id": 15768, "name": "MainProcess"}, "thread": {"id": 10228, "name": "MainThread"}, "time": {"repr": "2022-07-28 11:25:44.442053+08:00", "timestamp": 1658978744.442053}}}
123456

使用bind()添加额外的属性:

logger.add("test.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")
12345

输出结果

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: anybody
123

使用bind()和filter对日志进行过滤:

logger.add("test.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!")
123

输出结果

2022-07-28 11:33:58.214 | INFO     | __main__:<module>:58 - This message, though, is logged to the file!
1

自定义级别

Loguru 附带了所有标准日志记录级别,额外添加了trace和success。如果需要自定义级别,可以使用level()函数来创建:

new_level = logger.level("test2", no=66, color="<black>", icon="🐍")

logger.log("test2", "Here we go!")
123

输出结果:
img

日期时间处理

logger.add("test.log", format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}")
logger.debug("debug")
logger.info("info")
logger.success("success")
logger.warning("warning")
logger.error("error")
logger.critical("critical")
1234567

输出结果:

2022-07-28 at 11:41:32 | DEBUG | debug
2022-07-28 at 11:41:32 | INFO | info
2022-07-28 at 11:41:32 | SUCCESS | success
2022-07-28 at 11:41:32 | WARNING | warning
2022-07-28 at 11:41:32 | ERROR | error
2022-07-28 at 11:41:32 | CRITICAL | critical
123456

loguru配置

在脚本中使用记录器很容易,您可以在开始时configure()它。要从库中使用 Loguru,请记住永远不要调用 add(),而是使用 disable(),以便日志记录函数变为 no-op。如果开发人员希望查看库的日志,他可以再次enable() 它。

# For scripts
config = {
    "handlers": [
        {"sink": sys.stdout, "format": "{time} - {message}"},
        {"sink": "test.log", "serialize": True},
    ],
    "extra": {"user": "someone"}
}
logger.configure(**config)

# For libraries
logger.disable("my_library")
logger.info("No matter added sinks, this message is not displayed")
logger.enable("my_library")
logger.info("This message however is propagated to the sinks")
123456789101112131415

通知程序

Loguru 可以和强大的邮件通知模块 notifiers 库结合使用,以在程序意外失败时接收电子邮件,或发送许多其他类型的通知。

import notifiers

params = {
    "username": "you@gmail.com",
    "password": "abc123",
    "to": "dest@gmail.com"
}
# Send a single notification
notifier = notifiers.get_notifier("gmail")
notifier.notify(message="The application is running!", **params)
# Be alerted on each error message
from notifiers.logging import NotificationHandler
handler = NotificationHandler("gmail", defaults=params)
logger.add(handler, level="ERROR")
1234567891011121314151617

尾语

希望能帮助到大家,如果又说的不对的地方,欢迎大家指正。

posted @ 2022-12-07 15:14  hanfe1  阅读(332)  评论(0编辑  收藏  举报