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.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

View File

@ -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

View File

@ -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:

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,
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,
)