Python loguru

Python loguru

在使用Python进行程序开发的过程中,会遇到需要记录的日志的需求,常常会用到Python自带的logging模块,但是logging需要我们进行不同的初始化等相关工作。对应不熟悉该模块的同学来说,还是有些费劲的,比如需要配置 Handler/Formatter 等。而且随着业务的复杂度提升, 对日志收集有着更高的要求, 例如: 日志分类, 文件存储, 异步写入, 自定义类型等等。

loguru 是一个 Python 简易且强大的第三方日志记录库,该库旨在通过添加一系列有用的功能来解决标准记录器的注意事项,从而减少 Python 日志记录的痛苦。

loguru

Installation

1
pip install loguru

log to console

1
2
3
4
5
6
from loguru import logger

logger.debug("That's it, beautiful and simple logging!")

#console print
#2024-01-14 08:47:45.344 | DEBUG | __main__:<module>:3 - That's it, beautiful and simple logging!

log formatiing

loguru默认格式是时间、级别、名称+模块和日志内容,其中名称+模块是写死的,一般场景下不建议修改,但在业务复杂的场景下,自定义模块名称,是非常有用的,我们可以通过logger.configure手工指定模块名称。如下如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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.info("this is {}", "a info log")
logger.info("this is {}", 3)
logger.info("this is {:.2f}", 3)
1
2
3
4
5
6
7
8
import sys
from loguru import logger

logger.remove()
logger.add(sys.stdout, format="{time:YYYY-MM-DD at HH:mm:ss} | <red>{level}</red> | <green>{file}</green> | <b><i>{message}</i></b>")
logger.info("Hello, world!")
logger.info("Hello, {name}!", name="everyone")

format 中,可以通过 {param} 的形式设置内容,通过 <tag></tag> 的形式设置格式。

常见的内容参数有:

参数 含义
time 时间
level 日志等级
file 文件名
message 日志信息
path 文件路径
function 函数
line 行数
module 模块
process 进程信息
thread 线程信息
tzinfo 时区信息
exception 异常信息

log to file

1
2
3
logger.add("log/file_1.log")  # sink

logger.info("this is a info log")

log rotation

1
2
3
4
5
6
7
8
logger.add("log/file_2.log", rotation='10 KB')

for i in range(100):
logger.info("this is a info log")
logger.debug("this is a debug log")
logger.warning("this is a warning log")
logger.error("this is a error log")
logger.critical("this is a critical log")

关于rotation参数还有常见的如下用法:

1
2
3
4
logger.add("log.log", rotation="50 MB")      # 文件超过50M则另起一个文件
logger.add("log.log", rotation="00:00") # 每天00:00另起一个文件
logger.add("log.log", rotation="1 week") # 每周另起一个文件
logger.add("log.log", rotation="10 days") # 每10天另起一个文件

其他常用设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# retention 参数可以设置日志保存时间,到时间后日志会自动清理,注意与 rotation 区分
logger.add("log.log", retention="10 days")

# compression 可以对关闭的日志(如 rotation 处理的日志)进行压缩,节约空间
logger.add("log.log", compression="zip")

# enqueue=True 可以支持异步写入,实现多进程安全
logger.add("log.log", enqueue=True)

# filter 参数可以设置日志的过滤规则
# 过滤不包含 hello 的日志
logger.add("log.log", filter=lambda x: "hello" not in x["message"])

# encoding 设置编码方式
# level 设置日志等级,大于该等级的日志会被记录
logger.add("log.log", encoding="utf-8", level="INFO")

#异步写入
logger.add("log.log", enqueue=True)

#序列化为json写入
logger.add("log1.log", serialize=True)

常用的推荐设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import os
import time
from loguru import logger

logger_dir = "./log" # 这里是日志的存放目录,需要根据你的项目进行修改

log_path = os.path.join(logger_dir, f'{time.strftime("%Y%m")}', '{time:YYYY_MM_DD}.log')
logger.add(
log_path,
rotation="00:00",
retention="30 days",
enqueue=True,
encoding="utf-8",
level="INFO"
)

与PyTest结合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pytest
from _pytest.logging import LogCaptureFixture
from loguru import logger

def some_func(i, j):
logger.info('Oh no!')
logger.info('haha')
return i + j

@pytest.fixture
def caplog(caplog: LogCaptureFixture):
handler_id = logger.add(caplog.handler, format="{message}")
yield caplog
logger.remove(handler_id)

def test_some_func_logs_warning(caplog):
assert some_func(-1, 3) == 2
assert "Oh no!" in caplog.text

简单封装日志方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from loguru import logger
import os


# 获取项目路径
def get_pro_path():
pro_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
return pro_path


def get_logger():
logger.add(os.path.join(get_pro_path(), "mytest.log"), rotation="500 MB")
return logger

日志管理器类

在日常使用中,我们可以封装一个日志管理器类,并在其中配置日志文件存储、日志轮转等功能。然后可以在其他文件中直接导入和使用。
log_manager.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from loguru import logger
import os

class LogManager:
def __init__(self, log_file="app.log", log_level="DEBUG", rotation="1 MB", retention="7 days"):
self.log_file = log_file
self.log_level = log_level
self.rotation = rotation
self.retention = retention
self._configure_logger()

def _configure_logger(self):
"""配置日志记录器"""
log_path = os.path.join(os.getcwd(), self.log_file)

# 设置日志输出格式和级别
logger.remove() # 移除默认配置
logger.add(
log_path,
level=self.log_level,
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
rotation=self.rotation, # 设置文件轮转条件
retention=self.retention, # 设置文件保留时间
compression="zip" # 可选,压缩旧的日志文件
)

def get_logger(self):
"""返回logger实例"""
return logger

# 创建全局的日志实例
log_manager = LogManager(log_file="app.log")

# 获取日志对象
logger = log_manager.get_logger()

现在我们可以在项目的其他文件中使用它

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from log_manager import logger  # 导入封装的logger

def example_function():
try:
logger.info("Function started.")
# 模拟一些操作
result = 10 / 0 # 触发除零错误
logger.info(f"Function result: {result}")
except Exception as e:
logger.error(f"Error occurred: {e}")

if __name__ == "__main__":
example_function()

通过 loguru 和封装,您可以方便地管理和存储日志文件,支持文件轮转和日志保留。
你可以在多个模块中导入和使用同一个 logger 实例,支持跨文件调用。

pytest case调用

1
2
3
4
5
6
7
8
9
10
11
12
"""
loguru使用
"""
from public_fun.log_fun import get_logger
from assertpy import assert_that
logger = get_logger()


def test_fun1():
logger.info('我需要比较1')
assert_that(1).is_not_equal_to(1)


Python loguru
https://skynetboys.github.io/2024/01/14/Python-loguru/
Author
Edison
Posted on
January 14, 2024
Licensed under