如何在Python日志记录中格式化异常堆栈跟踪?

时间:2015-01-27 21:16:39

标签: python logging traceback

我在Python中创建的日志旨在临时存储为文件,然后将文件处理到日志数据库中。它们采用管道描述的格式来指示如何处理日志,但logging.exception()通过添加太多字段和太多新行来破坏我的标准。

import logging
logging.basicConfig(filename='output.txt', 
                    format='%(asctime)s|%(levelname)s|%(message)s|', 
                    datefmt='%m/%d/%Y %I:%M:%S %p', 
                    level=logging.DEBUG)
logging.info('Sample message')

try:
    x = 1 / 0
except ZeroDivisionError as e:
    logging.exception('ZeroDivisionError: {0}'.format(e))

# output.txt
01/27/2015 02:09:01 PM|INFO|Sample message|
01/27/2015 02:09:01 PM|ERROR|ZeroDivisionError: integer division or modulo by zero|
Traceback (most recent call last):
  File "C:\Users\matr06586\Desktop\ETLstage\Python\blahblah.py", line 90, in <module>
    x = 1 / 0
ZeroDivisionError: integer division or modulo by zero

如何使用空格和换行符来最好地处理或格式化回溯?这些消息是logging.exception()中的部分和包裹,但是当我尝试时,绕过该函数感觉很奇怪记录异常的实例。如何记录我的回溯并将其格式化?是否应该忽略追溯?

感谢您的时间!

3 个答案:

答案 0 :(得分:7)

您可以定义自己的Formatter,其方法可以覆盖,以便按照您希望的方式格式化异常信息。这是一个简单(但有效)的例子:

import logging

class OneLineExceptionFormatter(logging.Formatter):
    def formatException(self, exc_info):
        result = super(OneLineExceptionFormatter, self).formatException(exc_info)
        return repr(result) # or format into one line however you want to

    def format(self, record):
        s = super(OneLineExceptionFormatter, self).format(record)
        if record.exc_text:
            s = s.replace('\n', '') + '|'
        return s

fh = logging.FileHandler('output.txt', 'w')
f = OneLineExceptionFormatter('%(asctime)s|%(levelname)s|%(message)s|', '%m/%d/%Y %I:%M:%S %p')
fh.setFormatter(f)
root = logging.getLogger()
root.setLevel(logging.DEBUG)
root.addHandler(fh)
logging.info('Sample message')

try:
    x = 1 / 0
except ZeroDivisionError as e:
    logging.exception('ZeroDivisionError: {0}'.format(e))

这只产生两行:

01/28/2015 07:28:27 AM|INFO|Sample message|
01/28/2015 07:28:27 AM|ERROR|ZeroDivisionError: integer division or modulo by zero|'Traceback (most recent call last):\n  File "logtest2.py", line 23, in <module>\n    x = 1 / 0\nZeroDivisionError: integer division or modulo by zero'|

当然,您可以在此示例的基础上进行精确的操作,例如:通过traceback模块。

答案 1 :(得分:0)

您应该定义自己的函数,使用traceback.extract_tb将回溯格式化为您想要的语法,然后将其返回或写入文件:

traceback.extract_tb(traceback[, limit])

返回从追溯对象追溯中提取的最多限制“预处理”堆栈跟踪条目的列表。 对堆栈跟踪的替代格式化非常有用。如果省略limit或None,则提取所有条目。 “预处理”堆栈跟踪条目是4元组(文件名,行号,函数名称,文本),表示通常为堆栈跟踪打印的信息。文本是一个带有前导和尾随空格的字符串;如果来源不可用,则为None

https://docs.python.org/2/library/traceback.html

答案 2 :(得分:0)

在我的用例中,Vinay Sajip的代码不能很好地工作(我使用的是更复杂的消息格式),所以我想到了这个代码(对我来说,它也更干净):

class OneLineExceptionFormatter(logging.Formatter):
    def format(self, record):
        if record.exc_info:
            # Replace record.msg with the string representation of the message
            # use repr() to prevent printing it to multiple lines
            record.msg = repr(super().formatException(record.exc_info))
            record.exc_info = None
        result = super().format(record)
        return result

因此,此format()方法可以检测到将要记录异常,并且可以将其转换为其字符串表示形式,并且日志消息的格式仅针对该普通消息字符串进行。 我在python 3中进行了测试。