Send error mail to admin

Closes: #73
This commit is contained in:
Edward Betts 2023-12-07 17:15:58 +00:00
parent 9ff61c3af8
commit 0465e5eddd
2 changed files with 75 additions and 0 deletions

72
agenda/error_mail.py Normal file
View file

@ -0,0 +1,72 @@
"""Send mail to admin when an error happens."""
import logging
from logging import Formatter
from logging.handlers import SMTPHandler
import flask
from flask import g, request
PROJECT = "agenda"
class MySMTPHandler(SMTPHandler):
"""Custom SMTP handler to change mail subject."""
def getSubject(self, record: logging.LogRecord) -> str:
"""Specify subject line for error mails."""
subject = (
f"{PROJECT} error: {record.exc_info[0].__name__}"
if (record.exc_info and record.exc_info[0])
else f"{PROJECT} error: {record.pathname}:{record.lineno:d}"
)
if qid := getattr(g, "qid", None):
subject += f" {qid}"
if label := getattr(g, "label", None):
subject += f": {label}"
return subject
class RequestFormatter(Formatter):
"""Custom logging formatter to include request."""
def format(self, record: logging.LogRecord) -> str:
"""Record includes request."""
record.request = request
return super().format(record)
def setup_error_mail(app: flask.Flask) -> None:
"""Send mail to admins when an error happens."""
formatter = RequestFormatter(
"""
Message type: {levelname}
Location: {pathname:s}:{lineno:d}
Module: {module:s}
Function: {funcName:s}
Time: {asctime:s}
GET args: {request.args!r}
URL: {request.url}
Message:
{message:s}
""",
style="{",
)
mail_handler = MySMTPHandler(
app.config["SMTP_HOST"],
app.config["MAIL_FROM"],
app.config["ADMINS"],
app.name + " error",
timeout=30,
)
mail_handler.setFormatter(formatter)
mail_handler.setLevel(logging.ERROR)
app.logger.propagate = True
app.logger.addHandler(mail_handler)

View file

@ -15,12 +15,15 @@ import werkzeug.debug.tbtools
import yaml import yaml
import agenda.data import agenda.data
import agenda.error_mail
import agenda.travel import agenda.travel
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.debug = False app.debug = False
app.config.from_object("config.default") app.config.from_object("config.default")
agenda.error_mail.setup_error_mail(app)
@app.errorhandler(werkzeug.exceptions.InternalServerError) @app.errorhandler(werkzeug.exceptions.InternalServerError)
def exception_handler(e: werkzeug.exceptions.InternalServerError) -> tuple[str, int]: def exception_handler(e: werkzeug.exceptions.InternalServerError) -> tuple[str, int]: