loguru 是 python 第三方库,用于替代 logging 库,不需要手动创建 logger,开箱即用;

另外,日志输出内置了彩色功能,颜色和非颜色控制很方便,更加友好。

参考:loguru 官方文档

# 概述

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

loguru 是标准库 logging 的替代品,它不仅能够减少繁琐的配置过程还能实现和 logging 类似的功能,同时还能保证日志记录的线程进程安全,又能够和 logging 相兼容,并进一步追踪异常也能进行代码回溯。

# 基本使用

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

# 安装

loguru 是非标准库,需要事先安装: pip install loguru

# 日志输出

loguru 默认的输出格式是:时间、级别、模块、行号以及日志内容。

# 输出到控制台

安装后,最简单的使用样例如下:

from loguru import logger
logger.debug ('hello, this debug loguru')
logger.info ('hello, this is info loguru')
logger.warning ('hello, this is warning loguru')
logger.error ('hello, this is error loguru')
logger.critical ('hello, this is critical loguru')

上述代码输出如下:

2025-09-22 22:53:31.174 | DEBUG    | __main__:<module>:5 - hello, this debug loguru
2025-09-22 22:53:31.175 | INFO     | __main__:<module>:6 - hello, this is info loguru
2025-09-22 22:53:31.175 | WARNING  | __main__:<module>:7 - hello, this is warning loguru
2025-09-22 22:53:31.175 | ERROR    | __main__:<module>:8 - hello, this is error loguru
2025-09-22 22:53:31.175 | CRITICAL | __main__:<module>:9 - hello, this is critical loguru

# 输出到文件

日志打印到文件的用法也很简单,代码如下,运行时可以将日志打印到 console,也可以打印到文件中去。

from loguru import logger
logger.add ('myloguru.log')
logger.debug ('hello, this debug loguru')
logger.info ('hello, this is info loguru')
logger.warning ('hello, this is warning loguru')
logger.error ('hello, this is error loguru')
logger.critical ('hello, this is critical loguru')

# 处理器参数

Loguru 中,可以使用 logger.configure () 方法来设置日志处理器(handlers)。 handlers 是一个列表,定义了日志的输出处理器。定义内容常为字典形式。格式样例:

from loguru import logger
logger.configure (handlers=[
    {
        "sink": sys.stderr,
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |<lvl>{level:8}</>| {name} : {module}:{line:4} | <cyan>mymodule</> | - <lvl>{message}</>",
        "colorize": True
    },
])

handlers 的常见参数如下

参数含义示例
sink指定日志输出的目标,即标准错误流(控制台)或者是文件中。{"sink": sys.stderr} 输出到标准错误流 <br /> {"sink":"app.log"} 输出到文件
encoding指定文件输出的编码,仅当 sink 是文件时有效。{"encoding":"utf-8"} 指定文件编码方式为 "utf-8"
colorize设置为 True 时,启用终端颜色输出,使日志更易读(级别和固定字符串会根据颜色标记显示颜色)。{"encoding": True} 启用终端颜色输出
filter类型为函数或字符串,用于过滤日志记录。{"filter":"my_module"} 只记录来自指定模块 "my_module" 的日志。
{"filter": lambda record: record ["level"].name =="ERROR"} 只记录 ERROR 级别的日志。
level设置此处理器的最低日志级别。低于此级别的日志不会被此处理器处理。默认情况下,所有级别都会被处理。{"level":"WARNING"} 不记录 WARNING 以下级别的日志
serialize布尔值。设置为 True 时,日志记录会序列化为 JSON 格式,便于结构化存储或传输。默认 False。{"serialize": True} 将日志序列化为 JSON 格式
enqueue布尔值。设置为 True 时,日志记录会异步处理(放入队列),避免阻塞主线程。默认 False。适用于高频日志场景{"enqueue": True} 异步处理日志
catch布尔值。设置为 True 时,处理器会捕获并记录自己的异常(例如,写入文件失败)。默认 False。{"catch": True} 捕获并记录 loguru 自身的异常
rotation定义日志文件的轮转策略。{"rotation":"1 day"} 每天轮转。
{"rotation":"10 MB"} 文件大小超过 10MB 时轮转。
{"rotation":"00:00"} 每天午夜轮转。
retention定义日志文件的保留策略。例如:

"7 days":保留 7 天的日志。
"5 files":保留最新的 5 个文件。
compression定义日志文件的压缩格式。{"compression":"zip"} 压缩为 ZIP。
{"compression":"gz"} :压缩为 GZIP。
backtrace布尔值。设置为 True 时,在异常日志中显示完整的回溯信息(包括调用栈)。默认 False。{"backtrace": True} 在异常日志中显示完整的回溯信息
diagnose布尔值。设置为 True 时,在异常日志中显示更详细的诊断信息(如变量值)。默认 False。注意:这会影响性能。{"diagnose": True} 在异常日志中显示更详细的诊断信息

# 进阶用法

# 显示格式

loguru 默认格式是 时间 | 级别 | 名称:模块:日志内容 ,其中 名称:模块 是写死的,是当前文件的 __name__ 变量,此变量最好不要修改。

工程比较复杂的情况下,自定义模块名称更容易定界定位,避免陷入细节中。可以通过 logger.configure 手工指定模块名称,方法为:

logger.configure 相关参数

  • handlers :表示日志输出句柄或者目的地
  • sink : sys.stderr 表示输出到终端
  • format : 表示日志格式化。{level:8}</> 表示按照日志级别显示颜色。8 表示输出宽度为 8 个字符
  • colorize : True 表示显示颜色
import sys
from loguru import logger
logger.configure (handlers=[
    {
        "sink": sys.stderr,
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |<lvl>{level:8}</>| {name} : {module}:{line:4} | <cyan>mymodule</> | - <lvl>{message}</>",
        "colorize": True
    },
])
logger.debug ('this is debug')
logger.info ('this is info')
logger.warning ('this is warning')
logger.error ('this is error')
logger.critical ('this is critical')

# 写入文件

日志一般需要持久化,除了输出到命令行终端外,还需要写入文件。通过在 logger.configure 新增了 handler ,写入到日志文件中去。示例如下:

import sys
from loguru import logger
logger.configure (handlers=[
    {
        "sink": sys.stderr,
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |<lvl>{level:8}</>| {name} : {module}:{line:4} | <cyan>mymodule</> | - <lvl>{message}</>",
        "colorize": True
    },
    {
        "sink": 'first.log',
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |{level:8}| {name} : {module}:{line:4} | mymodule | - {message}",
        "colorize": False
    },
])
logger.debug ('this is debug')
logger.info ('this is info')
logger.warning ('this is warning')
logger.error ('this is error')
logger.critical ('this is critical')

# 模块名参数化

实际项目开发中,不同模块写日志,需要指定不同的模块名称。因此,模块名称需要参数化,这样实用性更强。

logger.bind (module_name=‘my-loguru’) 通过 bind 方法,实现 module_name 的参数化。 bind 返回一个日志对象,可以通过此对象进行日志输出,这样就可以实现不同模块的日志格式。

import sys
from loguru import logger
logger.configure (handlers=[
    {
        "sink": sys.stderr,
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |<lvl>{level:8}</>| {name} : {module}:{line:4} | <cyan>{extra [module_name]}</> | - <lvl>{message}</>",
        "colorize": True
    },
    {
        "sink": 'first.log',
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |{level:8}| {name} : {module}:{line:4} | {extra [module_name]} | - {message}",
        "colorize": False
    },
])
log = logger.bind (module_name='my-loguru')
log.debug ("this is hello, module is my-loguru")
log2 = logger.bind (module_name='my-loguru2')
log2.info ("this is hello, module is my-loguru2")

# 日志留存、压缩与清理

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

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

  • rotation :将日志记录以文件大小、时间等方式进行分割或划分。
# 设置每天 0 点新创建一个 log 文件:
logger.add ('runtime_{time}.log', rotation='00:00')
# 设置超过 500 MB 新创建一个 log 文件:
logger.add ('runtime_{time}.log', rotation="500 MB")
# 设置每隔一个周新创建一个 log 文件:
logger.add ('runtime_{time}.log', rotation='1 week')
  • compression :对日志进行压缩后留存。
# 设置使用 zip 文件格式保存
logger.add ('runtime_{time}.log', compression='zip')
# 设置使用 gz 文件格式保存
logger.add ('runtime_{time}.log', compression='gz')
  • retention :只保留一段时间内的日志并对超期的日志进行删除。
from loguru import logger
import datetime
# 设置日志文件最长保留 15 天:
logger.add ('runtime_{time}.log', retention='15 days')
# 设置日志文件最多保留 10 个:
logger.add ('runtime_{time}.log', retention=10)
# retention 的参数也可以是一个 datetime.timedelta 对象,比如设置日志文件最多保留 5 个小时:
logger.add ('runtime_{time}.log', retention=datetime.timedelta (hours=5))

# 序列化为 json 格式

通过 serialize 参数可以日志转化成序列化的 json 格式,最后将导入类似于 MongoDB、ElasticSearch 这类数 NoSQL 数据库中用作后续的日志分析。

loguru 保存成结构化 json 格式非常简单,只需要设置 serialize=True 参数即可。代码如下

from loguru import logger
logger.add ('json.log', serialize=True, encoding='utf-8')
logger.debug ('this is debug message')
logger.info ('this is info message')
logger.error ('this is error message')

# 并发安全

loguru 默认是线程安全的,但不是多进程安全的,如果使用了多进程安全,需要添加参数 enqueue=True,样例代码如下:

logger.add ("somefile.log", enqueue=True)

# 使用示例

# 多模块调用

