Add exception e-mail handler
This commit is contained in:
parent
5c00f2b512
commit
45eec97bf3
|
@ -29,6 +29,7 @@ Config.load_plugins()
|
|||
|
||||
from rophako import __version__
|
||||
from rophako.plugin import load_plugin
|
||||
from rophako.log import logger
|
||||
import rophako.model.tracking as Tracking
|
||||
import rophako.utils
|
||||
|
||||
|
@ -156,6 +157,16 @@ def index():
|
|||
return catchall("index")
|
||||
|
||||
|
||||
@app.errorhandler(Exception)
|
||||
def catch_exception(error):
|
||||
"""Catch unexpected Python exceptions and e-mail them out."""
|
||||
logger.error("INTERNAL SERVER ERROR: {}".format(str(error)))
|
||||
|
||||
# E-mail it out.
|
||||
rophako.utils.handle_exception(error)
|
||||
return rophako.utils.template("errors/500.html")
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def not_found(error):
|
||||
return render_template('errors/404.html', **g.info), 404
|
||||
|
|
|
@ -13,6 +13,7 @@ import json
|
|||
import time
|
||||
|
||||
from rophako.settings import Config
|
||||
from rophako.utils import handle_exception
|
||||
from rophako.log import logger
|
||||
|
||||
redis_client = None
|
||||
|
@ -137,7 +138,10 @@ def read_json(path):
|
|||
data = json.loads(text)
|
||||
except:
|
||||
logger.error("Couldn't decode JSON data from {}".format(path))
|
||||
logger.error(text)
|
||||
handle_exception(Exception("Couldn't decode JSON from {}\n{}".format(
|
||||
path,
|
||||
text,
|
||||
)))
|
||||
data = None
|
||||
|
||||
return data
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from flask import g, session, request, render_template, flash, redirect, url_for
|
||||
from flask import (g, session, request, render_template, flash, redirect,
|
||||
url_for, current_app)
|
||||
from functools import wraps
|
||||
import codecs
|
||||
import uuid
|
||||
|
@ -12,6 +13,7 @@ import smtplib
|
|||
import markdown
|
||||
import json
|
||||
import urlparse
|
||||
import traceback
|
||||
|
||||
from rophako.log import logger
|
||||
from rophako.settings import Config
|
||||
|
@ -192,6 +194,61 @@ def send_email(to, subject, message, sender=None, reply_to=None):
|
|||
server.quit()
|
||||
|
||||
|
||||
def handle_exception(error):
|
||||
"""Send an e-mail to the site admin when an exception occurs."""
|
||||
if current_app.config.get("DEBUG"):
|
||||
print traceback.format_exc()
|
||||
raise
|
||||
|
||||
import rophako.jsondb as JsonDB
|
||||
|
||||
# Don't spam too many e-mails in a short time frame.
|
||||
cache = JsonDB.get_cache("exception_catcher")
|
||||
if cache:
|
||||
last_exception = int(cache)
|
||||
if int(time.time()) - last_exception < 120:
|
||||
# Only one e-mail per 2 minutes, minimum
|
||||
logger.error("RAPID EXCEPTIONS, DROPPING")
|
||||
return
|
||||
JsonDB.set_cache("exception_catcher", int(time.time()))
|
||||
|
||||
username = "anonymous"
|
||||
try:
|
||||
if "username" in g.info["session"]:
|
||||
username = g.info["session"]["username"]
|
||||
except:
|
||||
pass
|
||||
|
||||
# Get the timestamp.
|
||||
timestamp = time.ctime(time.time())
|
||||
|
||||
# Exception's traceback.
|
||||
error = str(error.__class__.__name__) + ": " + str(error)
|
||||
stacktrace = error + "\n\n" \
|
||||
+ "==== Start Traceback ====\n" \
|
||||
+ traceback.format_exc() \
|
||||
+ "==== End Traceback ====\n"
|
||||
|
||||
# Construct the subject and message
|
||||
subject = "Internal Server Error on {} - {} - {}".format(
|
||||
Config.site.site_name,
|
||||
username,
|
||||
timestamp,
|
||||
)
|
||||
message = "{} has experienced an exception on the route: {}".format(
|
||||
username,
|
||||
request.path,
|
||||
)
|
||||
message += "\n\n" + stacktrace
|
||||
|
||||
# Send the e-mail.
|
||||
send_email(
|
||||
to=Config.site.notify_address,
|
||||
subject=subject,
|
||||
message=message,
|
||||
)
|
||||
|
||||
|
||||
def generate_csrf_token():
|
||||
"""Generator for CSRF tokens."""
|
||||
if "_csrf" not in session:
|
||||
|
|
10
rophako/www/errors/500.html
Normal file
10
rophako/www/errors/500.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block title %}Internal Server Error{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<h1>Internal Server Error</h1>
|
||||
|
||||
This website has experienced an error. The site admin has been sent an e-mail
|
||||
about this. Please retry your request sometime later.
|
||||
|
||||
{% endblock %}
|
|
@ -25,12 +25,17 @@ parser.add_argument(
|
|||
type=str,
|
||||
help="SSL certificate file.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--production",
|
||||
help="Turns off debug mode, runs as if in production.",
|
||||
action="store_true",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if __name__ == '__main__':
|
||||
flask_options = dict(
|
||||
host='0.0.0.0',
|
||||
debug=True,
|
||||
debug=not args.production,
|
||||
port=args.port,
|
||||
threaded=True,
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user