Python日志库Loguru教程(最人性化的Python日志模块)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Loguru是一个旨在为Python带来愉悦的日志记录的库。在使用中可以让我们更加简便的使用日志功能,从而把精力放到要解决的问题上。

标题

Python日志库Loguru教程(最人性化的Python日志模块)

作者: quantgalaxy@outlook.com   
欢迎交流

1. What:我们需要一个什么样的日志库

  1. 可以区分不同类型的日志:正常,警告,错误,严重。
  2. 可以配置指定的日志文件名称。
  3. 可以配置指定的日志格式。
  4. 可以把不同的日志类型写到不同的文件中。
  5. 可以配置按照时间,文件大小等条件对日志文件进行滚动分割。
  6. 支持异步写日志。
  7. 支持线程安全和进程安全写入日志。
  8. 可以方便的记录,支持python的string format格式。

2. Why:为什么选用loguru

python自带的logging模块,需要完成复杂的配置才能很好的使用,基本生产环境都需要进行二次包装。
loguru专门梳理了这方面的问题,可以通过简单直接的配置完成你的需求。

举一个简单的例子,默认输出到标准输出:

# hello.py
from loguru import logger

logger.info("Hello from loguru!")

执行:

$ python hello.py
2021-07-21 12:16:59.394 | INFO     | __main__:<module>:4 - Hello from loguru!

输出到日志文件:

from loguru import logger

logger.remove(0)
logger.add("out.log")
logger.success("Written message to log file")

可以看到,使用loguru可以非常简单的记录日志,也很方便的写到日志文件中。默认的日志格式已经版喊了基本的时间日期,日志类型,模块名称,代码行数。
官方说,Loguru是一个旨在为Python带来愉悦的日志记录的库。在使用中可以让我们更加简便的使用日志功能,从而把精力放到要解决的问题上。

作者: quantgalaxy@outlook.com   
欢迎交流

3. How:如何使用loguru

3.1 安装

pip install loguru

最简单的使用:

from loguru import logger

# 在标准输出里面输出一行debug日志
logger.debug("That's it, beautiful and simple logging!")

3.2 日志类型(Level)介绍

loguru提供了七层日志层级,或者说七种日志类型。
生产环境中,常常在不同场景下使用不用的日志类型,用于处理各种问题。
每种类型的日志有一个整数值,表示日志层级,我们成为log level no。

  • TRACE (5): 用于记录程序执行路径的细节信息,以进行诊断。
  • DEBUG (10): 开发人员使用该工具记录调试信息。
  • INFO (20): 用于记录描述程序正常操作的信息消息。
  • SUCCESS (25): 类似于INFO,用于指示操作成功的情况。
  • WARNING (30): 警告类型,用于指示可能需要进一步调查的不寻常事件。
  • ERROR (40): 错误类型,用于记录影响特定操作的错误条件。
  • CRITICAL (50): 严重类型,用于记录阻止核心功能正常工作的错误条件。
logger.trace("A trace message.")
logger.debug("A debug message.")
logger.info("An info message.")
logger.success("A success message.")
logger.warning("A warning message.")
logger.error("An error message.")
logger.critical("A critical message.")

输出如下:

2022-08-10 11:58:33.224 | DEBUG | __main__:<module>:12 - A debug message.
2022-08-10 11:58:33.224 | INFO | __main__:<module>:13 - An info message.
2022-08-10 11:58:33.225 | SUCCESS | __main__:<module>:14 - A success message.
2022-08-10 11:58:33.226 | WARNING | __main__:<module>:15 - A warning message.
2022-08-10 11:58:33.226 | ERROR | __main__:<module>:16 - An error message.
2022-08-10 11:58:33.227 | CRITICAL | __main__:<module>:17 - A critical message.

如果你在linux的终端上,可以看到不同类型的日志,已经有不同的颜色加以区分,默认的配置已经很方便的让我们识别和使用了。
请注意,上述输出不包括TRACE级别的日志信息。这是因为Loguru默认使用DEBUG作为其最低日志级别,导致任何严重性低于DEBUG的日志信息都会被忽略。

如果您想更改默认级别,可以使用下面所示的add()方法的级别参数:

import sys
from loguru import logger

logger.remove(0)
logger.add(sys.stderr, level="INFO")

remove()方法被首先调用,以删除默认处理程序的配置(其ID为0)。然后,add()方法向记录器添加一个新处理程序。该处理程序将记录到标准错误,只记录INFO或更高级别的日志。
你也可以自定义一个新的类型的日志,并赋予新的日志level no,在这里就不介绍了,先保证使用默认的日志level,就足够了。

3.3 设置日志输出的格式

在日常使用中,如果默认的输出内容不够,我们还可以自定义日志的输出内容和格式。
可以通过add()方法中的格式选项对Loguru生成的日志记录进行重新格式化。
Loguru 中的每条日志记录都是一个 Python 字典,其中包含其时间戳、日志级别等数据。
可以使用loguru提供的格式化指令,包括或重新排列每条信息,如下所示:

import sys
from loguru import logger

logger.remove(0)
logger.add(sys.stderr, format="{time} | {level} | {message}")

logger.debug("Happy logging with Loguru!")

格式参数定义了自定义格式,在这个例子中有三个指令:
{time}:时间戳
{level}:日志级别
{message}:日志消息

输出如下:

2022-08-10T15:01:32.154035-0400 | DEBUG | Happy logging with Loguru!

Loguru还通过其序列化选项支持JSON格式的结构化日志。
这可以让你以JSON格式输出你的日志,这样机器可以很容易地解析和分析它,因为每条记录中的信息将以键/值对的形式提供。

import sys
from loguru import logger

logger.remove(0)
logger.add(sys.stderr, format="{time:MMMM D, YYYY > HH:mm:ss!UTC} | {level} | {message}", serialize=True)
logger.debug("Happy logging with Loguru!")

json格式的输出:

{"text": "August 10, 2022 > 19:38:06 | DEBUG | Happy logging with Loguru!\n", "record": {"elapsed": {"repr": "0:00:00.004000", "seconds": 0.004}, "exception": null, "extra": {}, "file": {"name": "app.py", "path": "C:\\Users\\Eric\\Documents\\Better Stack\\loguru-demo\\app.py"}, "function": "<module>", "level": {"icon": "🐞", "name": "DEBUG", "no": 10}, "line": 8, "message": "Happy logging with Loguru!", "module": "app", "name": "__main__", "process": {"id": 22652, "name": "MainProcess"}, "thread": {"id": 25892, "name": "MainThread"}, "time": {"repr": "2022-08-10 15:38:06.369578-04:00", "timestamp": 1660160286.369578}}}

3.4 把日志记录到文件中

最简单的配置如下:

logger.add("loguru.log")
logger.debug("A debug message.")

输出如下:

cat loguru.log
2022-08-11 13:16:52.573 | DEBUG | __main__:<module>:13 - A debug message.

当add函数配置为一个文件时,add方法提供了更多选项来自定义日志文件的处理方式:

  • rotate:指定关闭当前日志文件并创建新文件的条件。此条件可以是 int、datetime 或 str,建议使用 str,因为它更易于阅读。
    • 如果是整数值,它对应于当前文件在创建新文件之前允许保留的最大字节数。
    • 如果是datetime.timedelta 值时,它指示每次旋转的频率,而 datetime.time 指定每个旋转应在一天中发生的时间。
    • 如果是str值,这是上述类型的变体。
  • retention:指定在从文件系统中删除每个日志文件之前如何保留日志。
  • compression:如果设置此选项,日志文件将转换为指定的压缩格式。
  • delay:如果设置为 True,则新日志文件的创建将延迟到推送第一条日志消息。
  • mode, buffering, encoding: 这些参数将被传递给 Python 的 open() 函数,该函数决定了 Python 将如何打开日志文件。
# 将自动删除超过一分钟的老文件
logger.add("loguru.log", rotation="5 seconds", retention="1 minute")
# 将仅保留三个最新文件
logger.add("loguru.log", rotation="5 seconds", retention=3)

一个完整的配置:

logger.add(
    sink="./logs/app.log",
    enqueue=True,
    rotation="4 weeks",
    retention="4 months",
    encoding="utf-8",
    backtrace=True,
    diagnose=True,
    compression="zip",
)

add函数参数的完整解释:

  • sink:为记录器生成的每条记录指定目的地。默认情况下,它设置为 sys.stderr。
  • level:指定记录器的最低日志级别。
  • format:用于为日志定义自定义格式。
  • filter:用于确定一条记录是否应该被记录。
  • colorize: 采用布尔值并确定是否应启用终端着色。
  • serialize:如果设置为 True,则日志记录以 JSON 格式呈现。
  • backtrace:确定异常跟踪是否应该延伸到捕获错误的点之外,以便于调试。 诊断:确定变量值是否应显示在异常跟踪中。您应该在生产环境中将其设置为 False 以避免泄露敏感信息。
  • diagnose: 确定变量值是否应在异常跟踪中显示。在生产环境中应将其设置为 False,以避免泄露敏感信息。
  • enqueue:启用此选项会将日志记录放入队列中,以避免多个进程记录到同一目的地时发生冲突。
  • catch:如果在记录到指定的接收器时发生意外错误,您可以通过将此选项设置为 True 来捕获该错误。错误将打印到标准错误。

4. One More Thing

4.1 不同类型的日志记录到不同的文件中

在上面的配置中,我们讲到,可以使用add函数来配置最小的日志级别,如果我们需要把不同的日志输出到不同的文件中,我们需要使用到filter参数:

import sys
from loguru import logger

def level_filter(level):
    def is_level(record):
        return record["level"].name == level
    return is_level

logger.remove(0)
logger.add("./logs/app.log", filter=level_filter(level="WARNING"))

输出如下:

2022-09-30 12:17:00.548 | WARNING  | __main__:<module>:15 - A warning message.

还可以使用lambda函数直接配置filter参数,一个完整的例子:

from loguru import logger

# 设置不同级别的日志输出文件
logger.add("debug.log", level="DEBUG", rotation="10 MB", filter=lambda record: record["level"].name == "DEBUG")
logger.add("info.log", level="INFO", rotation="10 MB", filter=lambda record: record["level"].name == "INFO")
logger.add("warning.log", level="WARNING", rotation="10 MB", filter=lambda record: record["level"].name == "WARNING")
logger.add("error.log", level="ERROR", rotation="10 MB", filter=lambda record: record["level"].name == "ERROR")
logger.add("critical.log", level="CRITICAL", rotation="10 MB", filter=lambda record: record["level"].name == "CRITICAL")

# 输出不同级别的日志消息
logger.debug("This is a debug message")
logger.info("This is an info message")
logger.warning("This is a warning message")
logger.error("This is an error message")
logger.critical("This is a critical message")

4.2 异常记录

loguru提供了非常方便的异常定位功能,可以直接使用catch闭包,把抛出异常的位置记录到日志中。

from loguru import logger

logger.add(sink='log.log')

@logger.catch
def my_function(x, y, z):
    return 1 / (x + y + z)

res = my_function(0,0,0)

输出如下:

> File "/var/folders/kb/0pw_yx2n75z8mlyzjk3mwlwc0000gn/T/ipykernel_85315/1609034425.py", line 9, in <module>
    res = my_function(0,0,0)
          └ <function my_function at 0x7fcce2170670>

  File "/var/folders/kb/0pw_yx2n75z8mlyzjk3mwlwc0000gn/T/ipykernel_85315/1609034425.py", line 7, in my_function
    return 1 / (x + y + z)
                │   │   └ 0
                │   └ 0
                └ 0

ZeroDivisionError: division by zero

4.3 实际使用示例

最后给一组我的代码里面使用的配置:

folder_ = "./log/"
prefix_ = "polaris-"
rotation_ = "10 MB"
retention_ = "30 days"
encoding_ = "utf-8"
backtrace_ = True
diagnose_ = True

# 格式里面添加了process和thread记录,方便查看多进程和线程程序
format_ = '<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> ' \
            '| <magenta>{process}</magenta>:<yellow>{thread}</yellow> ' \
            '| <cyan>{name}</cyan>:<cyan>{function}</cyan>:<yellow>{line}</yellow> - <level>{message}</level>'

# 这里面采用了层次式的日志记录方式,就是低级日志文件会记录比他高的所有级别日志,这样可以做到低等级日志最丰富,高级别日志更少更关键
# debug
logger.add(folder_ + prefix_ + "debug.log", level="DEBUG", backtrace=backtrace_, diagnose=diagnose_,
            format=format_, colorize=False,
            rotation=rotation_, retention=retention_, encoding=encoding_,
            filter=lambda record: record["level"].no >= logger.level("DEBUG").no)

# info
logger.add(folder_ + prefix_ + "info.log", level="INFO", backtrace=backtrace_, diagnose=diagnose_,
            format=format_, colorize=False,
            rotation=rotation_, retention=retention_, encoding=encoding_,
            filter=lambda record: record["level"].no >= logger.level("INFO").no)

# warning
logger.add(folder_ + prefix_ + "warning.log", level="WARNING", backtrace=backtrace_, diagnose=diagnose_,
            format=format_, colorize=False,
            rotation=rotation_, retention=retention_, encoding=encoding_,
            filter=lambda record: record["level"].no >= logger.level("WARNING").no)

# error
logger.add(folder_ + prefix_ + "error.log", level="ERROR", backtrace=backtrace_, diagnose=diagnose_,
            format=format_, colorize=False,
            rotation=rotation_, retention=retention_, encoding=encoding_,
            filter=lambda record: record["level"].no >= logger.level("ERROR").no)

# critical
logger.add(folder_ + prefix_ + "critical.log", level="CRITICAL", backtrace=backtrace_, diagnose=diagnose_,
            format=format_, colorize=False,
            rotation=rotation_, retention=retention_, encoding=encoding_,
            filter=lambda record: record["level"].no >= logger.level("CRITICAL").no)