设置一个基础的日志模块,所有其他模块统一调用基础模块记录日志

# -*- coding: utf-8 -*-
# loguru_base.py
# 基础日志模块,提供日志配置和获取 loguru 实例的功能
import sys
from loguru import logger
logger.configure (handlers=[
    {
        "sink": sys.stderr,
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |<lvl>{level:8}</>| {name} : {module}:{line:4} | <cyan>{extra [module]}</> | - <lvl>{message}</>",
        "colorize": True
    },
    {
        "sink": "app.log",
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |<lvl>{level:8}</>| {name} : {module}:{line:4} | <cyan>{extra [module]}</> | - <lvl>{message}</>",
        "colorize": True
    }
])
def get_logger (module_name: str = "default"):
    return logger.bind (module=module_name)
# 导出 get_logger 函数供其他模块使用
__all__ = ["get_logger"]

在其余模块中调用:

from loguru_base import get_logger
logger = get_logger ("test_module")
logger.info ("这是一个信息日志")
logger.error ("这是一个错误日志")
logger.debug ("这是一个调试日志")

# 在 Qt 中应用

我们希望将日志信息输出到一个 QTextEdit 中,首先调整基础日志模块,去除掉终端输出并新增 UI 输出

import sys
from loguru import logger
logger.configure (handlers=[
    {
        "sink": sys.stderr,
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |<lvl>{level:8}</>| {name} : {module}:{line:4} | <cyan>{extra [module]}</> | - <lvl>{message}</>",
        "colorize": True
    },
    {
        "sink": "app.log",
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |<lvl>{level:8}</>| {name} : {module}:{line:4} | <cyan>{extra [module]}</> | - <lvl>{message}</>",
        "colorize": True
    }
])
def get_logger (module_name: str = "default"):
    return logger.bind (module=module_name)
def add_gui_sink (widget):
    logger.add (widget.append, format="{time:YYYY-MM-DD HH:mm:ss.SSS} |<lvl>{level:8}</>| {name} : {module}:{line:4} | <cyan>{extra [module]}</> | - <lvl>{message}</>", level="INFO")
# 导出 get_logger 和 add_gui_sink 函数供其他模块使用
__all__ = ["get_logger", "add_gui_sink"]

随后,在 Qt 中,只需要使用 self.logger.info (message) 即可让日志信息输出到 UI 中,示例如下

from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QLineEdit, QTextEdit
from loguru_base import get_logger, add_gui_sink
class MainWindow (QMainWindow):
    def __init__(self):
        super ().__init__()
        self.setWindowTitle ("Simple PySide6 App")
        # 设置初始大小
        self.resize (600, 600)
        layout = QVBoxLayout ()
        self.button = QPushButton ("Click Me")
        self.text_input = QLineEdit ()
        self.text_input.setPlaceholderText ("Enter some text here...")
        self.output_box = QTextEdit ()
        self.output_box.setReadOnly (True)
        
        layout.addWidget (self.button)
        layout.addWidget (self.text_input)
        layout.addWidget (self.output_box)
        container = QWidget ()
        container.setLayout (layout)
        self.setCentralWidget (container)
        self.bind ()
        # 获取 logger 实例
        self.logger = get_logger ("main")
        # 设置 UI handler
        add_gui_sink (self.output_box)
    
    def bind (self):
        self.button.clicked.connect (self.on_button_click)
        self.text_input.returnPressed.connect (self.on_text_input)
    
    def on_button_click (self):
        message = "Button clicked!"
        self.logger.info (message)
    
    def on_text_input (self):
        text = self.text_input.text ()
        message = f"You entered: {text}"
        self.logger.info (message)
        self.text_input.clear ()
if __name__ == "__main__":
    app = QApplication ([])
    window = MainWindow ()
    window.show ()
    app.exec ()

# 使用装饰器记录函数调用

通过使用装饰器,记录函数的调用和执行时间:

import time
import sys
from loguru import logger
logger.configure (handlers=[
    {
        "sink": sys.stderr,
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |<lvl>{level:8}</>| {name} : {module}:{line:4} | <cyan>{extra [module]}</> | - <lvl>{message}</>",
        "colorize": True
    }
])
def log_function_call (func):
    def wrapper (*args, **kwargs):
        start_time = time.time ()
        result = func (*args, **kwargs)
        end_time = time.time ()
        elapsed_time = end_time - start_time
        logger.bind (module=func.__name__).info (f"{func.__name__} executed in {elapsed_time:.2f} seconds.")
        return result
    return wrapper
# 应用装饰器来记录函数调用
@log_function_call
def example_function ():
    # 一些需要记录执行时间的代码
    time.sleep (2)
# 调用带有装饰器的函数
if __name__ == "__main__":
    example_function ()
# 输出示例
>>> 2025-09-24 21:12:50.875 |INFO    | __main__ : 装饰器:  19 | example_function | - example_function executed in 2.00 seconds.
更新于 阅读次数