diff --git a/src/sentry/conf/server.py b/src/sentry/conf/server.py index 26781e6f9ed917..9fdd9bf01fdee5 100644 --- a/src/sentry/conf/server.py +++ b/src/sentry/conf/server.py @@ -781,6 +781,7 @@ def create_partitioned_queues(name): # Default project ID (for internal errors) SENTRY_PROJECT = 1 +SENTRY_PROJECT_KEY = None # Project ID for recording frontend (javascript) exceptions SENTRY_FRONTEND_PROJECT = None diff --git a/src/sentry/utils/raven.py b/src/sentry/utils/raven.py index bebf566a02ddca..65e64fa551b502 100644 --- a/src/sentry/utils/raven.py +++ b/src/sentry/utils/raven.py @@ -4,11 +4,12 @@ import inspect import logging import raven -import sentry +import six +import time from django.conf import settings -from django.db.utils import DatabaseError from raven.contrib.django.client import DjangoClient +from raven.utils import get_auth_header from . import metrics @@ -27,6 +28,8 @@ def is_current_event_safe(): class SentryInternalClient(DjangoClient): + request_factory = None + def is_enabled(self): if getattr(settings, 'DISABLE_RAVEN', False): return False @@ -43,9 +46,6 @@ def capture(self, *args, **kwargs): return super(SentryInternalClient, self).capture(*args, **kwargs) def send(self, **kwargs): - # TODO(dcramer): this should respect rate limits/etc and use the normal - # pipeline - # Report the issue to an upstream Sentry if active # NOTE: we don't want to check self.is_enabled() like normal, since # is_enabled behavior is overridden in this class. We explicitly @@ -60,69 +60,44 @@ def send(self, **kwargs): if not is_current_event_safe(): return - # Force raven-python encoding of this event, so that edge cases like - # non JSON-serializable objects are handled. - kwargs = self.decode(self.encode(kwargs)) - - from sentry import tsdb - from sentry.coreapi import ClientApiHelper - from sentry.event_manager import EventManager - from sentry.models import Project - - helper = ClientApiHelper( - agent='raven-python/%s (sentry %s)' % (raven.VERSION, sentry.VERSION), - project_id=settings.SENTRY_PROJECT, - version=self.protocol_version, - ) - - try: - project = Project.objects.get_from_cache(id=settings.SENTRY_PROJECT) - except DatabaseError: - self.error_logger.error('Unable to fetch internal project', exc_info=True) - return - except Project.DoesNotExist: - self.error_logger.error( - 'Internal project (id=%s) does not exist', settings.SENTRY_PROJECT - ) - return - except Exception: - self.error_logger.error( - 'Unable to fetch internal project for some unknown reason', exc_info=True - ) + # These imports all need to be internal to this function as this class + # is set up by django while still parsing LOGGING settings and we + # cannot import this stuff until settings are finalized. + from sentry.models import ProjectKey + from sentry.web.api import StoreView + from django.test import RequestFactory + key = None + if settings.SENTRY_PROJECT_KEY is not None: + key = ProjectKey.objects.filter( + id=settings.SENTRY_PROJECT_KEY, + project=settings.SENTRY_PROJECT).first() + if key is None: + key = ProjectKey.get_default(settings.SENTRY_PROJECT) + if key is None: return - helper.context.bind_project(project) - - metrics.incr('events.total') - - kwargs['project'] = project.id - try: - # This in theory is the right way to do it because validate - # also normalizes currently, but we just send in data already - # normalised in the raven client now. - # data = helper.validate_data(kwargs) - data = kwargs - manager = EventManager(data) - data = manager.normalize() - tsdb.incr_multi( - [ - (tsdb.models.project_total_received, project.id), - (tsdb.models.organization_total_received, project.organization_id), - ] - ) - helper.insert_data_to_database(data) - except Exception as e: - if self.raise_send_errors: - raise - message = kwargs.get('message') - if not message: - msg_interface = kwargs.get('sentry.interface.Message', {}) - message = msg_interface.get( - 'formatted', msg_interface.get('message', 'unknown error') - ) - self.error_logger.error( - 'Unable to record event: %s\nEvent was: %r', e, message, exc_info=True - ) + client_string = 'raven-python/%s' % (raven.VERSION,) + headers = { + 'HTTP_X_SENTRY_AUTH': get_auth_header( + protocol=self.protocol_version, + timestamp=time.time(), + client=client_string, + api_key=key.public_key, + api_secret=key.secret_key, + ), + 'HTTP_CONTENT_ENCODING': self.get_content_encoding(), + } + self.request_factory = self.request_factory or RequestFactory() + request = self.request_factory.post( + '/api/store', + data=self.encode(kwargs), + content_type='application/octet-stream', + **headers + ) + StoreView.as_view()( + request, + project_id=six.text_type(settings.SENTRY_PROJECT), + ) class SentryInternalFilter(logging.Filter):