Michael Scheper
Michael Scheper

Reputation: 7038

How to make Flask log chained exceptions in unhandled exceptions?

Python 3 introduced exception chaining, so this:

import logging

logger = logging.getLogger(__name__)

class MyException(Exception):
    pass

def blow_up():
    try:
        impossible = 42 / 0
    except ZeroDivisionError as zde:
        raise MyException('Uh oh!') from zde

try:
    blow_up()
except:
    logger.exception('It blew up!')

Produces this:

It blew up!
Traceback (most recent call last):
  File "ka-boom.py", line 10, in blow_up
    impossible = 42 / 0
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "ka-boom.py", line 15, in <module>
    blow_up()
  File "ka-boom.py", line 12, in blow_up
    raise MyException('Uh oh!') from zde
MyException: Uh oh!

But when an unhandled exception gets thrown in a Flask view method, the __cause__ doesn't get logged, which makes debugging hard.

I can do this:

@app.errorhandler(Exception)
def better_exception_handler(error):
    current_app.logger.exception('Whoopsie!')
    return 'Internal server error', 500

but I feel uncomfortable capturing all exceptions like this, and it doesn't feel very elegant. Is there a way to get Flask's built-in exception handler to log the chained exception?

Upvotes: 5

Views: 2800

Answers (1)

Ryan Baker
Ryan Baker

Reputation: 303

Can you supply the version of Python and Flask that you're using? With Python 3.5.2 and Flask 0.12.1 I'm seeing what you're saying should happen.

from flask import Flask
app = Flask(__name__)


@app.route('/error')
def error_out():
    try:
        blow_up()
    except:
        app.logger.exception('it blew up!')
        return 'something went wrong'
    return 'everything is a-ok!'


def blow_up():
    try:
        impossible = 42 / 0
    except ZeroDivisionError as zde:
        raise MyExc('Uh oh!') from zde


class MyExc(Exception):
    pass


if __name__ == "__main__":
    app.run()

Hitting localhost:5000/error for me will then log the following in the console:

Seaking:flask-err rdbaker $ ~/.pyenv/versions/3.5.2/bin/python app.py 
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
[2017-05-15 12:19:52,229] ERROR in app: it blew up!
Traceback (most recent call last):
  File "app.py", line 21, in blow_up
    impossible = 42 / 0
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "app.py", line 12, in error_out
    blow_up()
  File "app.py", line 23, in blow_up
    raise MyExc('Uh oh!') from zde
MyExc: Uh oh!
127.0.0.1 - - [15/May/2017 12:19:52] "GET /error HTTP/1.1" 200 -

and I see the text something went wrong in my browser.

Upvotes: 2

Related Questions