Python 中如何自定义日志输出

当你使用任何编程语言时,最终目标始终是拥有一个按照提供的指令正常运行的程序。然而,第一次就达到期望的结果是很少见的,你可能需要分析你的运行以识别错误。在现代软件中,理解运行时行为已成为标准做法,这就是日志记录派上用场的地方。

在本文中,我们将专注于Pythonlogging库的基础知识,该库提供了所有必要的功能。它易于使用,在实施时提供了许多好处。虽然你可能目前正在使用print函数来调试和验证结果,但在生产环境中,按照日志记录的标准进行工作是很重要的。Python的日志记录库可以让你做到这一点。

日志记录的级别

不同的日志级别是日志记录的一个重要方面,了解它们的工作原理至关重要。简而言之,你可以选择所需的级别来控制输出中出现的日志消息。logging库为每个级别提供了单独的模块,它们的编号从10到50不等。所有级别都是不言而喻的,易于理解。但是,我们将详细介绍每个级别。

  • Debug:此日志级别主要用于调试目的,在生产环境中没有用处。它的日志级别为10。
  • Info:此日志级别提供了从程序行为中预期的信息。它的日志级别为20。
  • Warning:此日志级别通知用户有意外事件发生,但不足以使程序停止。它的日志级别为30。
  • Error:此日志级别用于报告运行时的意外故障。它会被提高以避免将来发生类似的故障。它的日志级别为40。
  • Critical:此日志级别表示严重错误,可能导致应用程序停止运行。它的日志级别为50。

程序记录高于指定级别的消息,类似于级联。下面是它的工作原理示例。在basicConfig中,我们应该提供所需的日志记录级别。结果,只有高于此级别的消息才会出现在输出中(包括当前级别)。因此,当我们想要查看WARNING消息时,程序不会记录DEBUGINFO级别的消息。

import logging  
  
def test_logging():  
    logging.basicConfig(level=logging.WARNING)  
  
    logging.debug("DEBUG")  
    logging.info("INFO")  
    logging.warning("WARNING")  
    logging.error("ERROR")  
    logging.critical("CRITICAL")  
  
test_logging()  
  
# WARNING:root:WARNING  
# ERROR:root:ERROR  
# CRITICAL:root:CRITICAL

在开始时,我们将级别设置为WARNING。因此,输出中只有三条消息 — 分别是WARNINGERRORCRITICAL级别的消息。现在,让我们将级别修改为DEBUG以观察输出。

import logging  
  
def test_logging():  
    logging.basicConfig(level=logging.DEBUG)  
  
    logging.debug("DEBUG")  
    logging.info("INFO")  
    logging.warning("WARNING")  
    logging.error("ERROR")  
    logging.critical("CRITICAL")  
  
test_logging()  
  
# DEBUG:root:DEBUG  
# INFO:root:INFO  
# WARNING:root:WARNING  
# ERROR:root:ERROR  
# CRITICAL:root:CRITICAL

很好,现在你有一个高层次的理解,我们可以转向日志记录方法的更实际部分。

更改基本配置

在上一个示例中,我们只使用了标准配置,并收到了一个格式为INFO:root:的输出,这并不是很信息丰富。然而,可以修改许多可选配置来获得所需的消息格式。

import logging  
  
def test_logging():  
    logging.basicConfig(  
        level=logging.ERROR,  
        format="%(asctime)s | %(levelname)s | %(message)s",  
        datefmt="%Y-%m-%d %H:%M:%S",  
        filename="basic.log")  
  
    logging.debug("DEBUG")  
    logging.info("INFO")  
    logging.warning("WARNING")  
    logging.error("ERROR")  
    logging.critical("CRITICAL")  
  
test_logging()  
  
# 2023-11-18 14:52:30 | ERROR | ERROR  
# 2023-11-18 14:52:30 | CRITICAL | CRITICAL

日志的新格式更加信息丰富,因为它提供了日志的确切时间。这种格式不仅限于日期更改,并且可以使用filename参数为basicConfig定制格式以将日志存储在文件中。存储日志对于以后的分析在生产工作流程中非常有用。

在生产就绪的应用程序中,通常使用特定的存储系统,它允许弹性分析方法。此外,日志消息中可以使用变量,但是要谨慎使用,不要提供任何敏感信息,以避免日志可能在未来造成潜在泄漏。

import logging  
  
def test_logging():  
    logging.basicConfig(  
        level=logging.INFO,  
        format="%(message)s")  
  
    for i in ["Dog", "Cat"]:  
        logging.info("%s is your animal!", i)  
  
test_logging()  
  
# Dog is your animal!  
# Cat is your animal!

自定义日志格式

在前面的示例中,我们直接从库中调用了记录器。然而,也可以创建自定义对象并根据需要进行自定义。在某些情况下,这种技术可能很有用,因此理解如何实现它非常重要。

例如,在下面的示例中,我们创建了

一个名为Test的记录器,并将其日志级别设置为DEBUG。然而,仅仅设置日志级别不足以输出消息。我们必须使用处理程序来实现。Handle本质上是一个将日志发送到特定目的地的对象。在这种情况下,我们将消息打印到控制台,但在生产环境中,你通常会将所有消息发送到一个特殊的存储或数据库。

import logging  
  
logger = logging.getLogger('TEST')  
logger.setLevel(logging.DEBUG)  
  
handle = logging.StreamHandler()  
handle.setLevel(logging.DEBUG)  
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')  
handle.setFormatter(formatter)  
logger.addHandler(handle)  
  
logger.debug("DEBUG")  
logger.info("INFO")  
  
# 2023-11-18 15:47:41,035 - TEST - DEBUG - DEBUG  
# 2023-11-18 15:47:41,035 - TEST - INFO - INFO

如你所见,我们添加了特定的格式,并在处理程序中使用了它。这个简单的示例表明,你可以创建多个记录器和处理程序实例,并根据需要将相关日志发送到每个目的地。此外,你还可以使用colorlog库使用不同的颜色进一步修改你的格式。下面是用于记录级别的颜色实现示例。

import logging  
import colorlog  
  
logger = logging.getLogger('TEST')  
logger.setLevel(logging.DEBUG)  
  
handle = logging.StreamHandler()  
handle.setLevel(logging.DEBUG)  
fmt = colorlog.ColoredFormatter(  
    "%(name)s: %(white)s%(asctime)s%(reset)s %(log_color)s%(levelname)s%(reset)s %(process)d >>> %(log_color)s%(message)s%(reset)s"  
)  
handle.setFormatter(fmt)  
logger.addHandler(handle)  
  
logger.error("ERROR")  
logger.info("INFO")

带有彩色格式的输出

这里是一个类似的方法的示例,用于创建数据库、将数据发送到数据库并在整个过程中记录一切。虽然下面的代码只是一个虚拟代码,但它仍然可以给你一个如何在实际情况下处理这样的任务的想法。


import logging  
from time import sleep  
  
def db_connection(user: str, password: str, logger: logging.Logger) -> str:  
    """  
    虚拟数据库连接  
    """  
    conn_str = user + password  
    logger.info("连接已启动")  
    sleep(1)  
    try:  
        conn = "连接成功"  
        logger.info("连接成功")  
    except:  
        logger.error("数据库连接期间出错")  
    return conn  
  
def send_data(data: tuple, conn: str, logger: logging.Logger) -> None:  
    logger.info("数据已发送")  
  
def main():  
  
    # 准备记录器   
    logger = logging.getLogger('TEST')  
    logger.setLevel(logging.DEBUG)  
    handle = logging.StreamHandler()  
    handle.setLevel(logging.DEBUG)  
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')  
    handle.setFormatter(formatter)  
    logger.addHandler(handle)  
  
    logger.info("程序已启动")  
    sleep(1)  
      
    conn = db_connection(user='test', password='test', logger=logger)  
  
    data = ("test", 123)  
    send_data(data=data, conn=conn, logger=logger)  
main()

程序输出

结论

强烈建议将代码中的print用法替换为logging。日志记录提供了更多的灵活性,对于调试工作流程更加有用。此外,了解日志记录在生产中的工作原理以及如何阅读现有日志是至关重要的。建议尝试各种示例以彻底学习这个概念。花一点时间学习如何使用日志记录库,将对你未来的工作大有裨益。

  • 22
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python ,可以使用 logging 模块将终端输出写入日志文件。具体实现可以参考以下示例代码: ```python import logging import sys class StreamToLogger: """ 把 stdout 和 stderr 输出日志文件 """ def __init__(self, logger, log_level=logging.INFO): self.logger = logger self.log_level = log_level self.linebuf = '' def write(self, buf): for line in buf.rstrip().splitlines(): self.logger.log(self.log_level, line.rstrip()) logging.basicConfig(filename='example.log', level=logging.DEBUG) stdout_logger = logging.getLogger('STDOUT') stdout_logger.setLevel(logging.INFO) stdout_handler = logging.StreamHandler(sys.stdout) stdout_logger.addHandler(stdout_handler) stdout_logger.info('This is a test message') stderr_logger = logging.getLogger('STDERR') stderr_logger.setLevel(logging.ERROR) stderr_handler = logging.StreamHandler(sys.stderr) stderr_logger.addHandler(stderr_handler) stderr_logger.error('This is an error message') ``` 在上面的代码,我们使用 `logging.getLogger` 方法创建了两个日志记录器,分别用于记录 `stdout` 和 `stderr` 的输出。然后,我们使用 `StreamHandler` 将输出重定向到日志文件,并设置了不同的日志级别。最后,我们使用 `logger.log` 方法将输出内容写入到日志文件。 需要注意的是,上述代码的 `StreamToLogger` 类是一个自定义输出流类,用于把 `stdout` 和 `stderr` 的输出写入到日志文件。在实际应用,可以根据需要修改该类的实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值