简体   繁体   English

Python-在打印前按级别对日志消息进行排序

[英]Python - Sort Log Messages By Level before Printing

Let's say I have a logging setup like this in my Python script: 假设我的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...')

Is there a way I can have it wait to print to stdout until the script is finished running and sort the log messages by level before printing? 有没有一种方法可以让我等待打印到stdout,直到脚本运行完毕并在打印之前按级别对日志消息进行排序?

It's pretty hack-y, but you could log to a StringIO object, split the lines, sort them, and then write the result to a file. 这很StringIO ,但是您可以登录到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

From the looks of it, the object passed to stream only needs to have a write method. 从外观上看,传递给stream的对象只需要具有write方法。 This means you can create a list-like object which appends data when write is called -- You can then sort the list-like object trivially before printing. 这意味着您可以创建一个类似列表的对象,该对象在调用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]

Of course, you might need to make your sort key a little more to pick up different levels. 当然,您可能需要再增加一些排序键才能选择不同的级别。 Something like: 就像是:

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

Here is a method that doesn't involve sorting after the fact (and so is a bit more efficient). 这是一种不涉及事实排序的方法(因此效率更高)。 It uses the single level filter from this question and separate handlers for each type of error. 它使用此问题的单级过滤器,并针对每种类型的错误使用单独的处理程序。 This way, the logs are definitely organized by type, and there won't be any problems from just checking strings to determine the log type. 这样,日志肯定是按类型组织的,并且仅通过检查字符串来确定日志类型就不会有任何问题。

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')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM