假设我的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直到脚本运行完毕并在打印前按级别对日志消息进行排序?
答案 0 :(得分: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
答案 1 :(得分: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]])
答案 2 :(得分: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')