[python] Python日志记录库loguru使用指北
<p>Loguru是一个功能强大且易于使用的开源Python日志记录库。它建立在Python标准库中的logging模块之上,并提供了更加简洁直观、功能丰富的接口。Logging模块的使用见:Python日志记录库logging总结。Loguru官方仓库见:loguru,loguru官方文档见: loguru-doc。</p><p>Loguru的主要特点包括:</p>
<ul>
<li>简单易用:无需复杂的配置和定制即可实现基本的日志记录和输出。</li>
<li>灵活的日志格式:支持自定义日志格式,并提供丰富的格式化选项。</li>
<li>丰富的日志级别:支持多种日志级别,例如DEBUG、INFO、WARNING、ERROR和CRITICAL。</li>
<li>多种日志目标:可以将日志输出到终端、文件、电子邮件、网络服务器等目标。</li>
<li>强大的日志处理功能:支持日志过滤、格式化、压缩、旋转等功能。</li>
<li>支持异步日志记录:能够极大地提升日志记录的性能。</li>
<li>支持跨进程、跨线程的日志记录:可以安全地记录多进程、多线程应用程序的日志。</li>
</ul>
<p>Loguru与logging是Python中常用的两个日志记录库,但两者在功能和易用性方面存在一些差异,如下所示:</p>
<table>
<thead>
<tr>
<th>特性</th>
<th>Loguru</th>
<th>logging</th>
</tr>
</thead>
<tbody>
<tr>
<td>易用性</td>
<td>更简单易用</td>
<td>相对复杂</td>
</tr>
<tr>
<td>日志格式</td>
<td>更灵活</td>
<td>较简单</td>
</tr>
<tr>
<td>日志级别</td>
<td>更丰富</td>
<td>较少</td>
</tr>
<tr>
<td>日志目标</td>
<td>更多种类</td>
<td>较少</td>
</tr>
<tr>
<td>日志处理功能</td>
<td>更强大</td>
<td>较弱</td>
</tr>
<tr>
<td>异步日志记录</td>
<td>支持</td>
<td>不支持</td>
</tr>
<tr>
<td>跨进程、跨线程支持</td>
<td>支持</td>
<td>支持</td>
</tr>
</tbody>
</table>
<p>总的来说,loguru在易用性、功能性和性能方面都优于logging。如果要一个简单、强大且易于使用的日志系统,loguru是一个很好的选择。而如果只是需要快速输出一些调试信息,print可能就足够了。不过,对于生产环境,使用loguru或其他日志系统通常会更加合适。</p>
<p>Loguru安装命令如下:</p>
<blockquote>
<p>pip install loguru</p>
</blockquote>
<pre><code class="language-python"># 查看loguru版本
import loguru
print(loguru.__version__) # 输出:0.7.2
</code></pre>
<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>1 使用说明<ul><li>1.1 基础用法</li><li>1.2 日志配置</li><li>1.3 进阶使用</li></ul></li><li>2 参考</li></ul></div><p></p>
<h1 id="1-使用说明">1 使用说明</h1>
<h2 id="11-基础用法">1.1 基础用法</h2>
<p><strong>简单使用</strong></p>
<p>Loguru的核心概念是只有一个全局的日志记录器,也就是logger。这个设计使得日志记录变得非常简洁和一致。使用Loguru时,你不需要创建多个日志实例,而是直接使用这个全局的logger来记录信息。这不仅减少了配置的复杂性,也使得日志管理更加集中和高效。</p>
<pre><code class="language-python">from loguru import logger
logger.debug("这是一个调试信息")
</code></pre>
<p>输出:</p>
<pre><code>2024-06-29 19:57:44.506 | DEBUG | __main__:<module>:3 - 这是一个调试信息
</code></pre>
<p>Loguru日志输出默认格式如下:</p>
<ol>
<li>时间戳:表示日志记录的具体时间,格式通常为年-月-日 时:分:秒.毫秒。</li>
<li>日志级别:表示这条日志的严重性级别。</li>
<li>进程或线程标识:表示日志来自哪个模块或脚本。 <code>__main__</code> 表示日志来自主模块。如果是其他文件会显示文件名。</li>
<li>文件名和行号:记录日志消息的函数名和行号。</li>
<li>日志消息:实际的日志内容,此外loguru支持使用颜色来区分不同的日志级别,使得日志输出更加直观.</li>
</ol>
<p><strong>日志等级</strong></p>
<p>Loguru可以通过简单的函数调用来记录不同级别的日志,并自动处理日志的格式化和输出。这一特点可以让使用者专注于记录重要的信息,而不必关心日志的具体实现细节。Loguru支持的日志级别,按照从最低到最高严重性排序:</p>
<ul>
<li>TRACE: 最详细的日志信息,用于追踪代码执行过程。Loguru默认情况下使用DEBUG级别作为最低日志记录级别,而不是TRACE级别。这是因为TRACE级别会产生大量的日志信息。</li>
<li>DEBUG: 用于记录详细的调试信息,通常只在开发过程中使用,以帮助诊断问题。</li>
<li>INFO: 用于记录常规信息,比如程序的正常运行状态或一些关键的操作。</li>
<li>SUCCESS: 通常用于记录操作成功的消息,比如任务完成或数据成功保存。</li>
<li>WARNING: 用于记录可能不是错误,但需要注意或可能在未来导致问题的事件。</li>
<li>ERROR: 用于记录错误,这些错误可能会影响程序的某些功能,但通常不会导致程序完全停止。</li>
<li>CRITICAL: 用于记录非常严重的错误,这些错误可能会导致程序完全停止或数据丢失。</li>
</ul>
<pre><code class="language-python">from loguru import logger
logger.debug("这是一条跟踪消息")
logger.debug("这是一条调试信息")
logger.info("这是一条普通信息")
logger.success("操作成功完成")
logger.warning("这是一条警告信息")
logger.error("这是一条错误信息")
logger.critical("这是一条严重错误信息")
</code></pre>
<p>输出:</p>
<pre><code>2024-06-29 19:58:11.535 | DEBUG | __main__:<module>:3 - 这是一条跟踪消息
2024-06-29 19:58:11.536 | DEBUG | __main__:<module>:4 - 这是一条调试信息
2024-06-29 19:58:11.536 | INFO | __main__:<module>:5 - 这是一条普通信息
2024-06-29 19:58:11.537 | SUCCESS| __main__:<module>:6 - 操作成功完成
2024-06-29 19:58:11.537 | WARNING| __main__:<module>:7 - 这是一条警告信息
2024-06-29 19:58:11.538 | ERROR | __main__:<module>:8 - 这是一条错误信息
2024-06-29 19:58:11.538 | CRITICAL | __main__:<module>:9 - 这是一条严重错误信息
</code></pre>
<h2 id="12-日志配置">1.2 日志配置</h2>
<p>在loguru中,add函数用于添加日志处理器。这个函数用于指定日志消息应该被发送到何处,例如控制台、文件或其他自定义的目的地。add函数主要参数介绍如下:</p>
<ul>
<li><code>sink</code>: 定义日志消息的输出位置,可以是文件路径、标准输出(stdout)、标准错误(stderr,默认)或其他自定义的输出位置。</li>
<li><code>format</code>: 指定日志消息的格式,可以是简单的字符串,也可以是格式化字符串,支持各种字段插值。</li>
<li><code>level</code>: 设置处理程序处理的日志消息的最低级别。比如设置为DEBUG,则处理程序将处理所有级别的日志消息。</li>
<li><code>filter</code>: 可选参数,用于添加过滤器,根据特定的条件过滤掉不需要的日志消息。</li>
<li><code>colorize</code>: 布尔值,指定是否对日志消息进行着色处理,使日志在控制台中更易于区分。</li>
<li><code>serialize</code>: 布尔值,指定是否对日志消息进行序列化处理,通常与<code>enqueue=True</code>一起使用,以确保多线程安全。</li>
<li><code>enqueue</code>: 布尔值,指定是否将日志消息放入队列中处理,用于多线程应用中避免阻塞。</li>
<li><code>backtrace</code>: 布尔值或字符串,指定是否记录回溯信息,默认为<code>False</code>。</li>
<li><code>diagnose</code>: 布尔值,启用后,会在处理程序内部出现错误时记录诊断信息。</li>
<li><code>rotation</code>: 日志文件轮换的配置,支持按大小或时间进行日志文件的轮换。</li>
<li><code>retention</code>: 用于设置日志文件的保留时间。</li>
<li><code>compression</code>: 布尔值,指定是否对轮换后的日志文件进行压缩处理。</li>
</ul>
<pre><code class="language-python">from loguru import logger
import sys
# 终端显示不受该段代码设置
# 添加一个日志处理器,输出到文件
# 设置日志最低显示级别为INFO,format将设置sink中的内容
# sink链接的本地文件,如不存在则新建。如果存在则追写
logger.add(sink="myapp.log", level="INFO", format="{time:HH:mm:ss}| {message}| {level}")
# debug结果不被显示到本地文件
logger.debug("这是一条调试信息")
logger.info("这是一条普通信息")
</code></pre>
<p>输出:</p>
<pre><code>2024-06-29 19:58:56.159 | DEBUG | __main__:<module>:11 - 这是一条调试信息
2024-06-29 19:58:56.159 | INFO | __main__:<module>:12 - 这是一条普通信息
</code></pre>
<p>当连续两次调用 add 函数时,loguru 会将新的日志处理器添加到处理器列表中,而不是覆盖之前的处理器。这意味着所有添加的处理器都会接收到日志消息,并且按照它们被添加的顺序来处理这些消息。</p>
<pre><code class="language-python">from loguru import logger
logger.add(sink="myapp1.log", level="INFO")
logger.add(sink="myapp2.log", level="INFO")
# 会同时存入所有add添加日志处理器
logger.info("这是一条普通信息,存入myapp2")
</code></pre>
<p>如果想删除所有已添加的日志处理器,loguru运行使用 logger.remove()方法不带任何参数来移除所有日志处理器。</p>
<pre><code class="language-python">from loguru import logger
import sys
# 移除所有日志处理器(包括终端输出)
logger.remove()
logger.add(sink="myapp3.log", level="INFO", format="{time:HH:mm:ss}| {message}| {level}")
logger.debug("这是一条调试信息存入myapp3")
logger.info("这是一条普通信息存入myapp3")
</code></pre>
<p>注意调用logger.remove()之后的所有日志将不会被记录,因为没有处理器了。</p>
<pre><code class="language-python">from loguru import logger
# 移除所有日志处理器(包括终端输出)
logger.remove()
# 没有输出
logger.info("这是一条普通信息存入myapp3")
</code></pre>
<p>如果希望移除某些日志处理器,而不是从所有日志器中移除,代码如下:</p>
<pre><code class="language-python">from loguru import logger
# 移除默认终端logger,如果终端存在。
# logger.remove(0)
# 添加多个文件处理器,enqueu设置异步日志记录
handler1 = logger.add("myapp1.log", enqueue=True)
print(handler1) # handler_id是移除的处理器的唯一标识符
handler2 = logger.add("myapp2.log")
# 记录一些日志
logger.info("这些信息会被记录到两个文件中")
# 移除特定的文件处理器
logger.remove(handler1)
# 现在只有myapp2.log 会记录日志
logger.info("这条信息只会记录在myapp2.log 中")
</code></pre>
<p>如果想将日志输出到日志台,代码如下:</p>
<pre><code class="language-python">from loguru import logger
import sys
logger.remove() # 移除默认输出
# 添加一个日志处理器,输出到控制台,使用自定义格式
logger.add(
sink=sys.stdout,
level="DEBUG",
# green表示颜色
format="<green>{time:HH:mm}</green> <level>{message}</level>"
)
# 注意终端显示会同步显示
logger.debug("这是一条调试信息")
logger.info("这是一条普通信息")
</code></pre>
<p><strong>时间自定义</strong></p>
<p>可以使用datatime库来自定义日志时间格式。</p>
<pre><code class="language-python">from datetime import datetime
from loguru import logger
# 自定义时间格式
# time_format = "%Y-%m-%d %H:%M:%S,%f"# 包括微秒
time_format = "%H:%M:%S,%f"# 包括微秒但不含年月日
# 定义日志格式,使用 datetime.now().strftime() 来格式化时间
log_format = "{time:" + time_format + "} - {level} - {message}"
logger.add("myapp.log", format=log_format, level="DEBUG")
# 记录一条日志
logger.debug("这是一个带有微秒的测试日志")
</code></pre>
<p><strong>日志轮换</strong></p>
<pre><code class="language-python">from loguru import logger
# 当文件大小达到100MB时创建新的日志文件,旧文件保留并重命名,用于防止单个日志文件变得过大。
logger.add("file_1.log", rotation="100 MB")
# 每天中午12时创建新的日志文件,旧文件保留并重命名
logger.add("file_2.log", rotation="12:00")
# 当日志文件存在超过一周时创建新的日志文件,旧文件保留并重命名
logger.add("file_3.log", rotation="1 week")
# 设置日志文件保留10天
logger.add("file_4.log", retention="10 days")
# 当文件大小达到100MB时创建新的日志文件,旧文件保留压缩为zip文件
logger.add('file_{time}.log', rotation="100 MB", compression='zip')
</code></pre>
<h2 id="13-进阶使用">1.3 进阶使用</h2>
<p><strong>异常捕获</strong></p>
<p>@logger.catch装饰器可以用来装饰my_function函数,并将这些异常信息记录到日志中。</p>
<pre><code class="language-python">from loguru import logger
logger.add(sink='myapp.log')
@logger.catch
def my_function(x, y):
return x / y
res = my_function(0,0)
</code></pre>
<p><strong>过滤</strong></p>
<p>使用loguru库进行Python日志记录时,可以通过自定义的filter函数来筛选并记录特定的日志信息。此函数接收一个记录对象作为参数,根据日志消息内容(message)、级别(level)或其他日志属性,返回布尔值以决定是否记录该条日志。如果函数返回True,则日志被记录;若返回False,则忽略该日志。</p>
<pre><code class="language-python">from loguru import logger
# 定义一个过滤器函数
def my_filter(record):
# 只记录包含 "第一" 的日志
return "第一" in record["message"]
# 使用过滤器
logger.add("myapp.log", filter=my_filter)
# 记录一些日志
logger.info("第一个记录")
logger.info("第二个记录")
</code></pre>
<p>此外可以结合bind方法进行过滤,bind方法用于向日志记录器添加额外的上下文信息。这些信息将被包含在每条日志消息中,但不会改变日志消息本身。如下所示:</p>
<pre><code class="language-python">from loguru import logger
def filter_user(record):
return record["extra"].get("user") =="A"
logger.add("myapp.log", filter=filter_user)
# 绑定user
logger.bind(user="A").info("来自A")
logger.bind(user="B").info("来自B")
</code></pre>
<h1 id="2-参考">2 参考</h1>
<ul>
<li>loguru</li>
<li>loguru-doc</li>
<li>Python日志记录库logging总结</li>
<li>Python日志库Loguru教程</li>
</ul>
</div>
<div id="MySignature" role="contentinfo">
<p>本文来自博客园,作者:落痕的寒假,转载请注明原文链接:https://www.cnblogs.com/luohenyueji/p/18276299</p>
<div style="text-align:center">
<img src="https://gitlab.com/luohenyueji/article_picture_warehouse/-/raw/main/wechat/content/%E5%8A%A0%E6%B2%B9%E9%B8%AD.gif"/>
</div><br><br>
来源:https://www.cnblogs.com/luohenyueji/p/18276299
頁:
[1]