I would suggest that you don't pass the exc_info tuple parts explicitly in your logging calls. Instead, note that if an exception occurs and you pass exc_info=True or exc_info=sys.exc_info(), then the tuple is already stored in the LogRecord's exc_info attribute. You can access these in your formatter, so you can either use a Formatter subclass or a Filter subclass to convert parts of the tuple to other LogRecord attributes which can be referred to in the format string (or even otherwise, handled by a custom Formatter subclass).
Update: You can reference as %(exc_info)s in the format string, but that will just display the tuple. Note that a Formatter's formatException method can be overridden to display the exception. The default will format a standard traceback - do I understand that you don't want that to happen?
class MyFormatter(logging.Formatter):
def formatException(self, exc_info):
return 'exception: %s %s' % exc_info[:2])
That would print a one-liner rather than a full traceback, but on a new line. Or you could use an approach like:
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 ''
and then use a format string with %(exc_data)s in it.
With both of these, you need to ensure that a true exc_info is passed into the logging call, to ensure that the exception data is saved in the LogRecord. The exception() method of loggers does this (with a level of ERROR).
Further update: To do this with a Filter subclass, you could do something like:
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
This should have the same effect as the earlier example, so you can use the same format string.
Filterexample.