better exceptions

This commit is contained in:
Emmanuel Viennet 2021-09-13 09:54:53 +02:00
parent c1b06b18b4
commit da204f5df8
2 changed files with 28 additions and 10 deletions

View File

@ -12,7 +12,7 @@ from logging.handlers import SMTPHandler, WatchedFileHandler
from flask import current_app, g, request from flask import current_app, g, request
from flask import Flask from flask import Flask
from flask import abort, has_request_context from flask import abort, has_request_context, jsonify
from flask import render_template from flask import render_template
from flask.logging import default_handler from flask.logging import default_handler
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
@ -24,7 +24,7 @@ from flask_moment import Moment
from flask_caching import Cache from flask_caching import Cache
import sqlalchemy import sqlalchemy
from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_exceptions import ScoValueError, APIInvalidParams
from config import DevConfig from config import DevConfig
import sco_version import sco_version
@ -56,6 +56,12 @@ def internal_server_error(e):
return render_template("error_500.html", SCOVERSION=sco_version.SCOVERSION), 500 return render_template("error_500.html", SCOVERSION=sco_version.SCOVERSION), 500
def handle_invalid_usage(error):
response = jsonify(error.to_dict())
response.status_code = error.status_code
return response
def render_raw_html(template_filename: str, **args) -> str: def render_raw_html(template_filename: str, **args) -> str:
"""Load and render an HTML file _without_ using Flask """Load and render an HTML file _without_ using Flask
Necessary for 503 error mesage, when DB is down and Flask may be broken. Necessary for 503 error mesage, when DB is down and Flask may be broken.
@ -94,13 +100,8 @@ class ScoSMTPHandler(SMTPHandler):
def getSubject(self, record: logging.LogRecord) -> str: def getSubject(self, record: logging.LogRecord) -> str:
stack_summary = traceback.extract_tb(record.exc_info[2]) stack_summary = traceback.extract_tb(record.exc_info[2])
frame_summary = stack_summary[-1] frame_summary = stack_summary[-1]
subject = f"Sco Exc: {record.exc_info[0].__name__} in {frame_summary.name} {frame_summary.filename}" subject = f"ScoExc({sco_version.SCOVERSION}): {record.exc_info[0].__name__} in {frame_summary.name} {frame_summary.filename}"
# stack_summary.reverse()
# with open("/tmp/looooo", "wt") as f:
# for frame_summary in stack_summary:
# f.write(
# f"{record.exc_info[0].__name__} in {frame_summary.name} {frame_summary.filename}\n"
# )
return subject return subject
@ -121,6 +122,7 @@ def create_app(config_class=DevConfig):
app.register_error_handler(ScoValueError, handle_sco_value_error) app.register_error_handler(ScoValueError, handle_sco_value_error)
app.register_error_handler(500, internal_server_error) app.register_error_handler(500, internal_server_error)
app.register_error_handler(503, postgresql_server_error) app.register_error_handler(503, postgresql_server_error)
app.register_error_handler(APIInvalidParams, handle_invalid_usage)
from app.auth import bp as auth_bp from app.auth import bp as auth_bp
@ -168,7 +170,6 @@ def create_app(config_class=DevConfig):
mailhost=(app.config["MAIL_SERVER"], app.config["MAIL_PORT"]), mailhost=(app.config["MAIL_SERVER"], app.config["MAIL_PORT"]),
fromaddr="no-reply@" + app.config["MAIL_SERVER"], fromaddr="no-reply@" + app.config["MAIL_SERVER"],
toaddrs=["exception@scodoc.org"], toaddrs=["exception@scodoc.org"],
subject="ScoDoc Exception from " + host_name,
credentials=auth, credentials=auth,
secure=secure, secure=secure,
) )

View File

@ -96,3 +96,20 @@ class ScoGenError(ScoException):
class ScoInvalidDateError(ScoValueError): class ScoInvalidDateError(ScoValueError):
pass pass
# Pour les API JSON
class APIInvalidParams(Exception):
status_code = 400
def __init__(self, message, status_code=None, payload=None):
Exception.__init__(self)
self.message = message
if status_code is not None:
self.status_code = status_code
self.payload = payload
def to_dict(self):
rv = dict(self.payload or ())
rv["message"] = self.message
return rv