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')
执行结果如下:
引言 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
输出结果
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
输出结果
完全描述性异常
记录代码中发生的异常对于跟踪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
输出结果
自定义颜色
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
输出结果
异步/线程安全/多进程安全
默认情况下,添加到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
输出结果:
日期时间处理
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
尾语
希望能帮助到大家,如果又说的不对的地方,欢迎大家指正。