Logging Exceptions¶
Normally, none of the logging functions except logging.exception()
include a stack trace. To include a stack trace, pass exc_info=True
(e.g.
to log an exception + stack trace at a severity less than ERROR
), or
use logging.exception()
.
If there is a stack trace included, then the exception object itself is redundant.
Example¶
try:
...
except Exception as e:
logging.error(e)
...
This might seem innocuous at first. It’s not too uncommon to catch any exception at the top of your request / event handling loop, log it, and move on. But if you actually encounter an exception, what log message do you get? One example might be:
ERROR:root:0
Completely unhelpful! ERROR
is the severity, root
is the logger, and
0
could mean anything. In this case, maybe it was:
{}[0]
Which raises a KeyError: 0
. But logging.error(e)
doesn’t include the
KeyError
, because it’s equivalent to logging.error(str(e))
, and
str(e)
does not include the type.
One way out, if you really don’t want to include the stack trace, would be to manually include the exception name:
logging.error('%s: %s', type(e).__name_, e)
But since more information is better, it’s more helpful to include the stack trace:
logging.error("", exc_info=True)
# or:
logging.exception("")
Since the error message is already included in the stack trace, the log message
should be something useful, rather than ""
or e
.
logging.exception(e)
is redundant, and logging.exception("")
misses an
opportunity to provide context, specify what the inputs were, etc.