在部署一些定时运行或者长期运行的任务时,为了留存一些导致程序出现异常或错误的信息,通常会才用日志的方式来进行记录这些信息。

在 Python 中用到日志记录,那就不可避免地会用到内置的 logging 标准库 。虽然 logging 库采用的是模块化设计,你可以设置不同的 handler 来进行组合,但是在配置上通常较为繁琐;而且如果不是特别处理,在一些多线程或多进程的场景下使用 logging 还会导致日志记录会出现错乱或是丢失的情况。

但有这么一个库,它不仅能够减少繁琐的配置过程还能实现和 logging 类似的功能,同时还能保证日志记录的线程进程安全,又能够和 logging 相兼容,并进一步追踪异常也能进行代码回溯。这个库叫 loguru——一个专为像我这样懒人而生日志记录库。

loguru 库的使用可以说是十分简单,我们直接可以通过导入它本身封装好的 logger 类就可以直接进行调用。

#!pip install loguru
from loguru import logger

logger 本身就是一个已经实例化好的对象,如果没有特殊的配置需求,那么自身就已经带有通用的配置参数;同时它的用法和 logging 库输出日志时的用法一致

In [1]: from loguru import logger ...:  ...: logger.debug("debug message"    ) ...: logger.info("info level message") ...: logger.warning("warning level message") ...: logger.critical("critical level message")
2020-10-07 14:23:09.637 | DEBUG    | __main__:<module>:3 - debug message
2020-10-07 14:23:09.637 | INFO     | __main__:<module>:4 - info level message
2020-10-07 14:23:09.638 | WARNING  | __main__:<module>:5 - warning level message
2020-10-07 14:23:09.638 | CRITICAL | __main__:<module>:6 - critical level message

当你在 IDE 或终端里运行时会发现,loguru 还为输出的日志信息带上了不同的颜色样式(schema),使得结果更加美观。

01-结果样式

当然,loguru 也像 logging 一样为我们提供了其他可配置的部分,但相比于 logging 每次要导入特定的handler再设定一些formatter来说是更为「傻瓜化」了。

配置

使用基本的 add() 方法就可以对 logger 进行简单的配置,这些配置有点类似于使用 logging 时的 handler。这里简单提及一下比较常用的几个。

1、写入日志

在不指定任何参数时,logger 默认采用 sys.stderr 标准错误输出将日志输出到控制台(console)中;但在 linux 服务器上我们有时不仅让其输出,还要以文件的形式进行留存,那么只需要在第一个参数中传入一个你想要留存文件的路径字符串即可。就像这样:

from loguru import logger
import oslogger.add(os.path.expanduser("~/Desktop/testlog.log"))
logger.info("hello, world!")

这样在你的桌面上就会直接出现相应的 testlog.log 日志文件了。

但是如果你没有自己要是用 logging 没有预先封装来操作,那估计你得写成这样:

import logging
import os
import sys
from logging import handlerslog = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
fmt = logging.Formatter("%(asctime)s | %(levelname)s | %(message)s")
LOGFILE = os.path.expanduser("~/Desktop/testlog.log")console_handler = logging.StreamHandler(sys.stderr)
console_handler.setFormatter(fmt)
log.addHandler(console_handler)file_handler = handlers.RotatingFileHandler(LOGFILE)
file_handler.setFormatter(fmt)
log.addHandler(file_handler)log.info("hello, world")

2、日志留存、压缩与清理

通常来说如果程序或服务的量级较大,那么就可以通过集成的日志平台或数据库来对日志信息进行存储和留存,后续有需要的话也方便进行日志分析。

但对我们个人或者一些中小型项目来说,通常只需要以文件的形式留存输出的日志即可。

尽管我们需要将日志写入到相应的文件中,如果是少量的日志那还好,但是如果是日志输出或记录时间较长的情况,那么单个日志文件就十分之大,倘若仍然是将日志都写入到一个文件中,那么当日志中的内容增长到一定数量时我们想要读取并查找相应的部分时就十分困难。这时候我们就需要对日志文件进行留存、压缩,甚至在必要时及时进行清理。

基于以上,我们可以通过对 rotationcompressionretention 三个参数进行设定来满足我们的需要:

rotation 参数能够帮助我们将日志记录以大小、时间等方式进行分割或划分:

import os
from loguru import loggerLOG_DIR = os.path.expanduser("~/Desktop/logs")
LOG_FILE = os.path.join(LOG_DIR, "file_{time}.log")
if os.path.exits(LOG_DIR):os.mkdir(LOG_DIR)logger.add(LOG_FILE, rotation = "200KB")
for n in range(10000):logger.info(f"test - {n}")

最后呈现如下:

02-rotation

随着分割文件的数量越来越多之后,我们也可以进行压缩对日志进行留存,这里就要使用到 compression 参数,该参数只要你传入通用的压缩文件扩展名即可,如 ziptargz 等。

import os
from loguru import loggerLOG_DIR = os.path.expanduser("~/Desktop/logs")
LOG_FILE = os.path.join(LOG_DIR, "file_{time}.log")
if os.path.exits(LOG_DIR):os.mkdir(LOG_DIR)logger.add(LOG_FILE, rotation = "200KB", compression="zip")
for n in range(10000):logger.info(f"test - {n}")

从结果可以看到,只要是满足了 rotation 分割后的日志文件都被直接压缩成了 zip 文件,文件大小由原本的 200kb 直接减少至 10kb,对于一些磁盘空间吃紧的 Linux 服务器来说是则是很有必要的。

03-compression

当然了,如果你不想对日志进行留存,或者只想保留一段时间内的日志并对超期的日志进行删除,那么直接使用 retention 参数就好了。

这里我们可以将之前的结果随意复制 N 多份在 logs 文件夹中,然后再执行一次加上 retension 参数后代码:


from loguru import loggerLOG_DIR = os.path.expanduser("~/Desktop/logs")
LOG_FILE = os.path.join(LOG_DIR, "file_{time}.log")
if not os.path.exists(LOG_DIR):os.mkdir(LOG_DIR)logger.add(LOG_FILE, rotation="200KB",retention=1)
for n in range(10000):logger.info(f"test - {n}")

当然对 retention 传入整数时,该参数表示的是所有文件的索引,而非要保留的文件数,这里是个反直觉的小坑,用的时候注意一下就好了。所以最后我们会看到只有两个时间最近的日志文件会被保留下来,其他都被直接清理掉了。

04-retention

3、序列化

如果在实际中你不太喜欢以文件的形式保留日志,那么你也可以通过 serialize 参数将其转化成序列化的 json 格式,最后将导入类似于 MongoDB、ElasticSearch 这类数 NoSQL 数据库中用作后续的日志分析。

from loguru import logger
import oslogger.add(os.path.expanduser("~/Desktop/testlog.log"), serialize=True)
logger.info("hello, world!")

最后保存的日志都是序列化后的单条记录:

{"text": "2020-10-07 18:23:36.902 | INFO     | __main__:<module>:6 - hello, world\n","record": {"elapsed": {"repr": "0:00:00.005412","seconds": 0.005412},"exception": null,"extra": {},"file": {"name": "log_test.py","path": "/Users/Bobot/PycharmProjects/docs-python/src/loguru/log_test.py"},"function": "<module>","level": {"icon": "\u2139\ufe0f","name": "INFO","no": 20},"line": 6,"message": "hello, world","module": "log_test","name": "__main__","process": {"id": 12662,"name": "MainProcess"},"thread": {"id": 4578131392,"name": "MainThread"},"time": {"repr": "2020-10-07 18:23:36.902358+08:00","timestamp": 1602066216.902358}}
}

4、异常追溯

当异常和错误不可避免时,最好的方式就是让我们知道程序到底是哪里出了错,或者是因为什么导致错误,这样才能更好地让开发人员及时应对并解决。

loguru 集成了一个名为 better_exceptions 的库,不仅能够将异常和错误记录,并且还能对异常进行追溯,这里是来自一个官网的例子

import os
import sysfrom loguru import loggerlogger.add(os.path.expanduser("~/Desktop/exception_log.log"), backtrace=True, diagnose=True)def func(a, b):return a / bdef nested(c):try:func(5, c)except ZeroDivisionError:logger.exception("What?!")if __name__ == "__main__":nested(0)

最后在日志文件中我们可以得到以下内容:

2020-10-07 21:14:11.830 | ERROR    | __main__:nested:16 - What?!
Traceback (most recent call last):File "/Users/Bobot/PycharmProjects/docs-python/src/loguru/log_test.py", line 20, in <module>nested(0)└ <function nested at 0x7fb9300c1170>> File "/Users/Bobot/PycharmProjects/docs-python/src/loguru/log_test.py", line 14, in nestedfunc(5, c)│       └ 0└ <function func at 0x7fb93010add0>File "/Users/Bobot/PycharmProjects/docs-python/src/loguru/log_test.py", line 10, in funcreturn a / b│   └ 0└ 5ZeroDivisionError: division by zero

与 Logging 完全兼容(Entirely Compatible)

尽管说 loguru 算是重新「造轮子」,但是它也能和 logging 库很好地兼容。到现在我们才谈论到 add() 方法的第一个参数 sink

这个参数的英文单词动词有「下沉、浸没」等意,对于外国人来说在理解上可能没什么难的,可对我们国人来说,这可之前 logging 库中的 handler 概念还不好理解。好在前面我有说过,logurulogging 库的使用上存在相似之处,因此在后续的使用中其实我们就可以将其理解为 handler,只不过它的范围更广一些,可以除了 handler 之外的字符串、可调用方法、协程对象等。

loguru 官方文档对这一参数的解释是:

An object in charge of receiving formatted logging messages and propagating them to an appropriate endpoint.

翻译过来就是「一个用于接收格式化日志信息并将其传输合适端点的对象」,进一步形象理解就像是一个「分流器」。


import logging.handlers
import os
import sysfrom loguru import loggerLOG_FILE = os.path.expanduser("~/Desktop/testlog.log")
file_handler = logging.handlers.RotatingFileHandler(LOG_FILE, encoding="utf-8")
logger.add(file_handler)
logger.debug("hello, world")

当然目前只是想在之前基于 logging 写好的模块中集成 loguru,只要重新编写一个继承自 logging.Handler 类并实现了 emit() 方法的 Handler 即可。

import logging.handlers
import os
import sysfrom loguru import loggerclass InterceptHandler(logging.Handler):def emit(self, record):try:level = logger.level(record.levelname).nameexcept ValueError:level = record.levelnoframe, depth = logging.currentframe(), 2while frame.f_code.co_filename == logging.__file__:frame = frame.f_backdepth += 1logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())logging.basicConfig(handlers=[InterceptHandler()], level=0)def func(a, b):return a / bdef nested(c):try:func(5, c)except ZeroDivisionError:logging.exception("What?!")if __name__ == "__main__":nested(0)

最后结果同之前的异常追溯一致。而我们只需要在配置后直接调用 logging 的相关方法即可,减少了迁移和重写的成本。

最后

本文介绍了关于 loguru 的常用方法,从对比例子上来看,相比于复杂的 logging 配置来说,使用 loguru 库无疑还是很香的,毕竟别人已经为我们一些日常的通用性需求提供了封装好的解决方案,无论是在学习还是在使用的成本上,无疑还是比较小的。

由于篇幅有限,loguru 的其他配置部分没有进一步展开,如果看完本文的你对这个库感兴趣并打算投入到实际的开发和生产中使用,那么建议你还是阅读一下其官方文档,有必要的话可以浏览一下源码。

不过 loguru 的通用配置不一定满足每个人的需要,对于那些动手能力强或水平较高的朋友还能进一步根据个人需求或业务需求进行二次封装,或许也能较为贴合实际情况。

作者:100gle,练习时长不到两年的非正经文科生一枚,喜欢敲代码、写写文章、捣鼓捣鼓各种新事物;现从事有关大数据分析与挖掘的相关工作。

赞 赏 作 者

Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。

长按扫码添加“Python小助手” 

▼点击成为社区会员   喜欢就点个在看吧

