欢迎访问宙启技术站
智能推送

如何解决python中logging重复记录日志的问题

发布时间:2023-05-17 00:17:31

在 Python 中,使用 logging 模块进行记录日志是很常用的技术。然而,有时候会发现日志记录重复的问题,即同一条日志记录被重复输出多次。这个问题看起来是个错误,但实际上是因为 logging 模块设计有些复杂,需要我们仔细处理才能避免。接下来,我们将探讨一些可能导致 logging 记录重复的原因并提供相应的解决方案。

1. 多次添加日志句柄

logging 模块允许你同时将日志输出到不同的地方,比如终端、文件、远程服务器等。你可以通过调用 Logger.addHandler() 方法添加不同的日志句柄。例如:

import logging

logger = logging.getLogger(__name__)
handler1 = logging.StreamHandler()
handler2 = logging.FileHandler('example.log')

logger.addHandler(handler1)
logger.addHandler(handler2)

如果你不注意,可能会重复添加同一个句柄,导致日志重复输出。此外,有些 Python 软件包会默认添加多个日志句柄,如果你不检查就会出现问题。

解决方案:

在添加日志句柄之前,可以检查一下该句柄是否已经被添加过。例如:

if handler1 not in logger.handlers:
    logger.addHandler(handler1)

2. 不同 Logger 实例重复记录

在 Python 数据科学和工程界,常常涉及到多个 Python 模块间的交互,而这些模块有可能都记录了自己的日志。如果每个模块都定义了一个 Logger 实例,那么就可能会出现日志重复记录的问题。

解决方案:

在使用 Logger 实例时, 使用顶层的 Logger 实例,这样就可以保证只有一份日志记录。例如:

from logging import getLogger

logger = getLogger(__name__.split('.')[0])

这样,每个模块都获取到了同一个 Logger 实例,就可以避免不同 Logger 实例记录相同的日志。

3. 日志等级设置不当

logging 模块有五种日志等级:

* CRITICAL (50)

* ERROR (40)

* WARNING (30)

* INFO (20)

* DEBUG (10)

你可以通过调整 logging 模块的 logging.basicConfig 函数的level参数 ,设置日志最低等级。

如果你的日志等级设置过低,就会导致记录了大量不必要的信息,也可能会有重复记录。例如:

import logging

logging.basicConfig(level=logging.DEBUG)

def foo():
    logging.info('This is an info message')
    logging.debug('This is a debug message')

foo()

输出结果:

INFO:root:This is an info message
DEBUG:root:This is a debug message

可以看出,即使我们只想记录一条 info 信息,也记录了一条 debug 信息。

解决方案:

在执行 logging.basicConfig 函数时,设置合适的日志等级。如果你只想记录重要信息,则可以设置为 WARNING 或 ERROR 等级。

logging.basicConfig(level=logging.WARNING)

4. 日志输出格式问题

如果你的日志格式设置不当,也可能会出现日志重复记录的问题。特别是当使用 filehandler 时,需要注意。

解决方案:

在使用 filehandler 时,可以设置文件名,并调整日志格式。如果你想保证日志不被重复输出,可以使用下面的设置:

import logging

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(levelname)-8s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='example.log',
                    filemode='w')

5. 模块循环依赖问题

有时候,我们会遇到模块之间循环依赖的问题。这会导致两个模块相互引用,引用日志时也难以避免。

解决方案:

避免循环依赖,把依赖减少到最小。如果循环依赖是不可避免的,可以把日志记录封装到函数、类等封装体中,避免模块级别的日志记录冲突。

结论:

万能解决方法并没有。没有一个通用的解决方案,而是需要根据实际情况逐步排查问题,并找到合适的解决方案。

最后提醒,我们在实际开发过程中,使用 logging 记录日志不仅可以在出错时排除故障,也可以在运营期间监控部署情况。另外,同时记得在排除问题时,留下有启发性的日志记录,以便日后做事后处理。