暂停记录器的格式,然后返回到它

时间:2014-04-19 21:34:25

标签: python logging

我有一个日志配置,我在其中登录文件和控制台:

logging.basicConfig(filename=logfile, filemode='w',
                        level=numlevel,
                        format='%(asctime)s - %(levelname)s - %(name)s:%(funcName)s - %(message)s')
    # add console messages
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    consoleformatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    console.setFormatter(consoleformatter)
    logging.getLogger('').addHandler(console)

在我的脚本中的某个时刻,我需要通过打印摘要并要求确认来与用户进行交互。摘要目前由循环中的打印产生。我想暂停当前控制台日志的格式,这样我就可以打印出一大块文本,并在最后输出一个问题并等待用户输入。但我仍然希望将所有这些记录到文件中!

执行此操作的功能位于模块中,我尝试了以下操作:

logger = logging.getLogger(__name__)
def summaryfunc:
    logger.info('normal logging business')
    clearformatter = logging.Formatter('%(message)s')
    logger.setFormatter(clearformatter)
    logger.info('\n##########################################')
    logger.info('Summary starts here')

产生错误:AttributeError: 'Logger' object has no attribute 'setFormatter'

我知道记录器是记录器,而不是处理程序,但我不确定如何让事情发挥作用......

编辑

根据答案,我的问题变成:如何在与用户交互时暂停登录到控制台,同时仍然能够登录到文件。 IE:只挂起streamHandler。由于这是在一个模块中发生的,处理程序的细节在其他地方定义,所以这就是我如何做到的:

logger.debug('Normal logging to file and console')
root_logger = logging.getLogger()
stream_handler = root_logger.handlers[1]
root_logger.removeHandler(stream_handler)
print('User interaction')
logger.info('Logging to file only')
root_logger.addHandler(stream_handler)
logger.info('Back to logging to both file and console')

这依赖于streamHandler始终是handlers返回的列表中的第二个,但我相信这是因为它是按照我将处理程序添加到根记录器的顺序...

2 个答案:

答案 0 :(得分:4)

我同意Vinay您应该使用print进行正常的程序输出,并且仅使用logging进行日志记录。但是,如果您仍想在中间切换格式,请切换回来,以下是如何操作:

import logging

def summarize():
    console_handler.setFormatter(logging.Formatter('%(message)s'))
    logger.info('Here is my report')
    console_handler.setFormatter(console_formatter)

numlevel = logging.DEBUG
logfile = 's2.log'
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

console_handler = logging.StreamHandler()
console_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
console_handler.setFormatter(console_formatter)
logger.addHandler(console_handler)

file_handler = logging.FileHandler(filename=logfile, mode='w')
file_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s:%(funcName)s - %(message)s')
file_handler.setFormatter(file_formatter)
logger.addHandler(file_handler)

logger.info('Before summary')
summarize()
logger.info('After summary')

讨论

  • 该脚本创建一个记录器对象并为其分配两个处理程序:一个用于控制台,一个用于文件。
  • 在函数summarize()中,我为控制台处理程序切换了一个新格式化程序,执行了一些日志记录,然后切换回来。
  • 再次提醒您,不要使用logging来显示正常的节目输出。

更新

如果要禁止控制台日志记录,请将其重新打开。这是一个建议:

def interact():
    # Remove the console handler
    for handler in  logger.handlers:
        if not isinstance(handler, logging.FileHandler):
            saved_handler = handler
            logger.removeHandler(handler)
            break

    # Interact
    logger.info('to file only')

    # Add the console handler back
    logger.addHandler(saved_handler)

请注意,我没有针对logging.StreamHandler测试处理程序,因为logging.FileHandler来自logging.StreamHandler。因此,我删除了那些不是FileHandler的处理程序。在删除之前,我保存了该处理程序以便以后恢复。

更新2:.handlers = []

在主脚本中,如果您有:

logger = logging.getLogger(__name__) # __name__ == '__main__'

然后在一个模块中,你做:

logger = logging.getLogger(__name__) # __name__ == module's name, not '__main__'

问题是,在脚本__name__ == '__main__'和模块中,__name__ == <the module's name>而不是'__main__'。为了实现一致性,您需要在两个地方组成一些名称并使用它们:

logger = logging.getLogger('MyScript')

答案 1 :(得分:3)

不应使用记录来提供程序的实际输出 - 如果完全关闭记录,程序应该以相同的方式运行。所以我建议你最好先做你以前做过的事情,比如在循环中打印。