Python logging exception
Asked Answered
W

3

37

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?

Workbench answered 9/8, 2011 at 21:9 Comment(2)
possible duplicate of python exception loggingLegend
That's exactly what I am doing. Thanks for posting this question.Selfliquidating
N
40

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.

Nonjuror answered 9/8, 2011 at 21:16 Comment(2)
Is the last keyword supposed to be "except" instead of "else" or does that serve some purpose?Albertinaalbertine
It's supposed to be else. The else clause happens only if there was no exception, just like the else clause on for and while loops only happen if you didn't break out.Nonjuror
K
12

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
Kebab answered 9/8, 2011 at 21:16 Comment(0)
B
3

You can just extend the standard Exception class and add the logger into there.

Like this:

class LoggedException(Exception):
    """ An exception that also logs the msg to the given logger. """
    def __init__(self, logger: logging.Logger, msg: str):
        logger.error(msg)
        super().__init__(msg)
Ballman answered 20/10, 2022 at 7:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.