diff --git a/src/pretix/base/__init__.py b/src/pretix/base/__init__.py
index c89a3fad7c..d9d7652b0c 100644
--- a/src/pretix/base/__init__.py
+++ b/src/pretix/base/__init__.py
@@ -1,4 +1,5 @@
from django.apps import AppConfig
+from django.conf import settings
class PretixBaseConfig(AppConfig):
@@ -17,6 +18,10 @@ class PretixBaseConfig(AppConfig):
except ImportError:
pass
+ if hasattr(settings, 'RAVEN_CONFIG'):
+ from ..sentry import initialize
+ initialize()
+
default_app_config = 'pretix.base.PretixBaseConfig'
try:
diff --git a/src/pretix/base/templates/500.html b/src/pretix/base/templates/500.html
index 51a67b211a..409f3e30d1 100644
--- a/src/pretix/base/templates/500.html
+++ b/src/pretix/base/templates/500.html
@@ -6,6 +6,15 @@
{% trans "Internal Server Error" %}
{% trans "We had trouble processing your request." %}
{% trans "If this problem persists, please contact us." %}
+ {% if request.sentry.id %}
+
+ {% blocktrans trimmed %}
+ If you contact us, please send us the following code:
+ {% endblocktrans %}
+
+ {{ request.sentry.id }}
+
+ {% endif %}
{{ exception }}
{% trans "Take a step back" %}
diff --git a/src/pretix/base/views/errors.py b/src/pretix/base/views/errors.py
index 7ff9210444..7cedf04bc8 100644
--- a/src/pretix/base/views/errors.py
+++ b/src/pretix/base/views/errors.py
@@ -1,5 +1,8 @@
-from django.http import HttpResponseForbidden, HttpResponseNotFound
+from django.http import (
+ HttpResponseForbidden, HttpResponseNotFound, HttpResponseServerError,
+)
from django.middleware.csrf import REASON_NO_CSRF_COOKIE, REASON_NO_REFERER
+from django.template import TemplateDoesNotExist, loader
from django.template.loader import get_template
from django.utils.functional import Promise
from django.utils.translation import ugettext as _
@@ -53,3 +56,14 @@ def page_not_found(request, exception):
template = get_template('404.html')
body = template.render(context, request)
return HttpResponseNotFound(body)
+
+
+@requires_csrf_token
+def server_error(request):
+ try:
+ template = loader.get_template('500.html')
+ except TemplateDoesNotExist:
+ return HttpResponseServerError('
Server Error (500)
', content_type='text/html')
+ return HttpResponseServerError(template.render({
+ 'request': request
+ }))
diff --git a/src/pretix/celery_app.py b/src/pretix/celery_app.py
index 4a5a598f73..b451c0dd5a 100644
--- a/src/pretix/celery_app.py
+++ b/src/pretix/celery_app.py
@@ -9,10 +9,3 @@ from django.conf import settings
app = Celery('pretix')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
-
-
-if hasattr(settings, 'RAVEN_CONFIG'):
- # Celery signal registration
- from raven.contrib.celery import register_signal
- from raven.contrib.django.models import client
- register_signal(client, ignore_expected=True)
diff --git a/src/pretix/multidomain/maindomain_urlconf.py b/src/pretix/multidomain/maindomain_urlconf.py
index bd7bf25093..45be79040a 100644
--- a/src/pretix/multidomain/maindomain_urlconf.py
+++ b/src/pretix/multidomain/maindomain_urlconf.py
@@ -49,3 +49,4 @@ plugin_patterns = [
urlpatterns = common_patterns + plugin_patterns + presale_patterns_main
handler404 = 'pretix.base.views.errors.page_not_found'
+handler500 = 'pretix.base.views.errors.server_error'
diff --git a/src/pretix/multidomain/subdomain_urlconf.py b/src/pretix/multidomain/subdomain_urlconf.py
index d3cf991740..eefb5b4843 100644
--- a/src/pretix/multidomain/subdomain_urlconf.py
+++ b/src/pretix/multidomain/subdomain_urlconf.py
@@ -42,3 +42,4 @@ plugin_patterns = [
urlpatterns = common_patterns + plugin_patterns + presale_patterns
handler404 = 'pretix.base.views.errors.page_not_found'
+handler500 = 'pretix.base.views.errors.server_error'
diff --git a/src/pretix/sentry.py b/src/pretix/sentry.py
new file mode 100644
index 0000000000..d7a07d117f
--- /dev/null
+++ b/src/pretix/sentry.py
@@ -0,0 +1,41 @@
+from threading import Lock
+
+from raven.contrib.celery import SentryCeleryHandler
+from raven.contrib.django.apps import RavenConfig
+from raven.contrib.django.models import (
+ SentryDjangoHandler, client, get_client, install_middleware,
+ register_serializers,
+)
+
+_setup_lock = Lock()
+
+_initialized = False
+
+
+class CustomSentryDjangoHandler(SentryDjangoHandler):
+ def install_celery(self):
+ self.celery_handler = SentryCeleryHandler(client, ignore_expected=True).install()
+
+
+def initialize():
+ global _initialized
+
+ with _setup_lock:
+ if _initialized:
+ return
+
+ register_serializers()
+ install_middleware()
+
+ handler = CustomSentryDjangoHandler()
+ handler.install()
+
+ # instantiate client so hooks get registered
+ get_client() # NOQA
+
+ _initialized = True
+
+
+class App(RavenConfig):
+ def ready(self):
+ initialize()
diff --git a/src/pretix/settings.py b/src/pretix/settings.py
index 1f7ff42ded..cfa61e46d6 100644
--- a/src/pretix/settings.py
+++ b/src/pretix/settings.py
@@ -226,18 +226,6 @@ for entry_point in iter_entry_points(group='pretix.plugin', name=None):
PLUGINS.append(entry_point.module_name)
INSTALLED_APPS.append(entry_point.module_name)
-if config.has_option('sentry', 'dsn'):
- INSTALLED_APPS += [
- 'raven.contrib.django.raven_compat',
- ]
- DISABLE_SENTRY_INSTRUMENTATION = True # see celery.py for more, we use this differently
- RAVEN_CONFIG = {
- 'dsn': config.get('sentry', 'dsn'),
- 'transport': 'raven.transport.threaded_requests.ThreadedRequestsHTTPTransport',
- 'release': __version__,
- 'environment': SITE_URL,
- }
-
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
@@ -487,6 +475,17 @@ LOGGING = {
},
}
+if config.has_option('sentry', 'dsn'):
+ INSTALLED_APPS += [
+ 'pretix.sentry.App',
+ ]
+ RAVEN_CONFIG = {
+ 'dsn': config.get('sentry', 'dsn'),
+ 'transport': 'raven.transport.threaded_requests.ThreadedRequestsHTTPTransport',
+ 'release': __version__,
+ 'environment': SITE_URL,
+ }
+
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'