不想手动再配置logging?那可以试试loguru相关推荐

  1. Enterprise Library 2.0 技巧(4):如何用编程的方法来配置Logging Application Block

    在本系列的技巧(1)和技巧(2)中分别介绍了使用外部配置文件,使用数据库记录配置信息两种方法,不知道大家有没有想过不使用任何配置文件,也不使用数据库而直接用编程的方法来实现呢?本文将会展示如何使用编程 ...

  2. PXE 自动安装物理机 (DHCP服务由路由提供, 不能再配置)

    目录 1. PXE 自动安装物理机 (DHCP服务由路由提供, 不能再配置) 1.1. 需要的软件 1.2. 启动 proxy dhcp 服务 1.3. 关键的几个配置文件 PXE 自动安装物理机 ( ...

  3. 3d打印光固化好还是热固化好_创想三维再添重磅光固化3D打印机 LD-006大尺寸高精度-创想三维 LD-003_深圳3D打印机行情...

    创想三维成立6年来,深耕3D打印领域,在产品为王的时代,深挖消费者需求,重视创新,以优质的产品和现代化的服务赢得广大用户的热捧与好评.这个月,创想三维再添重磅光固化3D打印机--LD-006,为3D打 ...

  4. 不重装修复系统并恢复windows用户配置文件,适用于window 11 WSA出错后的dll文件缺失、.net framework缺失或者其他类似系统恢复后尽可能想恢复用户配置的场景

    不重装修复系统并恢复windows用户配置文件,适用于window 11 WSA出错后的dll文件缺失..net framework缺失或者其他类似系统恢复后尽可能想恢复用户配置的场景 问题 解决 1 ...

  5. Spring Cloud【Finchley】实战-06使用/actuator/bus-refresh端点手动刷新配置 + 使用Spring Cloud Bus自动更新配置

    文章目录 概述 特别注意版本信息 使用@RefreshScope + /actuator/bus-refresh端点手动刷新配置 Step1. 添加依赖 Step2. 配置RabbitMQ信息 Ste ...

  6. 将ubuntu配置为路由器_“名酒为王”时代来临但资源将尽,看泸州老窖如何进行“名酒资源再配置”丨深度观察...

    文丨酒业家主笔 彭伟 冲刺300亿,重回前三甲. 泸州老窖作为四大名酒之一,连续蝉联五届国家名酒,在全国范围的消费者中构建了极其深远的品牌影响力.因此,才会有泸州老窖股份有限公司党委书记.董事长刘淼在 ...

  7. 想明白再行动 也许就晚了

    近来常被学生们追问各种问题,五花八门.问得可爱,答得心甘.大部分人年轻时均如此,人生特定阶段的常态--进步最快.最大的一段美好时光.我这等好分享者(贬义些,则可称为好为人师者),自然以其为乐喽. 欣然 ...

  8. Python使用yaml配置logging日志

    前言 在Python环境下,logging是一个很好的用于处理日志的扩展包.平时使用时一般直接import logging后,调用logging.debug("info")方法打印 ...

  9. Win10 环境通过gcc手动编译配置boost库 for LibreCAD

    Win10 环境通过gcc手动编译配置boost库 for LibreCAD 0. 说明 1. 手动配置编译boost库 2. 将库文件和头文件添加到项目中 0. 说明 在win10环境下,通过Qt编 ...

最新文章

  1. c语言日期星期程序,C语言程序设计: 输入年月日 然后输出是星期几
  2. 如何把一段简单的代码变复杂?
  3. Centos7 vim/vi的使用
  4. 在教学中利用计算机软件,计算机软件技术教学方法研究
  5. linux vim看最低,linux vim
  6. 常见六大 Web 安全攻防解析 | 技术头条
  7. [转]Yii Framework: 从 model 中生成 select option
  8. cass参考手册_CASS9.2参考手册
  9. 【经验】JavaScript
  10. cdr宏教程_如何自学coreldraw vba
  11. kakfa 3.0 创建topic流程(源码)
  12. numpy浅拷贝与深拷贝
  13. 不怕新歌有多嗨,就怕老歌带DJ,Python批量对DJ歌曲进行下载
  14. 计算机excel公式2010,计算机二级Office2010Eexcel公式汇总
  15. python不是内部文件别太任性_Python对文件的操作
  16. 黑客代码雨源代码_工业城黑客空间教授的东西比代码更有价值
  17. 【Homebrew】Homebrew 介绍与安装
  18. 论文阅读-Attention Bottlenecks for Multimodal Fusion(多模态特征融合)
  19. php --interface接口的使用方法
  20. i5 12600k参数 i512600k评测

热门文章

  1. 索引、单列索引、复合索引、主键、唯一索引、聚簇索引、非聚簇索引、唯一聚簇索引 的区别与联系
  2. 同位语和插入语的理解
  3. POI-TL使用及工具类
  4. P 站有意收购 Tumblr,视频图片两开花;jQuery 3.4.1 发布
  5. 【Python百炼成魔】魂圣初入Python之Python最佳入门实践
  6. HDU 5528 狄利克雷卷积
  7. 2021最新大厂Java面试集合,顺利拿到offer
  8. abbyy是什么软件
  9. [MCGC]网络优化_MCGC 下载地址 最新版 持续更新
  10. addEvent和removeEvent优化写法