专栏收录: python高频库对比
本专栏将持续更新在工程领域高频使用的python库之间的对比
文章概览:
- 简单介绍日志管理常用的python库及特点
- 对比loguru和logging的异同
- 结合代码示例具体说明两个库的差异
Python中常用的日志打印和管理模块有以下几种:
-
logging模块:Python标准库中内置的日志记录模块,提供了功能强大的日志记录和管理功能,支持多种日志级别、日志格式化、日志处理器等。
-
loguru模块:一个灵活且功能丰富的日志库,提供了简单易用的API和丰富的功能,支持异步日志、动态调整日志级别等特性。
-
logbook模块:一个Python日志记录库,设计简单而强大,支持多种日志处理器和格式,可以很容易地集成到各种Python项目中。
-
structlog模块:一个结构化日志记录库,使日志记录更容易解析和分析,支持结构化的日志消息、自定义处理器等功能。
-
colorlog模块:一个给日志加上颜色的库,可以根据日志级别或者其他条件给日志添加颜色,提高日志的可读性。
这些日志打印和管理模块各有特点,按项目需求和个人喜好选择即可。其中,loguru
和logging
模块是Python中最常用的两个日志记录模块,文章将重点对比这2个库
2.loguru
和logging
对比
相同点:
-
功能:两者都提供了强大的日志记录功能,可以方便地记录各种级别的日志信息,也可以用于将日志消息输出到不同的目标,如控制台、文件、邮件等。
-
日志级别:都支持多种日志级别,如DEBUG、INFO、WARNING、ERROR、CRITICAL等。
-
格式化:都支持日志信息的格式化,可以自定义日志的格式,非常灵活。
-
错误处理: loguru 和 logging 都能够处理程序中的错误信息,并将其记录为日志消息。
不同点:
-
API设计:
logging
模块的API相对较复杂,需要通过配置Logger、Handler、Formatter等来完成日志记录和处理。loguru
模块的API设计更为简洁和直观,只需使用一个全局logger对象即可完成日志记录。
-
异常捕捉:
loguru
提供了一个更加简洁和现代化的 API,使得日志记录和异常捕获变得更容易logging
则需要进行一定显示操作才能达到效果,更麻烦一些
-
日志旋转:
loguru
模块天然支持日志文件的自动旋转,可以按照时间或文件大小进行分割。logging
模块的日志旋转需要借助logging.handlers
模块中的RotatingFileHandler
或TimedRotatingFileHandler
。
-
性能:
- 对于不同的场景,两个库之间的性能也有所不同,通常loguru会更慢一些,毕竟它提供了更多的特性和便利性,这自然会增加一些额外的处理开销,性能上的差异会涉及到很多的因素,如格式化,配置开销,异步支持等,建议根据实际需求进行大量测试后得到具体应用场景下性能对比
3.代码示例
loguru库安装
pip install loguru
相同点:
使用logging
模块:
import logging
# 创建一个 logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# 创建一个 handler,用于写入日志文件
file_handler = logging.FileHandler('my_loging_file.log')
# 定义 handler 的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
# 给 logger 添加 handler
logger.addHandler(file_handler)
# 记录不同级别的日志
logger.debug("这是一条 DEBUG 级别的日志,通常用于调试")
logger.info("这是一条 INFO 级别的日志,确认一切按预期运行")
logger.warning("这是一条 WARNING 级别的日志,表明可能出现问题")
logger.error("这是一条 ERROR 级别的日志,由于更严重的问题,软件已不能执行一些功能")
logger.critical("这是一条 CRITICAL 级别的日志,一个严重的错误,程序可能无法继续运行")
# 这条日志会被写入到 my_loging_file.log 文件中,因为已经设置了 handler
logger.info("这条日志会被写入到 my_loging_file.log 文件中")
使用loguru
模块:
from loguru import logger
# 自定义日志格式
logger.add("my_loguru_file.log", format="{time} {level} {message}")
# 记录不同级别的日志
logger.debug("这是一条 DEBUG 级别的日志,通常用于调试")
logger.info("这是一条 INFO 级别的日志,确认一切按预期运行")
logger.warning("这是一条 WARNING 级别的日志,表明可能出现问题")
logger.error("这是一条 ERROR 级别的日志,由于更严重的问题,软件已不能执行一些功能")
logger.critical("这是一条 CRITICAL 级别的日志,一个严重的错误,程序可能无法继续运行")
# 写入带有自定义格式的日志
logger.info("这条日志会被写入到 my_loguru_file.log 文件中")
在这个示例中,logging
和loguru
都自定义输出格式、设置多种日志级别
不同点:
- API设计
loguru 提供了更简单、更直观的 API,而 logging 模块的 API 则更为复杂。
使用logging
模块:
import logging
# 配置日志器
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# 创建一个处理器,将日志输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# 创建一个格式化器
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# 将格式化器添加到处理器
ch.setFormatter(formatter)
# 将处理器添加到日志器
logger.addHandler(ch)
# 记录日志
logger.debug('这是一条 debug 级别的日志')
logger.info('这是一条 info 级别的日志')
logger.warning('这是一条 warning 级别的日志')
使用loguru
模块:
from loguru import logger
# 无需额外配置,直接使用全局日志器记录日志
logger.debug('这是一条 debug 级别的日志')
logger.info('这是一条 info 级别的日志')
logger.warning('这是一条 warning 级别的日志')
# 你甚至可以在一行代码中更改日志的输出格式
logger.add("file_{time}.log", format="{time} {level} {message}", rotation="day")
# 再次记录日志,这次它们也会被写入到文件中
logger.info('这条日志也会被写入到文件中')
在这个示例中,可以看到 Loguru 的 API 更为直观,只需导入 logger 对象并调用相应的方法即可记录日志。而 logging 模块需要先配置基本的日志记录器,然后才能记录日志。
- 异常捕捉
使用loguru
模块:
from loguru import logger
def divide(a, b):
try:
result = a / b
logger.info(f'The result is {result}')
except ZeroDivisionError as e:
logger.exception('An error occurred')
divide(10, 0)
使用logging
模块:
import logging
# 配置 logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def divide(a, b):
try:
result = a / b
logging.info(f'The result is {result}')
except ZeroDivisionError as e:
logging.exception('An error occurred')
divide(10, 0)
两者的打印结果差异如下:
所以:loguru
不仅捕获了和logging
类似的异常调用栈,同时还是显示的告诉我们异常发生的位置
3. 日志旋转:
使用loguru
模块:
from loguru import logger
# 配置日志,按照日期时间进行轮换,每小时创建一个新的日志文件
logger.add("file_{time}.log", rotation="1 hour")
# 记录日志
logger.info("This is a log message")
在这个例子中,loguru 会在每小时开始时创建一个新的日志文件,例如 file_2024-05-04_23-11-09_072247.log 等
使用logging
模块:
import logging
from logging.handlers import TimedRotatingFileHandler
# 创建一个logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# 创建一个handler,用于写入日志文件,每5秒轮换一次(这里为了演示设置为5秒,实际中可能使用更长的周期如1天)
handler = TimedRotatingFileHandler('timed_rotation.log', when='S', interval=5, backupCount=5)
# 定义handler的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
# 给logger添加handler
logger.addHandler(handler)
# 记录一些日志
logger.info("This is an info message.")
logger.error("This is an error message.")
在这个例子中,TimedRotatingFileHandler 被配置为每5秒轮换一次日志文件(注意:在实际应用中,通常使用更长的周期,如 ‘D’ 表示每天轮换)。backupCount 参数指定了保留的备份文件的个数,超出这个个数的旧日志文件将被自动删除。请注意,由于文件系统的限制,过于频繁的轮换可能不是最佳实践
4. 性能:
性能测试方法参考:
from loguru import logger
import time
import logging
# Loguru 异步记录日志
logger.add("loguru_file.log", enqueue=True)
# Logging 模块同步记录日志
logging.basicConfig(filename="logging_file.log", level=logging.INFO)
# 使用 Loguru 记录大量日志消息并计时
start_time_loguru = time.time()
for i in range(100000):
logger.info("This is a Loguru message")
end_time_loguru = time.time()
# 使用 logging 模块记录大量日志消息并计时
start_time_logging = time.time()
for i in range(100000):
logging.info("This is a logging message")
end_time_logging = time.time()
print("Time taken by Loguru:", end_time_loguru - start_time_loguru)
print("Time taken by logging:", end_time_logging - start_time_logging)