Loguru 是一个现代化的、开箱即用的 Python 日志记录库,旨在让日志记录变得简单、直观、强大。它彻底改变了传统 Python logging 模块的复杂配置模式。

安装

pip install loguru

QuickStart

from loguru import logger
import sys

# 移除默认配置(可选)
logger.remove()

# 控制台输出(开发环境)
logger.add(
    sys.stderr,
    format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | "
           "<level>{level: <8}</level> | "
           "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
           "<level>{message}</level>",
    level="DEBUG",
    colorize=True
)

# 文件输出(生产环境)
logger.add(
    "logs/app_{time}.log",
    rotation="00:00",          # 每天午夜轮转
    retention="30 days",       # 保留30天
    compression="zip",
    level="INFO",
    format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} | {message}"
)

# 使用
logger.info("系统启动")
logger.debug(f"参数: {params}")
logger.error("数据库连接失败", user_id=123)

移除配置

使logger.remove() 移除配置,remove放在不同的位置会移除不同的配置

import sys
from loguru import logger

# 移除默认配置
logger.remove()
logger.add(
    sys.stderr,
    format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | "
           "<level>{level: <8}</level> | "
           "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
           "<level>{message}</level>",
    level="DEBUG",
    colorize=True
)
# 移除个人配置
logger.remove()

核心配置

logger.add()是 loguru 的核心配置方法,用于添加日志处理器(handler),决定日志输出到哪里以及如何格式化。

基本语法:

from loguru import logger

# 基本格式
handler_id = logger.add(
    sink,           # 输出目标
    level="INFO",   # 记录级别
    format="...",   # 格式字符串
    filter=None,    # 过滤器
    colorize=None,  # 是否彩色
    **kwargs        # 其他参数
)

sink 参数详解

输出到控制台

import sys

# 输出到标准错误(默认)
logger.add(sys.stderr, level="DEBUG")

# 输出到标准输出
import sys
logger.add(sys.stdout, level="INFO")

# 自定义输出函数
def my_sink(message):
    print(f"自定义输出: {message}")

logger.add(my_sink)

输出到文件

# 简单文件
logger.add("app.log")  # 追加模式

# 带时间戳的文件名
logger.add("app_{time}.log")           # app_2023-01-01_12-30-00.log
logger.add("app_{time:YYYY-MM}.log")   # app_2023-01.log

# 按大小轮转
logger.add("app.log", rotation="100 MB")

# 按时间轮转
logger.add("app.log", rotation="00:00")          # 每天午夜
logger.add("app.log", rotation="1 week")         # 每周
logger.add("app.log", rotation="1 month")        # 每月
logger.add("app.log", rotation="100 MB 1 day")   # 每天或100MB

# 保留策略
logger.add("app.log", retention="10 days")       # 保留10天
logger.add("app.log", retention=5)               # 保留5个文件

# 压缩旧日志
logger.add("app.log", compression="zip")         # zip格式
logger.add("app.log", compression="gz")          # gzip格式

输出到多种目标

# 同时输出到控制台和文件
logger.add(sys.stderr, level="INFO")
logger.add("app.log", level="DEBUG", rotation="100 MB")

# 不同级别到不同文件
logger.add("info.log", level="INFO", rotation="1 day")
logger.add("error.log", level="ERROR", rotation="10 MB")
logger.add("debug.log", level="DEBUG", retention="5 days")

输出到其他系统

# 发送到 HTTP 接口
import requests

def send_to_http(message):
    requests.post("https://logs.example.com", 
                  json={"log": message.record})

logger.add(send_to_http)

# 发送到数据库
import sqlite3

def send_to_db(message):
    conn = sqlite3.connect("logs.db")
    conn.execute("INSERT INTO logs VALUES (?, ?)", 
                 (message.record["time"], message.record["message"]))
    conn.commit()

logger.add(send_to_db)

format 参数详解

# 默认格式
logger.add(sys.stderr, format="{time} | {level} | {message}")

