将记录器消息存储在字符串中

时间:2015-08-13 22:45:29

标签: python logging

我想将所有中间日志消息(警告,信息,错误)存储到python中的字符串,最后在程序结束时,将所有内容显示为控制台的报告。

我尝试按照中列出的步骤进行操作 http://opensourcehacker.com/2011/02/23/temporarily-capturing-python-logging-output-to-a-string-buffer/ 但没有成功。

有人能告诉我一个简短,干净的方法吗?

这就是我现在所尝试的:

    log  = logging.getLogger('basic_logger')
    log.setLevel(logging.DEBUG)
    report=""

            memory_handler=logging.handlers.MemoryHandler(1024*20,logging.ERROR,report)
memory_handler.setLevel(logging.DEBUG)
log.addHandler(memory_handler)

log.info("hello world")
memory_handler.flush()
print "report:",report

5 个答案:

答案 0 :(得分:12)

它可以像记录到StringIO对象一样简单:

import logging
try:
    from cStringIO import StringIO      # Python 2
except ImportError:
    from io import StringIO

log_stream = StringIO()    
logging.basicConfig(stream=log_stream, level=logging.INFO)

logging.info('hello world')
logging.warning('be careful!')
logging.debug("you won't see this")
logging.error('you will see this')
logging.critical('critical is logged too!')

print(log_stream.getvalue())

<强>输出

INFO:root:hello world
WARNING:root:be careful!
ERROR:root:you will see this
CRITICAL:root:critical is logged too!

如果您只想记录WARN,INFO和ERROR级别的消息,可以使用过滤器。下面LevelFilter检查每个日志记录的级别号,只允许那些所需级别的记录:

import logging
try:
    from cStringIO import StringIO      # Python 2
except ImportError:
    from io import StringIO

class LevelFilter(logging.Filter):
    def __init__(self, levels):
        self.levels = levels

    def filter(self, record):
        return record.levelno in self.levels

log_stream = StringIO()    
logging.basicConfig(stream=log_stream, level=logging.NOTSET)
logging.getLogger().addFilter(LevelFilter((logging.INFO, logging.WARNING, logging.ERROR)))

logging.info('hello world')
logging.warning('be careful!')
logging.debug("you won't see this")
logging.error('you will see this')
logging.critical('critical is no longer logged!')

print(log_stream.getvalue())

<强>输出

INFO:root:hello world
WARNING:root:be careful!
ERROR:root:you will see this

答案 1 :(得分:1)

您也可以编写自己的流类。正如https://docs.python.org/2/library/logging.handlers.html所述,只有writeflush用于流媒体。

示例:

import logging

class LogStream(object):
    def __init__(self):
        self.logs = ''

    def write(self, str):
        self.logs += str

    def flush(self):
        pass

    def __str__(self):
        return self.logs

log_stream = LogStream()
logging.basicConfig(stream=log_stream, level=logging.DEBUG)

log = logging.getLogger('test')
log.debug('debugging something')
log.info('informing user')

print(log_stream)

<强>输出:

DEBUG:test:debugging something
INFO:test:informing user

答案 2 :(得分:1)

请注意,涉及basicConfig的解决方案设置了所有其他记录器都继承的 root 记录器的属性,这是不必要的,因为库也将记录到该属性。我的用例是一个调用数据处理模块的网站,我只想专门捕获该模块的日志。这还具有允许登录到文件的现有处理程序和终端保留的优点:

import io, logging
from django.http import HttpResponse

log_stream = io.StringIO()
log_handler = logging.StreamHandler(log_stream)
logging.getLogger('algorithm.user_output').addHandler(log_handler)

algorithm()
return HttpResponse(f'<pre>{log_stream.getvalue()}</pre>')

algorithm.py中:

logger = logging.getLogger(__name__ + '.user_output')  # 'algorithm.user_output'

答案 3 :(得分:0)

具有多个记录器并使用 StringIO 作为存储的快速配方

注意:

这是@mhawke Answer 的定制版本---> HERE 我需要有多个日志让每个日志都做它的事情,这是一个简单的脚本。

from io import StringIO
from datetime import date
# Formatter
LOG_FORMAT = '| %(asctime)s | %(name)s-%(levelname)s:  %(message)s '
FORMATTER = logging.Formatter(LOG_FORMAT)

# ------- MAIN LOGGER
main_handler = logging.StreamHandler()
main_handler.setLevel(logging.WARNING)
main_handler.setFormatter(FORMATTER)

# ------- FILE LOGGER
file_handler = logging.FileHandler(f'log_{date.strftime(date.today(), "%Y-%m-%d")}.log')
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(FORMATTER)

# ------- SECONDARY STREAMER (HOLDS ALL THE LOGS FOR RETRIEVE LATER) LOGGER
streamer = StringIO()
stream_handler = logging.StreamHandler(stream=streamer)
stream_handler.setFormatter(FORMATTER)

# Root Logger
logging.basicConfig(level=10, handlers=[main_handler, file_handler, stream_handler]) # Add handlers to Logger
_logger = logging.getLogger(__name__)

_logger.log(10, "DEBUG MESSAGE")
_logger.log(20, "INFO MESSAGE")
_logger.log(30, "WARNING MESSAGE")
_logger.log(40, "ERROR!")
_logger.log(50, "CRITICAL")
print('==='*15)
print('\nGetting All logs from StringIO')
print(streamer.getvalue())

从 StringIO 中清除日志

此外,我需要再次从 0 开始清除数据。最简单且性能更快的方法是创建一个新的 StringIO 实例并将其附加到 StreamHandler 实例。

new_streamer = StringIO()  # Creating the new instance
stream_handler.setStream(new_streamer)  # here we assign it to the logger

_logger.info("New Message")
_logger.info("New Message")
_logger.info("New Message")
print(new_streamer.getvalue()) # New data

另一种方法是“清除”流,但根据 @Chris Morgan 的其他 **StackOverflow Answer 性能较低。

# Python 3
streamer.truncate(0)
streamer.seek(0)

_logger.info("New Message")
_logger.info("New Message")
_logger.info("New Message")
print(streamer.getvalue())

# Python 2
streamer.truncate(0)

_logger.info("New Message")
_logger.info("New Message")
_logger.info("New Message")
print(streamer.getvalue())

文档

答案 4 :(得分:-1)

也许这个示例代码就足够了 通常,您应该发布您的代码,以便我们可以看到正在发生的事情。
在阅读任何给定的教程时,您还应该查看日志记录模块的实际Python文档 https://docs.python.org/2/library/logging.html

标准Python日志记录模块可以登录到文件。完成日志记录后,可以将该文件的内容打印到shell输出中。

# Do some logging to a file
fname = 'mylog.log'
logging.basicConfig(filename=fname, level=logging.INFO)
logging.info('Started')
logging.info('Finished')

# Print the output
with open(fname, 'r') as f:
    print f.read() # You could also store f.read() to a string