How to log python exception? [duplicate]
Asked Answered
U

5

129

How can I log an exception in Python?

I've looked at some options and found out I can access the actual exception details using this code:

import sys
import traceback

try:
    1/0
except:
    exc_type, exc_value, exc_traceback = sys.exc_info()
    traceback.print_exception(exc_type, exc_value, exc_traceback)

I would like to somehow get the string print_exception() throws to stdout so that I can log it.

Unilateral answered 22/12, 2010 at 11:46 Comment(2)
At least raise (without argument, so the stracktrace gets preserved) after logging, otherwise you swallow the exception silently.Pauly
You should always explicitly state the exception you are trying to catch: except NameError as e, say. That will prevent you catching things like KeyboardInterrupt and give you a reference to the exception object, which you can study for more details.Southward
V
102

In Python 3.5 you can pass exception instance in exc_info argument:

import logging
try:
    1/0
except Exception as e:
   logging.error('Error at %s', 'division', exc_info=e)
Veron answered 23/6, 2016 at 13:24 Comment(2)
This is exactly what I wanted. I needed to log an exception from a task and didn't have an except block.Odelet
Or just directly use logging.exception("..") and it will automatically log the traceback.Fellmonger
W
162

Take a look at logging.exception (Python Logging Module)

import logging 
def foo():
    try:
        some_code()
    except:
        logging.exception('')

This should automatically take care of getting the traceback for the current exception and logging it properly.

Wardroom answered 22/12, 2010 at 11:49 Comment(1)
except catch-all can be a bad idea: https://mcmap.net/q/36432/-how-can-i-write-a-try-except-block-that-catches-all-exceptionsSolidstate
V
102

In Python 3.5 you can pass exception instance in exc_info argument:

import logging
try:
    1/0
except Exception as e:
   logging.error('Error at %s', 'division', exc_info=e)
Veron answered 23/6, 2016 at 13:24 Comment(2)
This is exactly what I wanted. I needed to log an exception from a task and didn't have an except block.Odelet
Or just directly use logging.exception("..") and it will automatically log the traceback.Fellmonger
V
64

To answer your question, you can get the string version of print_exception() using the traceback.format_exception() function. It returns the traceback message as a list of strings rather than printing it to stdout, so you can do what you want with it. For example:

import sys
import traceback

try:
    asdf
except NameError:
    exc_type, exc_value, exc_traceback = sys.exc_info()
    lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
    print ''.join('!! ' + line for line in lines)  # Log it or whatever here

This displays:

!! Traceback (most recent call last):
!!   File "<stdin>", line 2, in <module>
!! NameError: name 'asdf' is not defined

However, I'd definitely recommend using the standard Python logging module, as suggested by rlotun. It's not the easiest thing to set up, but it's very customizable.

Venitavenite answered 22/12, 2010 at 14:32 Comment(3)
"not the easiest thing to set up" sort of implies that it's hard to set up, but that's just not true, logging.basicConfig() in the main function is adequate for most simple applications.Ingraham
You code is useful when you cannot use logging package. E.g. When implementing a logging Handler :-)Boring
@Doomsday, I would think implementing a logging.Handler might be the only good use for this code. For the OP's original question, OP should definitely use logging with logging.exception or log at a lower level with exc_info=True.Trigg
P
62

Logging exceptions is as simple as adding the exc_info=True keyword argument to any log message, see entry for Logger.debug in http://docs.python.org/2/library/logging.html.

Example:

try: 
    raise Exception('lala')
except Exception:
    logging.info('blah', exc_info=True)

output (depending, of course, on your log handler config):

2012-11-29 10:18:12,778 - root - INFO - <ipython-input-27-5af852892344> : 3 - blah
Traceback (most recent call last):
  File "<ipython-input-27-5af852892344>", line 1, in <module>
    try: raise Exception('lala')
Exception: lala
Pyroxylin answered 29/11, 2012 at 8:22 Comment(4)
You're going to a lot of effort. Why not just logging.exception(exc)?Leisure
logging.exception is short for logging.error(..., exc_info=True), so if you intend to log the exception as an error it would be better to use logging.exception. If you want to log a formatted exception at a log level other than error you must use exc_info=True.Pyroxylin
"explicit is better than implicit"Thinkable
@ChrisJohnson - you could simply use logging.exception() in your example... Also, there are perfectly reasonable architectural reasons to want to log exception info and not set the log's LEVEL to ERROR. logger.exception is a unique case since it's the only call that doesn't explicitly set the LEVEL to be its function name. logger.exception() sets the level to ERROR. We have alarms tied to spikes in errors, and although some exceptions are not important enough to raise those alarms, we definitely want to log the exc_info for them.Antonietta
M
2

First of all, consider using a proper Exception type on your except clause. Then, naming the exception, you can print it:

try:
    1/0
except Exception as e:
    print e

Dependending on your Python version, you must use

except Exception, e
Muricate answered 22/12, 2010 at 12:42 Comment(3)
Printing is not logging. Use logging.exception(exc).Leisure
@ChrisJohnson you've recommended logging.exception(exc) in a few comments on this page, but it's a bad idea. The first argument to logging.exception isn't for the exception to log (Python just grabs the one from the current except: block by magic), it's for the message to log before the traceback. Specifying the exception as the message causes it to be converted to a string, which results in the exception message being duplicated. If you don't have a meaningful message to log along with your exception, use logging.exception(''), but logging.exception(exc) makes little sense.Jaynajayne
This is the most candid code here. Meaningful message as default.Teeming

© 2022 - 2024 — McMap. All rights reserved.