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 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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
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,
|
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,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user