一、背景
在使用Python 编写自动化脚本过程中,大多数情况下可能都是直接用 logging 模块来记录日志,在使用时需要配置一些 Handler、Formatter 来进行一些处理,比如把日志输出到不同的位置(控制台打印、文件记录等等),或者定义不同的输出格式、日志分块、备份。需要配置的内容较多且繁琐。然后直到发现了 loguru 之后,功能强大而且还很灵活,几乎不需要太多配置就可以使用。在了解之后果然投入 loguru 的怀抱。
二、loguru
1.安装
>>> pip install loguru
2.入门操作
不需要配置什么东西,直接 improt logger,调用其对应日志 level 方法即可。logger 默认配置了基操信息,比如格式化输出、文本颜色区别、 时间日期记录、对应模块方法、代码行标识等等,尽可能的友好。值得点赞。
from loguru import logger
logger.debug('this is a debug message')
logger.info('this is a info message')
logger.warning('this is a warning message')
logger.error('this is a error message')
上面的代码运行结果如下:
2021-11-25 15:23:58.507 | DEBUG | __main__:<module>:53 - this is a debug message
2021-11-25 15:23:58.508 | INFO | __main__:<module>:54 - this is a info message
2021-11-25 15:23:58.508 | WARNING | __main__:<module>:55 - this is a warning message
2021-11-25 15:23:58.508 | ERROR | __main__:<module>:56 - this is a error message
Process finished with exit code 0
以上的日志信息是默认输出到控制台打印的,如果想要将日志输出或者记录到其他的地方,需要使用 add() 来指定。 下面将仔细介绍常用基本参数的使用。
from loguru import logger
log_path = Path(Path.cwd().parent, "log")
logger.add(f"{log_path}/interface_log_{time.strftime('%Y-%m-%d')}.log", rotation="50MB", encoding="utf-8")
logger.debug('Enter into a log file.')
对应的日志就写入到对应项目路径下的 /log/interface_log_2021-11-25.log
看起来是不是 眼前一亮!
# interface_log_2021-11-25.log
2021-11-25 17:15:56.988 | DEBUG | __main__:<module>:55 - Enter into a log file.
三、参数介绍
sink
一个对象,负责接收格式化的日志消息并将它们传播到适当的端点。
支持:file-like object pathlib.Path callable coroutine function logging.Handler 等等
logger.add(sys.stderr")
level
( intor str, 可选) -- 记录的消息应该发送到接收器的最低严重性级别
logger.add(sys.stderr, level='DEBUG')
format
(str或callable,可选)– 用于在发送到接收器之前格式化记录的消息的模板。
logger.add(sys.stderr, format="{message}", level='DEBUG')
filter
( callable, stror dict, optional) -- 一个可选的指令,用于决定每个记录的消息是否应该发送到接收器
logger.add(sys.stderr, format="{message}", level='DEBUG', filter="sub.module")
其他不太常用,默认设置即可.这里只做简单介绍不示例了
colorize
( bool, 可选) – 格式化消息中包含的颜色标记是否应转换为用于终端着色的 ansi 代码,或者以其他方式剥离。如果None,则根据接收器是否为 tty 自动做出选择
serialize
( bool, 可选) – 在发送到接收器之前,是否应首先将记录的消息及其记录转换为 JSON 字符串。
backtrace
( bool, 可选) – 格式化的异常跟踪是否应该向上扩展,超出捕获点,以显示生成错误的完整堆栈跟踪。
diagnose
(bool,可选)– 异常跟踪是否应显示变量值以简化调试。这应该False在生产中设置为避免泄露敏感数据。
enqueue
( bool, 可选) – 要记录的消息在到达接收器之前是否应首先通过多进程安全队列。这在通过多个进程记录到文件时很有用。这也具有使日志记录调用非阻塞的优点。可以理解为异步写入
catch
( bool, 可选) – 是否应自动捕获接收器处理日志消息时发生的错误。如果True,则显示异常消息,sys.stderr但异常不会传播到调用者,从而防止您的应用程序崩溃。
当且仅当接收器是文件路径时,以下参数适用:
rotation
( str, int, datetime.time, datetime.timedeltaor callable, 可选) – 指示何时应关闭当前记录的文件并启动新文件的条件。
from loguru import logger
# 根据指定 rotation 参数来自动分隔日志文件,可以根据文件大小,日期时间等
logger.add('runtime_{time}.log', rotation="500 MB") # 文件超过500Mb就会生成一个新的日志文件
logger.add('runtime_{time}.log', rotation='00:00') # 每天0点自动生成新的文件
logger.add('runtime_{time}.log', rotation='1 week') # 每隔一周生成新的
retention
( str, int,datetime.timedelta或callable, 可选) – 过滤旧文件的指令,应在循环或程序结束期间删除。
# 可以配置日志文件数据的最长保留时间
logger.add('runtime.log', retention='10 days')
compression
(str或callable,可选)– 日志文件在关闭时应转换为的压缩或存档格式。
# 配置文件的压缩格式
logger.add('runtime.log', retention='10 days', compression="zip")
delay ( bool, 可选) -- 是在配置接收器后立即创建文件,还是延迟到第一条记录的消息。它默认为False.
mode ( str, 可选) – 内置open()函数的打开模式。它默认为"a"(以追加模式打开文件)。
buffering (int,可选)– 内置open()函数的缓冲策略。它默认为1(行缓冲文件)。
encoding ( str, optional) – 内置open()函数的文件编码。如果None,则默认为 locale.getpreferredencoding()。
**kwargs – 其他参数传递给内置open()函数。
remove(handler_id=None)
删除先前添加的 sink 并停止向其接收器发送日志.
handler_id (int or None) – 要移除的接收器的 id,因为它是由add()方法返回的。如果None,则删除所有处理程序。其实实际并没有删除,只是没有将日志进行写入了而已。
sink = logger.add(sys.stderr, format="{message}")
logger.info("Logging")
logger.remove(sink)
logger.info("No longer logging")
@catch 使用
装饰器以自动记录包装函数中可能捕获的错误并将异常情况写入日志文件
@logger.catch
def catch_function(z):
# An error? It's caught anyway!
return 10 / z
if __name__ == '__main__':
catch_function(0)
上面抛出的zero异常由于函数上使用了 @catch 装饰器,不仅控制台会捕获异常信息,同事也将写入对应的日志文件中。
2021-11-25 17:09:04.852 | ERROR | __main__:<module>:53 - An error has been caught in function '<module>', process 'MainProcess' (14380), thread 'MainThread' (22452):
Traceback (most recent call last):
> File "C:/Users/lenovo/PycharmProjects/job/httpRunner_demo/utils\loguruUtils.py", line 53, in <module>
catch_function(0)
└ <function catch_function at 0x0000025BF548F948>
File "C:/Users/lenovo/PycharmProjects/job/httpRunner_demo/utils\loguruUtils.py", line 48, in catch_function
return 10 / z
└ 0
ZeroDivisionError: division by zero
Process finished with exit code 0
四、loguru封装
import time
from loguru import logger
from pathlib import Path
class Logger(object):
log = logger
def __init__(self):
self.log_path = Path(Path.cwd().parent, "log")
logger.add(f"{self.log_path}/interface_log_{time.strftime('%Y-%m-%d')}.log",
rotation="00:00",
encoding="utf-8",
enqueue=True,
retention="7 days")
def trace(self, *args, **kwargs):
return self.log.trace(*args, **kwargs)
def debug(self, *args, **kwargs):
return self.log.debug(*args, **kwargs)
def info(self, *args, **kwargs):
return self.log.info(*args, **kwargs)
def warning(self, *args, **kwargs):
return self.log.warning(*args, **kwargs)
def error(self, *args, **kwargs):
return self.log.error(*args, **kwargs)
def critical(self, *args, **kwargs):
return self.log.critical(*args, **kwargs)
if __name__ == '__main__':
logger = Logger()
logger.debug("Write anything down.")
可以进行简单的封装定制一下,就可以使用到项目当中去了。不需要改动太多地方。好东西啊!
2021-11-25 17:21:05.579 | DEBUG | __main__:debug:30 - Write anything down.
Process finished with exit code 0