如何使用logging模块避免重复输出?

3

我正在使用logging模块将脚本中原本用于打印的语句输出到控制台和日志文件。然而,每次运行脚本时,输出似乎会附加到之前已经在控制台和日志中打印的内容后面,而不是覆盖之前的内容。例如,第一次运行脚本时,我在控制台和日志文件中得到以下输出:

This print statement is going to both the console and the log
The year is: 2015

第二次运行脚本时,控制台会显示以下内容:
This print statement is going to both the console and the log
This print statement is going to both the console and the log
The year is: 2015
The year is: 2015

第三次:
This print statement is going to both the console and the log
This print statement is going to both the console and the log
This print statement is going to both the console and the log
The year is: 2015
The year is: 2015
The year is: 2015

等等..日志文件不断追加,以至于最后出现:

This print statement is going to both the console and the log
The year is: 2015
This print statement is going to both the console and the log
This print statement is going to both the console and the log
The year is: 2015
The year is: 2015
This print statement is going to both the console and the log
This print statement is going to both the console and the log
This print statement is going to both the console and the log
The year is: 2015
The year is: 2015
The year is: 2015

我希望在每次运行脚本时,日志文件和控制台只会给我以下内容:

This print statement is going to both the console and the log
The year is: 2015

注意:目前我能做到的唯一办法是在运行脚本之间关闭Python,但这不是一个实用的解决方案。
我尝试过使用flush()并尝试做如下操作:
logger = logging.basicConfig(filemode='w', level=logging.DEBUG)

但是我一直无法让它与我的代码配合使用。有人可以帮忙吗?这是我的代码:

import inspect
import logging
import datetime

def getDate():
    now = datetime.datetime.now()
    m = now.month
    d = now.day
    y = str(now.year)
    if m < 10:
        m = "0"+str(m)
    else:
        m = str(m)
    if d < 10:
        d = "0"+str(d)
    else:
        d = str(d)
    y = y[2:]
    formatted_date = m+d+y
    return formatted_date

def function_logger(file_level, console_level = None):
    function_name = inspect.stack()[1][3]
    logger = logging.getLogger(function_name)
    logger.setLevel(logging.DEBUG) #By default, logs all messages

    if console_level != None:
        ch = logging.StreamHandler() #StreamHandler logs to console
        ch.setLevel(console_level)
        ch_format = logging.Formatter('%(message)s')
        ch.setFormatter(ch_format)
        logger.addHandler(ch)

    log_name = 'Test_log' + getDate() + '.log'
    fh = logging.FileHandler(log_name.format(function_name))
    fh.setLevel(file_level)
    fh_format = logging.Formatter('%(message)s')
    fh.setFormatter(fh_format)
    logger.addHandler(fh)
    return logger

def f1():
    global logger
    year = '2015'
    logger.info("The year is: %s" % (year))

def main():

    global logger
    logger = function_logger(logging.INFO, logging.INFO)
    logger.info('This print statement is going to both the console and the log')
    f1()
    logging.shutdown()

if __name__ == '__main__':
    main()

1
您看到这个信息是因为每个处理程序只会发出一条记录,如果您多次运行脚本,则每次调用addHandler()都会注册一个新的处理程序。要么跟踪您的日志处理程序并在try..finally中将它们删除,要么在添加处理程序之前检查是否已经有一个已注册到您要添加的类型。 - Lukas Graf
每运行一次,打印 logger.handlers 以查看正在发生的情况。 - Lukas Graf
谢谢。将我的两个addHandlers都放在if not logger.handlers:下解决了重复条目的问题。然而,仅涉及日志文件的第二个问题是日志仍然被追加而不是覆盖。我该如何解决这个剩余的日志问题? - Chris Nielsen
1
如果您查看FileHandler的构造函数,它的mode默认为'a'(追加)。因此,请使用FileHandler(log_name.format(function_name), mode='w')来覆盖现有文件而不是追加(与open()的语义相同)。 - Lukas Graf
2个回答

3

感谢Lucas Graf,以下是我修复代码以实现我想要的功能的方法:

def function_logger(file_level, console_level = None):
    function_name = inspect.stack()[1][3]
    logger = logging.getLogger(function_name)
    logger.setLevel(logging.DEBUG) #By default, logs all messages
    log_name = 'Test_log_' + getDate() + '.log'

    if not logger.handlers:
        if console_level != None:
            ch = logging.StreamHandler() #StreamHandler logs to console
            ch.setLevel(console_level)
            ch_format = logging.Formatter('%(message)s')
            ch.setFormatter(ch_format)
            logger.addHandler(ch)

        fh = logging.FileHandler(log_name.format(function_name), mode='w')
        fh.setLevel(file_level)
        fh_format = logging.Formatter('%(message)s')
        fh.setFormatter(fh_format)
        logger.addHandler(fh)

    return logger

这个修复需要注意三点:
1.我把两个 addHandlers 都移到了测试条件下面:
if not logger.handlers:

2: 我在文件处理程序中添加了mode='w':

fh = logging.FileHandler(log_name.format(function_name), mode='w')

3: 我在main()函数的底部清除了处理程序:

logger.handlers = []

0

只需要这样做:

def LOG_insere(file, format, text, level):
    infoLog = logging.FileHandler(file)
    infoLog.setFormatter(format)
    logger = logging.getLogger(file)
    logger.setLevel(level)
    
    if not logger.handlers:
        logger.addHandler(infoLog)
        if (level == logging.INFO):
            logger.info(text)
        if (level == logging.ERROR):
            logger.error(text)
        if (level == logging.WARNING):
            logger.warning(text)
    
    infoLog.close()
    logger.removeHandler(infoLog)
    
    return

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接