【问题标题】:Python - Sort Log Messages By Level before PrintingPython - 在打印前按级别对日志消息进行排序
【发布时间】:2012-10-06 20:53:51
【问题描述】:

假设我的 Python 脚本中有这样的日志记录设置:

import logging

logging.basicConfig(level=logging.DEBUG, stream=sys.stdout,
                    format='%(asctime)s %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S')
logging.info('info')
logging.error('error...')
logging.debug('debug...')

有没有办法让它等待打印到标准输出,直到脚本完成运行并在打印前按级别对日志消息进行排序?

【问题讨论】:

    标签: python logging


    【解决方案1】:

    看起来,传递给stream的对象只需要一个write方法。这意味着您可以创建一个类似列表的对象,该对象在调用 write 时附加数据——然后您可以在打印之前对类似列表的对象进行简单的排序。

    import logging
    
    class LogList(list):
       def write(self,data):
           self.append(data)
    
    LL = LogList()
    logging.basicConfig(stream = LL,level=logging.DEBUG)
    logging.debug('This message should go to the log file')
    logging.info('So should this')
    logging.error('Wow, this is bad')
    logging.warning('And this, too')
    logging.debug('foobar')
    logging.warning('baz')
    
    for line in sorted(LL):
       print line[:-1]
    

    当然,您可能需要使您的排序键多一点才能选择不同的级别。比如:

    levels = {'DEBUG':0,'INFO':1,'WARNING':2,'ERROR':3}
    LL.sort(key = lambda x: levels[x.split(':')[0]])
    

    【讨论】:

    • +1 这比我的方法好(我在写答案时想到了类似的方法,但 mgilson 打败了我)。它更高效,更少hack-y,并且排序更流畅。
    • 我仍然不喜欢的一件事是日志是按字符串排序的。也许我们可以使用filter object 或其他什么...
    • 哇,这太优雅了!谢谢。行 [:-1] 是干什么用的?
    • 我做了“打印行”,所以打印不会添加自己的换行符。
    • 我实现了过滤器对象解决方案并将其发布为另一个答案。
    【解决方案2】:

    这很 hack-y,但您可以登录到 StringIO 对象,拆分行,对它们进行排序,然后将结果写入文件。

    import logging
    import cStringIO as StringIO
    
    logStrObj = StringIO.StringIO()
    
    logging.basicConfig(level=logging.DEBUG, stream=logStrObj,
                        format='%(asctime)s %(levelname)s %(message)s',
                        datefmt='%a, %d %b %Y %H:%M:%S')
    
    logging.info('info')
    logging.error('error...')
    logging.info('info 2')
    logging.debug('debug...')
    
    # sort the contents of logStrObj
    logList = logStrObj.getvalue().split('\n')
    infoLogList = []
    debugLogList = []
    warningLogList = []
    errorLogList = []
    criticalLogList = []
    for log in logList:
        if 'INFO' in log:
            infoLogList.append(log)
        elif 'DEBUG' in log:
            debugLogList.append(log)
        elif 'WARNING' in log:
            warningLogList.append(log)
        elif 'ERROR' in log:
            errorLogList.append(log)
        elif 'CRITICAL' in log:
            criticalLogList.append(log)
    logList = infoLogList + debugLogList + warningLogList + errorLogList + criticalLogList
    
    # write to a file (or print or whatever you want)
    for line in logList:
        print line
    

    【讨论】:

    • 我的其他答案和 mgilson 的答案都比这更好,但我会把它留在这里,因为它是一个有效的解决方案。
    【解决方案3】:

    这是一种不涉及事后排序的方法(因此效率更高)。它使用来自this question 的单级过滤器,并为每种类型的错误使用单独的处理程序。这样一来,日志肯定是按类型组织的,不会出现只检查字符串来确定日志类型的问题。

    import logging
    import cStringIO as StringIO
    
    class SingleLevelFilter(logging.Filter):
        '''This single level logging filter is from https://stackoverflow.com/a/1383365/1460235'''
        def __init__(self, passlevel, reject):
            self.passlevel = passlevel
            self.reject = reject
    
        def filter(self, record):
            if self.reject:
                return (record.levelno != self.passlevel)
            else:
                return (record.levelno == self.passlevel)
    
    # Use this formatter and logLevel in place of setting the global ones
    formatter = logging.Formatter(fmt='%(asctime)s %(levelname)s %(message)s',
                        datefmt='%a, %d %b %Y %H:%M:%S')
    globalLogLevel = logging.INFO
    
    # build handlers/ StringIO logs for each type
    rootLogger = logging.getLogger()
    rootLogger.setLevel(globalLogLevel)
    logStrObjList = []
    handlers = []
    i = 0
    for logLevel in [logging.INFO, logging.DEBUG, logging.WARNING, logging.ERROR, logging.CRITICAL]:
        logStrObjList.append(StringIO.StringIO())
        handlers.append(logging.StreamHandler(logStrObjList[i]))
        handlers[i].addFilter(SingleLevelFilter(logLevel, False))
        handlers[i].setFormatter(formatter)
        handlers[i].setLevel(globalLogLevel)
        rootLogger.addHandler(handlers[i])
        i += 1
    
    logging.critical('bad news bears')
    logging.info('info')
    logging.error('error...')
    logging.info('info 2')
    logging.debug('debug...')
    logging.error('another errooo')
    

    【讨论】:

      猜你喜欢
      • 2016-02-20
      • 1970-01-01
      • 2010-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-08
      相关资源
      最近更新 更多