logger.add(sys.stderr, level="CRITICAL", backtrace=backtrace_, diagnose=diagnose_,
            format=format_, colorize=True,
            filter=lambda record: record["level"].no >= logger.level("CRITICAL").no)

5. Author: 作者信息

作者: quantgalaxy@outlook.com   
欢迎交流

6. QA

  1. 如何对一个日志文件同时设置多种分割方式,比如100MB或者1天时间,都会触发日志分割?
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
6天前
|
调度 开发者 Python
Python中的异步编程:理解asyncio库
在Python的世界里,异步编程是一种高效处理I/O密集型任务的方法。本文将深入探讨Python的asyncio库,它是实现异步编程的核心。我们将从asyncio的基本概念出发,逐步解析事件循环、协程、任务和期货的概念,并通过实例展示如何使用asyncio来编写异步代码。不同于传统的同步编程,异步编程能够让程序在等待I/O操作完成时释放资源去处理其他任务,从而提高程序的整体效率和响应速度。
|
9天前
|
数据采集 存储 数据挖掘
Python数据分析:Pandas库的高效数据处理技巧
【10月更文挑战第27天】在数据分析领域,Python的Pandas库因其强大的数据处理能力而备受青睐。本文介绍了Pandas在数据导入、清洗、转换、聚合、时间序列分析和数据合并等方面的高效技巧,帮助数据分析师快速处理复杂数据集,提高工作效率。
31 0
|
2天前
|
数据库 Python
异步编程不再难!Python asyncio库实战,让你的代码流畅如丝!
在编程中,随着应用复杂度的提升,对并发和异步处理的需求日益增长。Python的asyncio库通过async和await关键字,简化了异步编程,使其变得流畅高效。本文将通过实战示例,介绍异步编程的基本概念、如何使用asyncio编写异步代码以及处理多个异步任务的方法,帮助你掌握异步编程技巧,提高代码性能。
11 4
|
2天前
|
API 数据处理 Python
探秘Python并发新世界:asyncio库,让你的代码并发更优雅!
在Python编程中,随着网络应用和数据处理需求的增长,并发编程变得愈发重要。asyncio库作为Python 3.4及以上版本的标准库,以其简洁的API和强大的异步编程能力,成为提升性能和优化资源利用的关键工具。本文介绍了asyncio的基本概念、异步函数的定义与使用、并发控制和资源管理等核心功能,通过具体示例展示了如何高效地编写并发代码。
11 2
|
7天前
|
数据采集 JSON 测试技术
Python爬虫神器requests库的使用
在现代编程中,网络请求是必不可少的部分。本文详细介绍 Python 的 requests 库,一个功能强大且易用的 HTTP 请求库。内容涵盖安装、基本功能(如发送 GET 和 POST 请求、设置请求头、处理响应)、高级功能(如会话管理和文件上传)以及实际应用场景。通过本文,你将全面掌握 requests 库的使用方法。🚀🌟
28 7
|
8天前
|
机器学习/深度学习 数据采集 算法
Python机器学习:Scikit-learn库的高效使用技巧
【10月更文挑战第28天】Scikit-learn 是 Python 中最受欢迎的机器学习库之一,以其简洁的 API、丰富的算法和良好的文档支持而受到开发者喜爱。本文介绍了 Scikit-learn 的高效使用技巧,包括数据预处理(如使用 Pipeline 和 ColumnTransformer)、模型选择与评估(如交叉验证和 GridSearchCV)以及模型持久化(如使用 joblib)。通过这些技巧,你可以在机器学习项目中事半功倍。
19 3
|
9天前
|
Java 程序员 开发者
Python的gc模块
Python的gc模块
|
10天前
|
存储 数据挖掘 数据处理
Python数据分析:Pandas库的高效数据处理技巧
【10月更文挑战第26天】Python 是数据分析领域的热门语言,Pandas 库以其高效的数据处理功能成为数据科学家的利器。本文介绍 Pandas 在数据读取、筛选、分组、转换和合并等方面的高效技巧,并通过示例代码展示其实际应用。
22 1
|
1天前
|
数据采集 数据可视化 数据挖掘
利用Python进行数据分析:Pandas库实战指南
利用Python进行数据分析:Pandas库实战指南
|
7天前
|
文字识别 自然语言处理 API
Python中的文字识别利器:pytesseract库
`pytesseract` 是一个基于 Google Tesseract-OCR 引擎的 Python 库,能够从图像中提取文字,支持多种语言,易于使用且兼容性强。本文介绍了 `pytesseract` 的安装、基本功能、高级特性和实际应用场景,帮助读者快速掌握 OCR 技术。
28 0
下一篇
无影云桌面