# 详细格式
logger.add(
    sys.stderr,
    format="{time:YYYY-MM-DD HH:mm:ss.SSS} | "
           "{level: <8} | "
           "{name}:{function}:{line} | "
           "{message}"
)

# 带颜色的格式(控制台)
logger.add(
    sys.stderr,
    format="<green>{time}</green> | "
           "<level>{level}</level> | "
           "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
           "<level>{message}</level>"
)

所有可用字段,字段需要加大括号,如{time}

{
    "time":        "2023-01-01 12:30:00.123",  # 时间戳
    "level":       "INFO",                      # 级别
    "message":     "Hello World",              # 消息内容
    "name":        "__main__",                 # 模块名
    "function":    "main",                     # 函数名
    "line":        42,                         # 行号
    "file":        "app.py",                   # 文件名
    "process":     12345,                      # 进程ID
    "thread":      67890,                      # 线程ID
    "elapsed":     1.234,                      # 从启动到现在的秒数
    "exception":   "ZeroDivisionError",        # 异常类型
}

level 参数详解

# 日志级别从低到高
logger.add("trace.log", level="TRACE")     # 最详细
logger.add("debug.log", level="DEBUG")     # 调试
logger.add("info.log", level="INFO")       # 信息(默认)
logger.add("success.log", level="SUCCESS") # 成功
logger.add("warning.log", level="WARNING") # 警告
logger.add("error.log", level="ERROR")     # 错误
logger.add("critical.log", level="CRITICAL") # 严重

# 动态级别
import sys
logger.add(
    sys.stderr,
    level=lambda record: "DEBUG" if record["function"] == "test" else "INFO"
)

filter 参数详解

# 只记录特定模块
logger.add("app.log", filter=lambda record: "my_module" in record["name"])

# 排除特定消息
def no_secrets(record):
    message = record["message"]
    return "password" not in message and "secret" not in message

logger.add("app.log", filter=no_secrets)

# 按级别过滤
logger.add("app.log", filter=lambda record: record["level"].no >= 30)  # >= WARNING

colorize 参数详解

# 自动检测(默认)
logger.add(sys.stderr, colorize=None)

# 强制彩色
logger.add(sys.stderr, colorize=True)

# 强制无彩色
logger.add(sys.stderr, colorize=False)

# 自定义颜色
logger.add(
    sys.stderr,
    format="<red>{time}</red> <blue>{message}</blue>",
    colorize=True
)

序列化输出

`

异步应用配置

# FastAPI/Django 配置
logger.add(
    "api.log",
    rotation="00:00",
    format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {extra[request_id]} | {message}",
    filter=lambda record: "uvicorn" not in record["name"],  # 过滤框架日志
    enqueue=True  # 多线程安全
)

# 使用
@app.middleware("http")
async def add_log_context(request: Request, call_next):
    request_id = request.headers.get("X-Request-ID", "unknown")
    with logger.contextualize(request_id=request_id):
        response = await call_next(request)
        return response

高级日志选项控制器

logger.opt()是 loguru 的高级日志选项控制器,允许你临时修改单条日志记录的行为、格式和内容。

from loguru import logger

# opt() 返回一个特殊的记录器实例
special_logger = logger.opt()

# 链式调用
logger.opt(exception=True).error("错误详情")

异常处理

exception=True控制是否在日志中包含完整的异常堆栈信息。

# 不记录异常堆栈
try:
    1 / 0
except:
    logger.error("发生了错误")  # 只记录消息,没有堆栈

# 记录异常堆栈
try:
    1 / 0
except:
    logger.opt(exception=True).error("发生了错误")  
    # 输出:错误消息 + 完整堆栈跟踪

# 等价于 logger.exception()
logger.opt(exception=True).error("错误")  # 等价于 logger.exception("错误")

异常深度控制

try:
    def inner():
        return 1 / 0
    inner()
except:
    # 只显示最近3层堆栈
    logger.opt(exception=True, depth=3).error("错误")
    
    # 不显示堆栈,只显示异常类型
    logger.opt(exception=False).error("错误")

调用深度

depth=N调整日志记录中文件名、函数名、行号的显示深度。

# utils.py
def helper():
    # depth=0: 显示 helper 函数的位置
    logger.opt(depth=0).info("helper 被调用")
    
    # depth=1: 显示调用 helper 的位置
    logger.opt(depth=1).info("上一级调用")
    
    # depth=2: 显示调用者的上一级
    logger.opt(depth=2).info("上上级调用")

# main.py
def main():
    helper()  # 从 main 调用 helper

depth = 0时,终端中会输出Info | utils.py::xxx行 | helper 被调用 这样的日志,到了depth = 1后,终端中会输出Info | main.py::xxx行 | 上一级调用 这样的日志,以此类推

通常logger.opt(depth=1)这个足够满足大部分的应用场景

访问原始记录

record=True允许在日志消息中访问并修改 record 字典。

# 添加额外字段到当前日志
logger.opt(record=True).info(
    "用户 {record[extra][user]} 的操作", 
    user="Alice"
)

# 动态修改消息
def add_timestamp(message):
    message.record["extra"]["timestamp"] = message.record["time"].isoformat()

logger.opt(record=True).info("当前时间: {record[extra][timestamp]}")

# 条件格式化
logger.opt(record=True).info(
    "状态: {record[extra][status] if 'status' in record['extra'] else '未知'}"
)

延迟计算

lazy=True可以延迟计算日志消息,只在需要记录时才计算(性能优化)。

V

颜色控制

colors=True/False强制启用或禁用单条日志的颜色。

import sys

# 配置带颜色的处理器
logger.add(sys.stderr, colorize=True, format="<level>{message}</level>")

# 这条日志有颜色
logger.info("普通信息")

# 这条日志强制无颜色
logger.opt(colors=False).info("无颜色信息")

# 这条日志强制有颜色(即使全局配置colorize=False)
logger.opt(colors=True).info("强制彩色信息")

原始输出

raw=True绕过格式化器,直接输出原始消息。

# 普通输出(经过格式化)
logger.add(sys.stderr, format="[INFO] {message}")
logger.info("Hello")  # 输出: [INFO] Hello

# 原始输出(绕过格式)
logger.opt(raw=True).info("Hello\n")  # 输出: Hello(直接换行)

# 组合使用
logger.opt(raw=True, colors=True).info("<red>错误</red>\n")

记录捕获

capture=True/False控制是否捕获并存储日志记录。

# 创建不带捕获的记录器
no_capture_logger = logger.opt(capture=False)

# 这条日志不会被任何处理器捕获
no_capture_logger.info("秘密消息")

# 只被特定处理器捕获
error_logger = logger.opt(capture=lambda: False)  # 自定义逻辑

输出

基础输出

from loguru import logger

# INFO 级别(默认)
logger.info("这是一条普通信息")

# DEBUG 级别(调试)
logger.debug("调试信息,通常用于开发阶段")

# WARNING 级别
logger.warning("警告信息,需要注意")

# ERROR 级别
logger.error("错误信息,操作失败")

# CRITICAL 级别
logger.critical("严重错误,系统可能无法继续运行")

# SUCCESS 级别(loguru 特有)
logger.success("操作成功!")

# TRACE 级别(最详细)
logger.trace("最详细的跟踪信息")

# 直接使用 log() 方法指定级别
logger.log("INFO", "使用 log 方法指定级别")

自动捕获异常

# 方法1:装饰器自动捕获
@logger.catch
def risky_function():
    return 1 / 0

# 方法2:上下文管理器
def process_data():
    try:
        result = 1 / 0
    except ZeroDivisionError:
        logger.exception("除以零错误")  # 自动包含完整堆栈

# 方法3:带级别控制
try:
    risky_operation()
except Exception as e:
    logger.opt(exception=True).error("操作失败")  # 只记录错误级别

# 方法4:详细配置
@logger.catch(level="ERROR", reraise=False)
def critical_function():
    # 函数内部异常会被记录但不重新抛出
    pass

文章作者: Vsoapmac
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 soap的会员制餐厅
python 第三方库
喜欢就支持一下吧