2012-10-16 31 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')