I'm writing a program that parses 10 websites, locates data files, saves the files, and then parses them to make data that can be readily used in the NumPy library. There are tons of errors this file encounters through bad links, poorly formed XML, missing entries, and other things I've yet to categorize. I initially made this program to handle errors like this:
try:
do_stuff()
except:
pass
But now I want to log errors:
try:
do_stuff()
except Exception, err:
print Exception, err
Note this is printing to a log file for later review. This usually prints very useless data. What I want is to print the exact same lines printed when the error triggers without the try-except intercepting the exception, but I don't want it to halt my program since it is nested in a series of for loops that I would like to see to completion.
First, don't use
print
s for logging, there is stable, proven and well-thought stdlib's module to do that:logging
. You definitely should use it instead.Second, don't be tempted to do mess with unrelated tools when there is native and simple approach. Here is it:
That's it. You are done now.
Explanation for anyone who is interested in how things go under the hood
What
log.exception
doing is actually just call tolog.error
(that is, log event with levelERROR
) and print traceback then.Why it is better?
Well, here is some considerations:
Why nobody shouldn't use
treceback
nor call logger withexc_info=True
nor get him/her hands dirty withsys.exc_info
?Well, because! They are all exist for different purposes. For example,
traceback.print_exc
's output is a little bit different from tracebacks produced by interpreter itself. If you going to use it, you will confuse anyone who will be banging him head with your logs.Passing
exc_info=True
to log calls is just inappropriate. But, it is useful when you catching recoverable errors and want to log them (using, e.gINFO
level) with tracebacks as well, becauselog.exception
produces logs of only one level -ERROR
.And you definitely should avoid messing with
sys.exc_info
as much as you can. It is just not public interface, it is internal one - you can use it if you definitely know what you are doing. It is not intended just for printing exceptions.You want the traceback module. It will let you print stack dumps like Python normally does. In particular, the print_last function will print the last exception and a stack trace.
In addition to @Aaron Hall's answer, if you are logging, but don't want to use
logging.exception()
(since it logs at the ERROR level), you can use a lower level and passexc_info=True
. e.g.When you don't want to halt your program on an error, you need to handle that error with a try/except:
To extract the full traceback, we'll use the
traceback
module from the standard library:And to create a decently complicated stacktrace to demonstrate that we get the full stacktrace:
Printing
To print the full traceback, use the
traceback.print_exc
method:Which prints:
Better than printing, logging:
However, a best practice is to have a logger set up for your module. It will know the name of the module and be able to change levels (among other attributes, such as handlers)
In which case, you'll want the
logger.exception
function instead:Which logs:
Or perhaps you just want the string, in which case, you'll want the
traceback.format_exc
function instead:Which logs:
Conclusion
And for all three options, we see we get the same output as when we have an error: