Python logging exception

Question:

I’m currently writing a wrapper class. I want to be able to log exceptions properly but allow calling methods to be aware of exceptions which occur. My class looks like this:

import logging

log = logging.getLogger('module')

class MyAPIWrapper(library.APIClass):

    def __init__(self):
        self.log = logging.getLogger('module.myapiwrapper')


    def my_wrapper_method(self):
        try:
            response = self.call_api_method()
            return response.someData
        except APIException, e:
            self.log.exception('Oh noes!')
            raise e #Throw exception again so calling code knows it happened

I’m a bit dubious about catching and exception just to log it and then re-raising it so the calling code can do something about it. What’s the proper pattern here?

Asked By: user130076

||

Answers:

There is nothing wrong with catching to log. However, I’d recommend:

    try:
        response = self.call_api_method()
    except APIException, e:  # or 'as e' depending on your Python version
        self.log.exception('Oh noes!')
        raise #Throw exception again so calling code knows it happened
    else:
        return response.someData

By just doing a bare raise you preserve the full traceback info. It’s also more explicit to put code that will only happen if you don’t have an exception in the else clause, and it’s clearer what line you’re catching an exception from.

It would also be fine for the calling class to do the logging if it’s handling the error anyway, but that may not be convenient for your app.

Edit: The documentation for try ... except ... else ... finally is under compound statements.

Answered By: agf

That method is correct, although instead of raise e you should just use raise, which will automatically re-raise the last exception. This is also one of the rare cases where using a blanket except is considered acceptable.

Here is an example very similar to what you are doing from the Python docs on Handling Exceptions:

The last except clause may omit the exception name(s), to serve as a wildcard. Use this with extreme caution, since it is easy to mask a real programming error in this way! It can also be used to print an error message and then re-raise the exception (allowing a caller to handle the exception as well):

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise
Answered By: Andrew Clark