如何在 Python 日志记录中格式化异常堆栈跟踪?
How do I can format exception stacktraces in Python logging?
我在 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() 中不可或缺的一部分,但绕过该函数感觉很奇怪当我试图记录异常实例时。我如何记录我的回溯并格式化它们?是否应忽略回溯?
感谢您的宝贵时间!
您应该定义自己的函数,使用 traceback.extract_tb
将回溯格式化为您想要的语法,然后 return 或将其写入文件:
traceback.extract_tb(traceback[, limit])
Return 从回溯对象回溯中提取的最多限制“预处理”堆栈跟踪条目的列表。 对于堆栈跟踪的替代格式非常有用。如果省略限制或 None,将提取所有条目。 “预处理的”堆栈跟踪条目是一个 4 元组(文件名、行号、函数名称、文本),表示通常为堆栈跟踪打印的信息。文本是去除了前导和尾随空格的字符串;如果来源不可用,则为 None
.
您可以定义自己的 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
模块。
对于我的用例 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
record.exc_text = None
result = super().format(record)
return result
所以这个 format() 方法可以检测到一个异常将被记录,并且可以将它转换成它的字符串表示形式,并且日志消息的格式只发生在那个普通的消息字符串上。
我在 python 3.
测试过
我在 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() 中不可或缺的一部分,但绕过该函数感觉很奇怪当我试图记录异常实例时。我如何记录我的回溯并格式化它们?是否应忽略回溯?
感谢您的宝贵时间!
您应该定义自己的函数,使用 traceback.extract_tb
将回溯格式化为您想要的语法,然后 return 或将其写入文件:
traceback.extract_tb(traceback[, limit])
Return 从回溯对象回溯中提取的最多限制“预处理”堆栈跟踪条目的列表。 对于堆栈跟踪的替代格式非常有用。如果省略限制或 None,将提取所有条目。 “预处理的”堆栈跟踪条目是一个 4 元组(文件名、行号、函数名称、文本),表示通常为堆栈跟踪打印的信息。文本是去除了前导和尾随空格的字符串;如果来源不可用,则为 None
.
您可以定义自己的 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
模块。
对于我的用例 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
record.exc_text = None
result = super().format(record)
return result
所以这个 format() 方法可以检测到一个异常将被记录,并且可以将它转换成它的字符串表示形式,并且日志消息的格式只发生在那个普通的消息字符串上。 我在 python 3.
测试过