Add sentry exception monitoring.
This commit is contained in:
parent
b30d0976f0
commit
fe665118bb
8 changed files with 77 additions and 8 deletions
2
app.py
2
app.py
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -30,3 +30,6 @@ git+https://github.com/NateFerrero/oauth2lib.git
|
|||
alembic
|
||||
sqlalchemy
|
||||
python-magic
|
||||
reportlab==2.7
|
||||
blinker
|
||||
raven
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
28
util/exceptionlog.py
Normal 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)
|
Reference in a new issue