Add exception e-mail handler

pull/2/head
Noah 2014-12-04 15:56:20 -08:00
parent 5c00f2b512
commit 45eec97bf3
5 changed files with 90 additions and 3 deletions

View File

@ -29,6 +29,7 @@ Config.load_plugins()
from rophako import __version__ from rophako import __version__
from rophako.plugin import load_plugin from rophako.plugin import load_plugin
from rophako.log import logger
import rophako.model.tracking as Tracking import rophako.model.tracking as Tracking
import rophako.utils import rophako.utils
@ -156,6 +157,16 @@ def index():
return catchall("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) @app.errorhandler(404)
def not_found(error): def not_found(error):
return render_template('errors/404.html', **g.info), 404 return render_template('errors/404.html', **g.info), 404

View File

@ -13,6 +13,7 @@ import json
import time import time
from rophako.settings import Config from rophako.settings import Config
from rophako.utils import handle_exception
from rophako.log import logger from rophako.log import logger
redis_client = None redis_client = None
@ -137,7 +138,10 @@ def read_json(path):
data = json.loads(text) data = json.loads(text)
except: except:
logger.error("Couldn't decode JSON data from {}".format(path)) 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 data = None
return data return data

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- 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 from functools import wraps
import codecs import codecs
import uuid import uuid
@ -12,6 +13,7 @@ import smtplib
import markdown import markdown
import json import json
import urlparse import urlparse
import traceback
from rophako.log import logger from rophako.log import logger
from rophako.settings import Config from rophako.settings import Config
@ -192,6 +194,61 @@ def send_email(to, subject, message, sender=None, reply_to=None):
server.quit() 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(): def generate_csrf_token():
"""Generator for CSRF tokens.""" """Generator for CSRF tokens."""
if "_csrf" not in session: if "_csrf" not in session:

View 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 %}

View File

@ -25,12 +25,17 @@ parser.add_argument(
type=str, type=str,
help="SSL certificate file.", 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() args = parser.parse_args()
if __name__ == '__main__': if __name__ == '__main__':
flask_options = dict( flask_options = dict(
host='0.0.0.0', host='0.0.0.0',
debug=True, debug=not args.production,
port=args.port, port=args.port,
threaded=True, threaded=True,
) )