Add sentry exception monitoring.

This commit is contained in:
Jake Moshenko 2014-04-28 18:59:22 -04:00
parent b30d0976f0
commit fe665118bb
8 changed files with 77 additions and 8 deletions

2
app.py
View file

@ -11,6 +11,7 @@ import features
from storage import Storage
from data.userfiles import Userfiles
from util.analytics import Analytics
from util.exceptionlog import Sentry
from data.billing import Billing
@ -44,3 +45,4 @@ storage = Storage(app)
userfiles = Userfiles(app)
analytics = Analytics(app)
billing = Billing(app)
sentry = Sentry(app)

View file

@ -32,7 +32,7 @@ def logs_init_builder(level=logging.DEBUG,
# values are set to the frontend, DO NOT PLACE ANY SECRETS OR KEYS in this list.
CLIENT_WHITELIST = ['SERVER_HOSTNAME', 'PREFERRED_URL_SCHEME', 'GITHUB_CLIENT_ID',
'GITHUB_LOGIN_CLIENT_ID', 'MIXPANEL_KEY', 'STRIPE_PUBLISHABLE_KEY',
'ENTERPRISE_LOGO_URL']
'ENTERPRISE_LOGO_URL', 'SENTRY_PUBLIC_DSN']
def getFrontendVisibleConfig(config_dict):
@ -102,6 +102,11 @@ class DefaultConfig(object):
# Analytics
ANALYTICS_TYPE = "FakeAnalytics"
# Exception logging
EXCEPTION_LOG_TYPE = 'FakeSentry'
SENTRY_DSN = None
SENTRY_PUBLIC_DSN = None
# Github Config
GITHUB_TOKEN_URL = 'https://github.com/login/oauth/access_token'
GITHUB_USER_URL = 'https://api.github.com/user'

View file

@ -155,6 +155,7 @@ def render_page_template(name, **kwargs):
feature_set=json.dumps(features.get_features()),
config_set=json.dumps(getFrontendVisibleConfig(app.config)),
mixpanel_key=app.config.get('MIXPANEL_KEY', ''),
sentry_public_dsn=app.config.get('SENTRY_PUBLIC_DSN', ''),
is_debug=str(app.config.get('DEBUGGING', False)).lower(),
show_chat=features.OLARK_CHAT,
cache_buster=cache_buster,

View file

@ -30,3 +30,6 @@ git+https://github.com/NateFerrero/oauth2lib.git
alembic
sqlalchemy
python-magic
reportlab==2.7
blinker
raven

View file

@ -6,10 +6,11 @@ Flask-Principal==0.4.0
Flask-RESTful==0.2.12
Jinja2==2.7.2
Mako==0.9.1
MarkupSafe==0.19
MarkupSafe==0.21
Pillow==2.4.0
PyGithub==1.24.1
PyMySQL==0.6.1
PyMySQL==0.6.2
PyPDF2==1.21
SQLAlchemy==0.9.4
Werkzeug==0.9.4
alembic==0.6.4
@ -23,8 +24,8 @@ ecdsa==0.11
gevent==1.0
greenlet==0.4.2
gunicorn==18.0
hiredis==0.1.2
html5lib==1.0b3
hiredis==0.1.3
html5lib==0.999
itsdangerous==0.24
jsonschema==2.3.0
lockfile==0.9.1
@ -35,15 +36,15 @@ mixpanel-py==3.1.2
mock==1.0.1
git+https://github.com/NateFerrero/oauth2lib.git
paramiko==1.13.0
peewee==2.2.2
peewee==2.2.3
py-bcrypt==0.4
pyPdf==1.13
pycrypto==2.6.1
python-daemon==1.6
python-dateutil==2.2
python-digitalocean==0.7
python-magic==0.4.6
pytz==2014.2
raven==4.2.1
redis==2.9.1
reportlab==2.7
requests==2.2.1
@ -51,4 +52,4 @@ six==1.6.1
stripe==1.14.0
websocket-client==0.11.0
wsgiref==0.1.2
xhtml2pdf==0.0.5
xhtml2pdf==0.0.6

View file

@ -778,7 +778,18 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
olark('api.chat.updateVisitorStatus', {snippet: 'username: ' + userResponse.username});
}
if (window.Raven !== undefined) {
Raven.setUser({
email: userResponse.email,
id: userResponse.username
});
}
CookieService.putPermanent('quay.loggedin', 'true');
} else {
if (window.Raven !== undefined) {
Raven.setUser();
}
}
if (opt_callback) {
@ -1366,6 +1377,17 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
}]);
}
if (window.__config && window.__config.SENTRY_PUBLIC_DSN) {
quayApp.config(function($provide) {
$provide.decorator("$exceptionHandler", function($delegate) {
return function(ex, cause) {
$delegate(ex, cause);
Raven.captureException(ex, {extra: {cause: cause}});
};
});
});
}
function buildConditionalLinker($animate, name, evaluator) {
// Based off of a solution found here: http://stackoverflow.com/questions/20325480/angularjs-whats-the-best-practice-to-add-ngif-to-a-directive-programmatically

View file

@ -58,6 +58,7 @@
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.2.0/js/bootstrap-datepicker.min.js"></script>
<script src="//cdn.jsdelivr.net/g/bootbox@4.1.0,underscorejs@1.5.2,restangular@1.2.0,d3js@3.3.3,momentjs"></script>
<script src="//cdn.ravenjs.com/1.1.14/jquery,native/raven.min.js"></script>
<script src="https://checkout.stripe.com/checkout.js"></script>
@ -73,6 +74,12 @@
<script src="/static/{{ script_path }}?v={{ cache_buster }}"></script>
{% endfor %}
{% if sentry_public_dsn %}
<script type="text/javascript">
Raven.config('{{ sentry_public_dsn }}').install();
</script>
{% endif %}
{% if mixpanel_key %}
<!-- start Mixpanel --><script type="text/javascript">
(function(e,b){if(!b.__SV){var a,f,i,g;window.mixpanel=b;a=e.createElement("script");a.type="text/javascript";a.async=!0;a.src=("https:"===e.location.protocol?"https:":"http:")+'//cdn.mxpnl.com/libs/mixpanel-2.2.min.js';f=e.getElementsByTagName("script")[0];f.parentNode.insertBefore(a,f);b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}var c=b;"undefined"!==

28
util/exceptionlog.py Normal file
View file

@ -0,0 +1,28 @@
from raven.contrib.flask import Sentry as FlaskSentry
class FakeSentry(object):
pass
class Sentry(object):
def __init__(self, app=None):
self.app = app
if app is not None:
self.state = self.init_app(app)
else:
self.state = None
def init_app(self, app):
sentry_type = app.config.get('EXCEPTION_LOG_TYPE', 'FakeSentry')
if sentry_type == 'Sentry':
sentry = FlaskSentry(app)
else:
sentry = FakeSentry()
# register extension with app
app.extensions = getattr(app, 'extensions', {})
app.extensions['sentry'] = sentry
return sentry
def __getattr__(self, name):
return getattr(self.state, name, None)