1

私の 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...')

スクリプトの実行が終了するまで stdout への出力を待機させ、出力する前にログ メッセージをレベル別にソートする方法はありますか?

4

3 に答える 3

3

見た目からすると、渡されるオブジェクトにはメソッド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]])
于 2012-10-16T17:29:46.637 に答える
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
于 2012-10-16T17:18:44.853 に答える
1

これは、事後ソートを含まない方法です (したがって、もう少し効率的です)。この質問の単一レベル フィルターと、エラーの種類ごとに個別のハンドラーを使用します。このように、ログは確実にタイプ別に編成され、文字列をチェックしてログ タイプを特定するだけで問題はありません。

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')
于 2012-10-16T19:21:19.710 に答える