Python/Django 日志记录的额外选项
我在Django里有一个日志配置文件,它会获取 sys.exc_info()
这个元组,并把它作为额外的选项在记录日志时使用(下面格式化器里的 type
和 value
变量就是这样)。
'formatters': {
'basic': {
'format': '%(levelname)s %(lineno)d %(message)s %(type)s %(value)s'
},
},
这是我记录错误的方式:
except Exception, e:
extra = {'type':sys.exc_info()[0], 'value':sys.exc_info()[1]}
logger.warning('My message', extra=extra)
但是如果我简单地写
except Exception, e:
logger.warning('My message')
我会遇到一个异常,因为在格式化器里 type
和 value
这两个变量现在是未定义的。我该怎么告诉格式化器,把这些变量当作可选的呢?也就是说,如果我在记录日志时传递了它们,就使用它们;如果没有,就跳过它们。
1 个回答
我建议你在记录日志时,不要把 exc_info
的各个部分直接传进去。其实,如果发生了异常,并且你传入了 exc_info=True
或者 exc_info=sys.exc_info()
,那么这个元组已经存储在 LogRecord
的 exc_info
属性里了。你可以在格式化器中访问这些信息,所以你可以使用一个 Formatter
的子类或者一个 Filter
的子类,把元组中的部分内容转换成其他的 LogRecord
属性,这样就可以在格式字符串中引用它们(或者通过自定义的 Formatter
子类来处理)。
更新:你可以在格式字符串中用 %(exc_info)s
来引用它,但这样只是会显示这个元组。需要注意的是,Formatter
的 formatException
方法可以被重写,以便显示异常信息。默认情况下,它会格式化成标准的追踪信息——我理解你是想避免这种情况,对吧?
class MyFormatter(logging.Formatter):
def formatException(self, exc_info):
return 'exception: %s %s' % exc_info[:2])
这样会打印一行信息,而不是完整的追踪信息,但会在新的一行显示。或者你可以使用类似这样的方式:
class MyFormatter(logging.Formatter):
def format(self, record):
if isinstance(record.exc_info, tuple):
record.exc_data = ' %s %s' % record.exc_info[:2]
else:
record.exc_data = ''
return super(MyFormatter, self).format(record)
def formatException(self, exc_info):
return ''
然后在格式字符串中使用 %(exc_data)s
。
在这两种情况下,你需要确保在记录日志时传入真实的 exc_info
,以确保异常数据被保存到 LogRecord
中。日志记录器的 exception()
方法会做到这一点(使用 ERROR
级别)。
进一步更新:如果你想用 Filter
的子类来实现,可以这样做:
class MyFilter(logging.Filter):
def filter(self, record):
if isinstance(record.exc_info, tuple):
record.exc_data = ' %s %s' % record.exc_info[:2]
else:
record.exc_data = ''
# The next bit is to prevent the standard Formatter from writing
# a traceback
record.exc_info = None
return True # otherwise, the record doesn't get output
这应该和之前的例子效果一样,所以你可以使用相同的格式字符串。