2012-10-16 26 views
1

前比方说,我有一个记录设置像这样在我的Python脚本: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...') 

有没有一种方法,我可以把它等待打印到标准输出,直到脚本在打印之前按级别完成运行并对日志消息进行排序?

回答

2

从外观上来看,传递给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]]) 
+0

+1这比我的方法更好(我在写回答时想到了这样的事情,但是mgilson打败了我)。它更有效率,更简单,并且分类更加清晰。 –

+0

我仍然不喜欢的一件事是日志按字符串排序。也许我们可以使用[过滤器对象](http://docs.python.org/library/logging.html#filter-objects)或其他... –

+0

哇,这是如此优雅!谢谢。这条线[: - 1]是什么意思? – Greg

2

这很可笑,但您可以登录到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 
+0

我的其他答案和mgilson的答案都比这更好,但我会留在这里,因为这是一个有效的解决方案。 –

1

这是一种不涉及事后排序(并且效率更高)的方法。它使用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')