pip install loguru
from loguru import logger
logger.debug("测试日志")
logger.info("普通日志")
logger.warning("警告日志")
logger.error("错误日志")
2026-07-26 10:18:55.570 | DEBUG | __main__:<module>:4 - 测试日志
2026-07-26 10:18:55.570 | INFO | __main__:<module>:5 - 普通日志
2026-07-26 10:18:55.570 | WARNING | __main__:<module>:6 - 警告日志
2026-07-26 10:18:55.570 | ERROR | __main__:<module>:7 - 错误日志
DEBUG > INFO > WARNING > ERROR
当加入 logger.remove() 控制台输出为空
from loguru import logger
logger.remove()
logger.debug("测试日志")
logger.info("普通日志")
logger.warning("警告日志")
logger.error("错误日志")
2, 丰富的日志级别
Loguru 提供了 7 个独特的日志级别,涵盖了从底层诊断到严重故障的各种场景:
TRACE (5):记录程序执行路径的极细粒度细节,用于深度诊断。
DEBUG (10):开发人员日常调试使用的信息。
INFO (20):记录程序正常操作的关键节点信息。
SUCCESS (25):Loguru 特有级别,用于明确指示某个操作已成功完成。
WARNING (30):提示发生了不寻常的事件,但程序仍可继续运行。
ERROR (40):记录导致特定操作失败的错误条件。
CRITICAL (50):记录阻止核心功能正常工作的严重错误
3,eg_1:
import sys
import time
from loguru import logger
# 1. 移除默认的控制台输出,避免重复日志
logger.remove()
# 2. 添加带颜色的控制台输出(仅显示 INFO 及以上级别)
logger.add(
sys.stderr,
colorize=True,
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="INFO"
)
# 3. 配置文件输出(记录 DEBUG 及以上级别,支持轮转和压缩)
logger.add(
"logs/app_{time:YYYY-MM-DD}.log",
rotation="100 MB",
retention="30 days",
compression="zip",
level="DEBUG",
backtrace=True,
diagnose=True
)
# 4. 定义业务处理函数
@logger.catch
def process_user(user_id: str, action: str):
"""处理用户操作,使用 @logger.catch 自动捕获异常"""
logger.info(f"用户 {user_id} 执行操作: {action}")
if action == "dangerous":
raise ValueError(f"用户 {user_id} 尝试执行危险操作!")
time.sleep(0.1) # 模拟业务处理
logger.success(f"用户 {user_id} 操作成功完成: {action}")
# 5. 测试代码
process_user("user_001", "login")
process_user("user_002", "dangerous") # 触发异常,自动记录详细堆栈
```
```shell
2026-07-26 10:35:23 | INFO | __main__:process_user:35 - 用户 user_001 执行操作: login
2026-07-26 10:35:23 | SUCCESS | __main__:process_user:41 - 用户 user_001 操作成功完成: login
2026-07-26 10:35:23 | INFO | __main__:process_user:35 - 用户 user_002 执行操作: dangerous
2026-07-26 10:35:23 | ERROR | __main__:<module>:46 - An error has been caught in function '<module>', process 'MainProcess' (14048), thread 'MainThread' (18204):
Traceback (most recent call last):
> File "F:\0026_Car_Pro\data_agent\v0\day02_loguru\1.py", line 46, in <module>
process_user("user_002", "dangerous") # 触发异常,自动记录详细堆栈
└ <function process_user at 0x00000180B18A3E20>
File "F:\0026_Car_Pro\data_agent\v0\day02_loguru\1.py", line 38, in process_user
raise ValueError(f"用户 {user_id} 尝试执行危险操作!")
└ 'user_002'
ValueError: 用户 user_002 尝试执行危险操作!
4,eg_2:
import sys
from pathlib import Path
from loguru import logger
# 1. 自动创建日志目录,避免路径不存在导致报错
LOG_DIR = Path("logs")
LOG_DIR.mkdir(parents=True, exist_ok=True)
# 2. 移除默认的日志输出(避免控制台和文件重复打印)
logger.remove()
# 3. 配置控制台输出(仅显示 INFO 及以上级别,带颜色)
logger.add(
sys.stdout,
level="INFO",
colorize=True,
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <level>{message}</level>"
)
# 4. 配置文件输出:普通日志 (INFO 及以上)
logger.add(
LOG_DIR / "app_{time:YYYY-MM-DD}.log",
level="INFO",
rotation="10 MB", # 文件大小超过 10MB 自动切割
retention="7 days", # 保留 7 天
encoding="utf-8",
format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}"
)
# 5. 配置文件输出:专门记录报错 (ERROR 及以上)
logger.add(
LOG_DIR / "error_{time:YYYY-MM-DD}.log",
level="ERROR",
rotation="10 MB",
retention="30 days", # 报错日志保留更长时间
backtrace=True, # 记录完整的调用栈
diagnose=True, # 自动诊断变量值
encoding="utf-8"
)
# 6. 业务代码测试
@logger.catch # 自动捕获函数内未处理的异常,并写入 error.log
def divide(a, b):
return a / b
if __name__ == "__main__":
logger.info("程序启动,开始执行业务逻辑...")
try:
# 模拟业务处理
logger.info("正在处理数据...")
result = divide(10, 0) # 触发 ZeroDivisionError
except Exception as e:
# 在 except 块中使用 exception() 记录完整堆栈
logger.exception("业务处理过程中发生严重错误")
logger.warning("这是一条警告信息,会写入 app.log 但不会写入 error.log")
2026-07-26 10:40:41 | INFO | 程序启动,开始执行业务逻辑...
2026-07-26 10:40:41 | INFO | 正在处理数据...
2026-07-26 10:40:41 | ERROR | An error has been caught in function '<module>', process 'MainProcess' (6036), thread 'MainThread' (18412):
Traceback (most recent call last):
> File "F:\0026_Car_Pro\data_agent\v0\day02_loguru\2.py", line 54, in <module>
result = divide(10, 0) # 触发 ZeroDivisionError
└ <function divide at 0x0000028ED4D89940>
File "F:\0026_Car_Pro\data_agent\v0\day02_loguru\2.py", line 45, in divide
return a / b
│ └ 0
└ 10
from contextvars import ContextVar
request_id_ctx_var = ContextVar("request_id", default="1")
print(request_id_ctx_var)
示例3:
import asyncio
import sys
from pathlib import Path
from loguru import logger
#from app.app_config import app_config
from app.context import request_id_ctx_var
# 配置日志格式
log_format = (
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
"<level>{level: <8}</level> | "
"<magenta>request_id - {extra[request_id]}</magenta> | "
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
"<level>{message}</level>"
)
# 注入request_id到日志记录中
def inject_request_id(record):
request_id = request_id_ctx_var.get()
record["extra"]["request_id"] = request_id
logger.remove()
# 给日志打补丁,使其支持注入request_id
logger = logger.patch(inject_request_id)
# 控制台日志(保持原有逻辑)
# if app_config.logging.console.enable:
# logger.add(sink=sys.stdout, level=app_config.logging.console.level, format=log_format)
if True:
logger.add(sink=sys.stdout, level="INFO", format=log_format)
# 文件日志:修改为项目根目录下的 logs 文件夹
#if app_config.logging.file.enable:
if True:
# 1. 获取项目根目录(当前文件所在目录的上层/上层,根据实际结构调整)
# 核心逻辑:__file__ 是当前文件路径,.parent 向上找根目录
# 如果你不确定层级,可以打印调试:print(Path(__file__).absolute())
PROJECT_ROOT = Path(__file__).parents[2] # 根据实际项目结构调整
# 2. 拼接日志路径:项目根目录 / logs / app.log
LOG_DIR = PROJECT_ROOT / "logs"
LOG_FILE = LOG_DIR / "app.log"
# 3. 创建日志目录(确保存在)
LOG_DIR.mkdir(parents=True, exist_ok=True)
# 4. 添加文件日志处理器
logger.add(
sink=LOG_FILE,
level="DEBUG",
format=log_format,
rotation="10 MB",
retention="7 days",
encoding="utf-8"
)
if __name__ == '__main__':
async def print_log(request: str):
# 打印日志
logger.info(request)
async def test1():
# 接收到请求
request_id_ctx_var.set("request-1")
# 模拟处理
await asyncio.sleep(1)
await print_log("request-1")
async def test2():
# 接收到请求
request_id_ctx_var.set("request-2")
# 模拟处理
await asyncio.sleep(1)
await print_log("request-2")
async def main():
await asyncio.gather(test1(), test2())
asyncio.run(main())
'''
<ContextVar name='request_id' default='1' at 0x000002364675DDA0>
1
2026-07-26 10:58:06.697 | INFO | request_id - request-1 | __main__:print_log:68 - request-1
2026-07-26 10:58:06.698 | INFO | request_id - request-2 | __main__:print_log:68 - request-2
'''