Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to intercept all exceptions in flask?

Perhaps I am not seeing something in the documentation.

I would like to not just handle some http errors, but all exceptions. The reason - I would like to log them using my own custom logic (sounds like reinventing the wheel, but I need full control over logging. I would like to not bring the server to its knees upon an exception, but bomb only that particular request.

This is how I launch Flask now. Here app.run starts the server. How can I instruct it to call my exception handler method whenever an exception occurs?

def main():
    args = parse_args()
    app.config['PROPAGATE_EXCEPTIONS'] = True
    flask_options = {'port' : args.port}
    if args.host == 'public':
        flask_options['host'] = '0.0.0.0'
    app.run(**flask_options)

if __name__ == '__main__':
    _sys.exit(main())
like image 470
Leonid Avatar asked Nov 28 '13 05:11

Leonid


1 Answers

Old question, but for anyone reading in 2021:

For all exceptions that aren't explicitly defined a 500 code can be returned.

The structure of the function is from Flask cookiecutter, though the pattern had a Jinja template for every error.

I haven't had luck catching all exceptions automatically, but I found this to be a lot DRYer then having an individual page for each individual exception.

"""
app.exceptions
==============
(python3)
"""
# app/exceptions.py
from typing import Tuple

from flask import Flask, render_template
from werkzeug.exceptions import HTTPException

EXCEPTIONS = {
    400: "Bad Request",
    401: "Unauthorized",
    403: "Forbidden",
    404: "Not Found",
    405: "Method Not Allowed",
    500: "Internal Server Error",
}


# general function structure: https://github.com/cookiecutter-flask/cookiecutter-flask
def init_app(app: Flask) -> None:
    """Register error handlers."""

    def render_error(error: HTTPException) -> Tuple[str, int]:
        """Render error template.

        If a HTTPException, pull the ``code`` attribute; default to 500.

        :param error: Exception to catch and render page for.
        :return: Tuple consisting of rendered template and error code.
        """
        app.logger.error(error.description)
        error_code = getattr(error, "code", 500)
        return (
            render_template(
                "exception.html",
                error_code=error_code,
                exception=EXCEPTIONS[error_code],
            ),
            error_code,
        )

    for errcode in [400, 401, 403, 404, 405, 500]:
        app.errorhandler(errcode)(render_error)

{# app/templates/exception.html #}
{% extends "base.html" %}

{# page header and browser tab #}
{% block page_name %}{{ error_code }} {{ exception }}{% endblock %}
like image 66
jshwi Avatar answered Oct 10 '22 01:10

jshwi