def testSignalsWithoutRequest(self): request = RF.get("/", REMOTE_ADDR="127.0.0.1:8000") try: Message.objects.get(id=999999999) except Message.DoesNotExist, exc: got_request_exception.send(sender=self.__class__, request=None)
def custom_exception_handler(exc): """ Custom exception handler for DRF, which doesn't provide one for HTTP responses like tastypie does. """ # Call REST framework's default exception handler first, # to get the standard error response. response = exception_handler(exc) # If the response is None, then DRF didn't handle the exception and we # should do it ourselves. if response is None: # Start with a generic default error message. data = {"detail": "Internal Server Error"} # Include traceback if DEBUG is active. if settings.DEBUG: import traceback import sys data['error_message'] = unicode(exc) data['traceback'] = '\n'.join( traceback.format_exception(*(sys.exc_info()))) request = getattr(exc, '_request', None) klass = getattr(exc, '_klass', None) # Send the signal so other apps are aware of the exception. got_request_exception.send(klass, request=request) # Send the 500 response back. response = Response(data, status=status.HTTP_500_INTERNAL_SERVER_ERROR) return response
def _wrapped(request, *args, **kwargs): try: status = 200 headers = { 'Access-Control-Allow-Origin': '*', } if len(methods) > 0 and request.method not in methods: data = http.HttpResponseNotAllowed('') else: # Call the view data = func(request, *args, **kwargs) # Isn't thrown as an exception, but instead returned if isinstance(data, http.HttpResponseNotAllowed): return http.HttpResponse(dumps({ 'error': 405, 'msg': 'HTTP method not allowed.', }), status=405, content_type='application/json') # Allow for multiple results if isinstance(data, tuple): if len(data) == 2: data, status = data elif len(data) == 3: data, status, headers = data else: raise Exception('Too many return values from view') if not isinstance(data, dict): raise Exception('Expected dictionary') resp = http.HttpResponse(dumps(data), status=status, content_type='application/json') for h in headers: resp[h] = headers[h] except Exception as e: if isinstance(e, BadRequest): resp = http.HttpResponseBadRequest(dumps({ 'error': 400, 'msg': str(e), }), content_type='application/json') elif isinstance(e, PermissionDenied): resp = http.HttpResponseForbidden(dumps({ 'error': 403, 'msg': str(e), }), content_type='application/json') elif isinstance(e, http.Http404): resp = http.HttpResponseNotFound(dumps({ 'error': 404, 'msg': str(e), }), content_type='application/json') else: got_request_exception.send(sender=BaseHandler, request=request) resp = http.HttpResponseServerError(dumps({ 'error': 500, 'msg': 'Internal server error.', }), content_type='application/json') return resp
def process_exception(self, request, exception): if isinstance(exception, RecordModifiedError): got_request_exception.send(sender=self, request=request) callback = get_callable(conf.HANDLER409) return callback(request, target=exception.target) else: # pragma: no cover pass
def test_signal_integration(self): with Settings(METLOG_CONF=self.METLOG_CONF, METLOG=self.METLOG, SENTRY_CLIENT=self.SENTRY_CLIENT, SENTRY_DSN=DSN): self.raven = get_client() try: int('hello') except: got_request_exception.send(sender=self.__class__, request=None) else: self.fail('Expected an exception.') msgs = settings.METLOG.sender.msgs self.assertEquals(len(msgs), 1) event = self.raven.decode(json.loads(msgs[0])['payload']) self.assertTrue('sentry.interfaces.Exception' in event) exc = event['sentry.interfaces.Exception'] self.assertEquals(exc['type'], 'ValueError') self.assertEquals(exc['value'], u"invalid literal for int() with base 10: 'hello'") self.assertEquals(event['level'], logging.ERROR) self.assertEquals(event['message'], u"ValueError: invalid literal for int() with base 10: 'hello'") self.assertEquals(event['culprit'], 'tests.contrib.django.tests.test_signal_integration') # The project_id must be extracted from the SENTRY_DSN # option self.assertEquals(event['project'], str(TESTING_PROJECT_ID))
def custom_exception_handler(exc, context=None): """ Custom exception handler for DRF, which ensures every exception we throw is caught, returned as a nice DRF Response, while still going to sentry etc. The default DRF exception handler does some of this work already, but it lets non-api exceptions through, and we don't want that. """ # If propagate is true, bail early. if settings.DEBUG_PROPAGATE_EXCEPTIONS: raise # Call REST framework's default exception handler first, # to get the standard error response. response = exception_handler(exc, context) # If the response is None, then DRF didn't handle the exception and we # should do it ourselves. if response is None: # Start with a generic default error message. data = {'detail': 'Internal Server Error'} # Send the got_request_exception signal so other apps like sentry # are aware of the exception. The sender does not match what a real # exception would do (we don't have access to the handler here) but it # should not be an issue, what matters is the request. request = context.get('request') sender = context.get('view').__class__ got_request_exception.send(sender, request=request) # Send the 500 response back. response = Response(data, status=status.HTTP_500_INTERNAL_SERVER_ERROR) return response
def testSignalsWithoutRequest(self): Error.objects.all().delete() ErrorBatch.objects.all().delete() request = RF.get("/", REMOTE_ADDR="127.0.0.1:8000") try: Error.objects.get(id=999999999) except Error.DoesNotExist, exc: got_request_exception.send(sender=self.__class__, request=None)
def error_handler(self, e, request, meth, em_format): """ Override this method to add handling of errors customized for your needs """ if isinstance(e, FormValidationError): return self.form_validation_response(e) got_request_exception.send(sender=type(self), request=request) if isinstance(e, TypeError): result = rc.BAD_REQUEST hm = HandlerMethod(meth) sig = hm.signature msg = 'Method signature does not match.\n\n' if sig: msg += 'Signature should be: %s' % sig else: msg += 'Resource does not expect any parameters.' if self.display_errors: msg += '\n\nException was: %s' % str(e) result.content = format_error(msg) return result elif isinstance(e, Http404): return rc.NOT_FOUND elif isinstance(e, HttpStatusCode): return e.response else: """ On errors (like code errors), we'd like to be able to give crash reports to both admins and also the calling user. There's two setting parameters for this: Parameters:: - `PISTON_EMAIL_ERRORS`: Will send a Django formatted error email to people in `settings.ADMINS`. - `PISTON_DISPLAY_ERRORS`: Will return a simple traceback to the caller, so he can tell you what error they got. If `PISTON_DISPLAY_ERRORS` is not enabled, the caller will receive a basic "500 Internal Server Error" message. """ exc_type, exc_value, tb = sys.exc_info() rep = ExceptionReporter(request, exc_type, exc_value, tb.tb_next) if self.email_errors: self.email_exception(rep) if self.display_errors: return HttpResponseServerError( format_error('\n'.join(rep.format_exception()))) else: raise
def testIntegrityMessage(self): DuplicateKeyModel.objects.create() try: DuplicateKeyModel.objects.create() except: got_request_exception.send(sender=self.__class__) else: self.fail('Excepted an IntegrityMessage to be raised.') self.assertEquals(Message.objects.count(), 1) self.assertEquals(GroupedMessage.objects.count(), 1)
def process_exception(self, request, exception): got_request_exception.send(sender=self, request=request) if not self.should_log(request): return None page_request = self.get_existing_page_request(request) if self.page_request_is_valid(request, page_request): page_request.was_exception = True page_request.save()
def testDatabaseMessage(self): from django.db import connection try: cursor = connection.cursor() cursor.execute("select foo") except: got_request_exception.send(sender=self.__class__) self.assertEquals(Message.objects.count(), 1) self.assertEquals(GroupedMessage.objects.count(), 1)
def testIntegrityError(self): DuplicateKeyModel.objects.create() try: DuplicateKeyModel.objects.create() except: got_request_exception.send(sender=self.__class__) else: self.fail('Excepted an IntegrityError to be raised.') self.assertEquals(Error.objects.count(), 1) self.assertEquals(ErrorBatch.objects.count(), 1)
def process_exception(self, request, exception): if isinstance(exception, Http404): return elif isinstance(exception, PermissionDenied): return elif isinstance(exception, ImproperlyConfigured): logger.critical("Site improperly configured", exc_info=True) else: logger.exception("[500] %s at %s" % (type(exception).__name__, request.path)) got_request_exception.send(sender=self, request=request) return handler500(request, exc_info=sys.exc_info())
def test_task_discarded_when_request_failed( self, original_apply_async_mock): request_started.send(sender=self) test_task.delay() self._verify_one_task_queued() # Simulate a request exception. got_request_exception.send(sender=self) self._verify_task_empty() # Assert the original `apply_async` was not called. self.assertEqual( original_apply_async_mock.call_count, 0, 'Unexpected PostRequestTask.original_apply_async call')
def test_signal_integration(django_elasticapm_client): try: int('hello') except ValueError: got_request_exception.send(sender=None, request=None) assert len(django_elasticapm_client.events) == 1 event = django_elasticapm_client.events.pop(0)['errors'][0] assert 'exception' in event exc = event['exception'] assert exc['type'] == 'ValueError' assert exc['message'] == u"ValueError: invalid literal for int() with base 10: 'hello'" assert event['culprit'] == 'tests.contrib.django.django_tests.test_signal_integration' assert event['handled'] is False
def test_signal_integration(self): try: int('hello') except: got_request_exception.send(sender=self.__class__, request=None) else: self.fail('Expected an exception.') self.assertEquals(len(self.raven.events), 1) event = self.raven.events.pop(0) self.assertEquals(event['class_name'], 'ValueError') self.assertEquals(event['level'], logging.ERROR) self.assertEquals(event['message'], u"invalid literal for int() with base 10: 'hello'") self.assertEquals(event['view'], 'tests.contrib.django.tests.test_signal_integration')
def test_task_discarded_when_request_failed(self, original_apply_async_mock): request_started.send(sender=self) test_task.delay() self._verify_one_task_queued() # Simulate a request exception. got_request_exception.send(sender=self) self._verify_task_empty() # Assert the original `apply_async` was not called. self.assertEqual( original_apply_async_mock.call_count, 0, 'Unexpected PostRequestTask.original_apply_async call')
def exception_reporting(exception: Exception, context: ExceptionContext) -> None: """ Determines which exceptions to report and sends them to Sentry. Used through drf-exceptions-hog """ if not isinstance(exception, APIException): capture_exception(exception) # NOTE: to make sure we get exception tracebacks in test responses, we need # to make sure this signal is called. The django test client uses this to # pull out the exception traceback. # # See https://github.com/django/django/blob/ecf87ad513fd8af6e4a6093ed918723a7d88d5ca/django/test/client.py#L714 got_request_exception.send(sender=None, request=context["request"])
def _handle_500(self, request, exception): import traceback import sys the_trace = '\n'.join(traceback.format_exception(*(sys.exc_info()))) if settings.DEBUG: response_class = TracebackApplicationJsonError else: response_class = ApplicationJsonError response_code = 500 NOT_FOUND_EXCEPTIONS = (NotFound, ObjectDoesNotExist, Http404) if isinstance(exception, NOT_FOUND_EXCEPTIONS): if settings.DEBUG: response_class = TracebackNotFoundJsonError else: response_class = NotFoundJsonError response_code = 404 if settings.DEBUG: data = { "developer_message": sanitize(six.text_type(exception)), "traceback": the_trace, } return self.error_response(request, None, response_class=response_class, **data) # When DEBUG is False, send an error message to the admins (unless it's # a 404, in which case we check the setting). send_broken_links = getattr(settings, 'SEND_BROKEN_LINK_EMAILS', False) if not response_code == 404 or send_broken_links: log = logging.getLogger('django.request.tastypie') log.error('Internal Server Error: %s' % request.path, exc_info=True, extra={ 'status_code': response_code, 'request': request }) # Send the signal so other apps are aware of the exception. got_request_exception.send(self.__class__, request=request) return self.error_response(request, None, response_class=response_class)
def test_signal_integration(self): try: int(None) except Exception: got_request_exception.send(sender=self.__class__, request=None) else: self.fail('Expected an exception.') assert len(self.raven.events) == 1 event = self.raven.events.pop(0) assert 'exception' in event exc = event['exception']['values'][-1] assert exc['type'] == 'TypeError' assert exc['value'], "int() argument must be a string or a number == not 'NoneType'" assert event['level'] == logging.ERROR assert event['message'], "TypeError: int() argument must be a string or a number == not 'NoneType'"
def new(request): if request.POST: data = request.POST["data"] try: chart_data = utils.import_chart_data(data) except Exception, e: utils.save_import_failure(request.user.username, data) got_request_exception.send(sender=None, request=request) return HttpResponseServerError("Parse error: " + e.message) chart = Chart(creator=request.user) chart.chart_data = chart_data chart.save() return redirect(reverse("chart.views.edit", args=[chart.id]))
def _handle_500(self, request, exception): import traceback import sys the_trace = '\n'.join(traceback.format_exception(*(sys.exc_info()))) response_class = http.HttpApplicationError response_code = 500 NOT_FOUND_EXCEPTIONS = (NotFound, ObjectDoesNotExist, Http404) if isinstance(exception, NOT_FOUND_EXCEPTIONS): response_class = HttpResponseNotFound response_code = 404 detailed_data = { "error_message": six.text_type(exception), "traceback": the_trace, } self.log.error('_handle_500 error', exc_info=True, extra={'data': detailed_data, 'request': request, 'original_exception': exception}) if settings.DEBUG: return self.error_response(request, detailed_data, response_class=response_class) # When DEBUG is False, send an error message to the admins (unless it's # a 404, in which case we check the setting). send_broken_links = getattr(settings, 'SEND_BROKEN_LINK_EMAILS', False) if not response_code == 404 or send_broken_links: log = logging.getLogger('django.request.tastypie') log.error('Internal Server Error: %s' % request.path, exc_info=True, extra={'status_code': response_code, 'request': request}) # Send the signal so other apps are aware of the exception. got_request_exception.send(self.__class__, request=request) # Prep the data going out. if 400 <= response_code < 500: data = { "error_message": six.text_type(exception), } else: data = { "error_message": getattr(settings, 'TASTYPIE_CANNED_ERROR', "Sorry, this request could not be processed. Please try again later."), } return self.error_response(request, data, response_class=response_class)
def test_signal_integration(self): try: int(None) except Exception: got_request_exception.send(sender=self.__class__, request=None) else: self.fail("Expected an exception.") assert len(self.raven.events) == 1 event = self.raven.events.pop(0) assert "exception" in event exc = event["exception"]["values"][0] assert exc["type"] == "TypeError" assert exc["value"], "int() argument must be a string or a number == not 'NoneType'" assert event["level"] == logging.ERROR assert event["message"], "TypeError: int() argument must be a string or a number == not 'NoneType'" assert event["culprit"] == "tests.contrib.django.tests in test_signal_integration"
def test_signal_integration(self): try: int("hello") except: got_request_exception.send(sender=self.__class__, request=None) else: self.fail("Expected an exception.") self.assertEquals(len(self.raven.events), 1) event = self.raven.events.pop(0) self.assertTrue("sentry.interfaces.Exception" in event) exc = event["sentry.interfaces.Exception"] self.assertEquals(exc["type"], "ValueError") self.assertEquals(exc["value"], u"invalid literal for int() with base 10: 'hello'") self.assertEquals(event["level"], logging.ERROR) self.assertEquals(event["message"], u"ValueError: invalid literal for int() with base 10: 'hello'") self.assertEquals(event["culprit"], "tests.contrib.django.tests.test_signal_integration")
def test_signal_integration(self): try: int('hello') except: got_request_exception.send(sender=self.__class__, request=None) else: self.fail('Expected an exception.') self.assertEquals(len(self.raven.events), 1) event = self.raven.events.pop(0) assert 'exception' in event exc = event['exception']['values'][0] self.assertEquals(exc['type'], 'ValueError') self.assertEquals(exc['value'], "invalid literal for int() with base 10: 'hello'") self.assertEquals(event['level'], logging.ERROR) self.assertEquals(event['message'], "ValueError: invalid literal for int() with base 10: 'hello'") self.assertEquals(event['culprit'], 'tests.tests in test_signal_integration')
def test_signal_integration(self): try: int('hello') except: got_request_exception.send(sender=self.__class__, request=None) else: self.fail('Expected an exception.') self.assertEquals(len(self.opbeat.events), 1) event = self.opbeat.events.pop(0) self.assertTrue('exception' in event) exc = event['exception'] self.assertEquals(exc['type'], 'ValueError') self.assertEquals(exc['value'], u"invalid literal for int() with base 10: 'hello'") self.assertEquals(event['level'], 'error') self.assertEquals(event['message'], u"ValueError: invalid literal for int() with base 10: 'hello'") self.assertEquals(event['culprit'], 'tests.contrib.django.django_tests.test_signal_integration')
def process_exception(self, request, exception): if issubclass(type(exception), ObjectDoesNotExist): exception = NotFound(str(exception)) if has_webargs and issubclass(type(exception), ValidationError): exception = BadRequest(exception.messages) if not issubclass(type(exception), ApiError): return None accept_headers = request.META.get('HTTP_ACCEPT', 'application/json') doc = Representation(request) doc.add_property('message', exception.message) if exception.logref is not None: doc.add_property('logref', exception.logref) if exception.path is not None: doc.add_property('path', exception.path) if exception.about is not None: doc.add_link('about', exception.about) if exception.describes is not None: doc.add_link('describes', exception.describes) if exception.help is not None: doc.add_link('help', exception.help) # Make sure the exception signal is fired for Sentry, but don't # bother it with anything that's not a server error if exception.status >= 500: got_request_exception.send(sender=self, request=request) content_type = best_content_type('vnd.error', accept_headers) content = doc.to_json() if 'html' in content_type: content=create_html(content) response = HttpResponse(content=content, status=exception.status) response['Content-Type'] = content_type response['Vary'] = 'Accept' return response
def process_view(self, request, view_func, view_args, view_kwargs): try: return view_func(request, *view_args, **view_kwargs) except GenusTransportError: from django.conf import settings if settings.DEBUG: raise else: if view_kwargs.get("use_xml", False): template = "social/epic_fail.xml" mimetype = "text/xml" else: template = "social/epic_fail.html" mimetype = "text/html" got_request_exception.send(sender=self, request=request) return direct_to_template(request, template, mimetype=mimetype)
def _handle_500(self, request, exception): ''' Override Tastypie for serialization''' import traceback import sys the_trace = '\n'.join(traceback.format_exception(*(sys.exc_info()))) response_class = HttpApplicationError response_code = 500 NOT_FOUND_EXCEPTIONS = (NotFound, ObjectDoesNotExist, Http404) if isinstance(exception, NOT_FOUND_EXCEPTIONS): response_class = HttpResponseNotFound response_code = 404 if settings.DEBUG: data = { "error_message": sanitize(six.text_type(exception)), "traceback": the_trace, } return self.build_error_response(request, data, response_class=response_class) # When DEBUG is False, send an error message to the admins (unless it's # a 404, in which case we check the setting). send_broken_links = getattr(settings, 'SEND_BROKEN_LINK_EMAILS', False) if not response_code == 404 or send_broken_links: log = logging.getLogger('django.request.tastypie') log.error('Internal Server Error: %s' % request.path, exc_info=True, extra={'status_code': response_code, 'request': request}) # Send the signal so other apps are aware of the exception. got_request_exception.send(self.__class__, request=request) # Prep the data going out. data = { "error_message": getattr( settings, 'TASTYPIE_CANNED_ERROR', "Sorry, this request could not be processed. Please try again later."), } return self.build_error_response(request, data, response_class=response_class)
def test_signal_integration(self): try: int('hello') except: got_request_exception.send(sender=self.__class__, request=None) else: self.fail('Expected an exception.') self.assertEquals(len(self.raven.events), 1) event = self.raven.events.pop(0) assert 'exception' in event exc = event['exception']['values'][0] self.assertEquals(exc['type'], 'ValueError') self.assertEquals(exc['value'], "invalid literal for int() with base 10: 'hello'") self.assertEquals(event['level'], logging.ERROR) self.assertEquals( event['message'], "ValueError: invalid literal for int() with base 10: 'hello'") self.assertEquals(event['culprit'], 'tests.tests in test_signal_integration')
def test_signal_integration(self): with Settings(HEKA_CONF=self.HEKA_CONF, HEKA=self.HEKA, SENTRY_CLIENT=self.SENTRY_CLIENT, SENTRY_DSN=DSN): self.raven = get_client() try: int('hello') except: got_request_exception.send(sender=self.__class__, request=None) else: self.fail('Expected an exception.') msgs = [] for mdata in settings.HEKA.stream.msgs: h, m = decode_message(mdata) msgs.append(m) self.assertEquals(len(msgs), 1) event = self.raven.decode(msgs[0].payload) self.assertTrue('sentry.interfaces.Exception' in event) exc = event['sentry.interfaces.Exception'] self.assertEquals(exc['type'], 'ValueError') self.assertEquals( exc['value'], u"invalid literal for int() with base 10: 'hello'") self.assertEquals(event['level'], logging.ERROR) self.assertEquals( event['message'], u"ValueError: invalid literal for int() with base 10: 'hello'") self.assertEquals( event['culprit'], 'tests.contrib.django.tests in test_signal_integration') # The project_id must be extracted from the SENTRY_DSN # option self.assertEquals(event['project'], str(TESTING_PROJECT_ID))
def test_signal_integration(self): try: int('hello') except: got_request_exception.send(sender=self.__class__, request=None) else: self.fail('Expected an exception.') events = [self.raven.decode(json.loads(msg)['payload']) for msg in settings.METLOG.sender.msgs] eq_(len(events), 1) event = events.pop(0) self.assertTrue('sentry.interfaces.Exception' in event) exc = event['sentry.interfaces.Exception'] eq_(exc['type'], 'ValueError') eq_(exc['value'], u"invalid literal for int() with base 10: 'hello'") eq_(event['level'], logging.ERROR) eq_(event['message'], u"ValueError: invalid literal for int() with base 10: 'hello'") eq_(event['culprit'], 'solitude.tests.test_metlog.test_signal_integration')
def _wrapped(request, *a, **kw): try: status = 200 headers = {} ret = f(request, *a, **kw) if isinstance(ret, tuple): if len(ret) == 3: ret, status, headers = ret else: ret, status = ret # Some errors are not exceptions. :\ if isinstance(ret, http.HttpResponseNotAllowed): blob = _dump_json({ 'error': 405, 'message': 'HTTP method not allowed.' }) return http.HttpResponse(blob, status=405, content_type=JSON) # Allow HttpResponses to go straight through. if isinstance(ret, http.HttpResponse): return ret blob = _dump_json(ret) response = http.HttpResponse(blob, status=status, content_type=content_type) for k in headers: response[k] = headers[k] return response except http.Http404 as e: blob = _dump_json({ 'error': 404, 'message': six.text_type(e), }) logger.warning('Not found: %s', request.path, extra={ 'status_code': 404, 'request': request, }) return http.HttpResponseNotFound(blob, content_type=JSON) except PermissionDenied as e: logger.warning('Forbidden (Permission denied): %s', request.path, extra={ 'status_code': 403, 'request': request, }) blob = _dump_json({ 'error': 403, 'message': six.text_type(e), }) return http.HttpResponseForbidden(blob, content_type=JSON) except BadRequest as e: blob = _dump_json({ 'error': 400, 'message': six.text_type(e), }) return http.HttpResponseBadRequest(blob, content_type=JSON) except Exception as e: exc_data = { 'error': 500, 'message': 'An error occurred', } if settings.DEBUG: exc_data['message'] = six.text_type(e) exc_data['traceback'] = traceback.format_exc() blob = _dump_json(exc_data) # Generate the usual 500 error email with stack trace and full # debugging information logger.error('Internal Server Error: %s', request.path, exc_info=True, extra={ 'status_code': 500, 'request': request }) # Here we lie a little bit. Because we swallow the exception, # the BaseHandler doesn't get to send this signal. It sets the # sender argument to self.__class__, in case the BaseHandler # is subclassed. got_request_exception.send(sender=BaseHandler, request=request, exception=e, exc_data=exc_data) return http.HttpResponseServerError(blob, content_type=JSON)
def testSignalsWithoutRequest(self): try: Message.objects.get(id=999999999) except Message.DoesNotExist, exc: got_request_exception.send(sender=self.__class__, request=None)
def _wrapped(request, *a, **kw): try: status = 200 headers = {} ret = f(request, *a, **kw) if isinstance(ret, tuple): if len(ret) == 3: ret, status, headers = ret else: ret, status = ret # Some errors are not exceptions. :\ if isinstance(ret, http.HttpResponseNotAllowed): blob = _dump_json({ 'error': 405, 'message': 'HTTP method not allowed.' }) return http.HttpResponse( blob, status=405, content_type=JSON) # Allow HttpResponses to go straight through. if isinstance(ret, http.HttpResponse): return ret blob = _dump_json(ret) response = http.HttpResponse(blob, status=status, content_type=content_type) for k in headers: response[k] = headers[k] return response except http.Http404 as e: blob = _dump_json({ 'error': 404, 'message': unicode(e), }) logger.warning('Not found: %s', request.path, extra={ 'status_code': 404, 'request': request, }) return http.HttpResponseNotFound(blob, content_type=JSON) except PermissionDenied as e: logger.warning( 'Forbidden (Permission denied): %s', request.path, extra={ 'status_code': 403, 'request': request, }) blob = _dump_json({ 'error': 403, 'message': unicode(e), }) return http.HttpResponseForbidden(blob, content_type=JSON) except BadRequest as e: blob = _dump_json({ 'error': 400, 'message': unicode(e), }) return http.HttpResponseBadRequest(blob, content_type=JSON) except Exception as e: if settings.DEBUG: exc_text = unicode(e) else: exc_text = 'An error occurred' blob = _dump_json({ 'error': 500, 'message': exc_text, }) # Generate the usual 500 error email with stack trace and full # debugging information logger.error('Internal Server Error: %s', request.path, exc_info=True, extra={ 'status_code': 500, 'request': request } ) # Here we lie a little bit. Because we swallow the exception, # the BaseHandler doesn't get to send this signal. It sets the # sender argument to self.__class__, in case the BaseHandler # is subclassed. got_request_exception.send(sender=BaseHandler, request=request) return http.HttpResponseServerError(blob, content_type=JSON)
def process_exception(self, request, exception): got_request_exception.send(sender=self, request=request) exc_info = sys.exc_info() self.log_exception(request, exception, exc_info) return HttpResponseServerError(json.dumps({"code": 1000}), content_type='application/json')
def _wrapped(request, *args, **kwargs): try: ret = f(request, *args, **kwargs) # Some errors are not exceptions if isinstance(ret, http.HttpResponseNotAllowed): return http.HttpResponse(json_dumps( _make_error(_('HTTP method not allowed.'))), status=405, content_type=JSON) if isinstance(ret, http.HttpResponseBadRequest): return http.HttpResponse(json_dumps( _make_error(_('Bad Request'))), status=400, content_type=JSON) # Allow other HttpResponses through if isinstance(ret, http.HttpResponse): return ret # Functions without return values default to a dict which just contains {success: true} if ret is None: ret = {} if include_success and 'success' not in ret: ret['success'] = True content = json_dumps(ret) return http.HttpResponse(content, status=200, content_type=JSON) except http.Http404 as e: logger.warning('Not found: %s', request.path, extra={ 'status_code': 404, 'request': request, }) return http.HttpResponseNotFound(json_dumps(_make_error( str(e))), content_type=JSON) except PermissionDenied as e: logger.warning('Forbidden (Permission denied): %s', request.path, extra={ 'status_code': 403, 'request': request, }) return http.HttpResponseForbidden(json_dumps( _make_error(str(e))), content_type=JSON) except BadRequest as e: return http.HttpResponseBadRequest(json_dumps( _make_error(str(e))), content_type=JSON) except ValidationError as e: # Validation errors are raised for errors such as invalid file names. # We return HTTP 400s in these cases, and send back a comma separated string of errors. # (although generally there will only be one error) return http.HttpResponseBadRequest(json_dumps( _make_error(", ".join(e.messages))), content_type=JSON) except Exception as e: data = _make_error(_('An error has occurred')) if settings.DEBUG or isinstance(e, InternalServerError): data['error'] = str(e) if settings.DEBUG: data['traceback'] = traceback.format_exc() content = json_dumps(data) # Generate the usual 500 error email with stack trace and full # debugging information logger.error('Internal Server Error: %s', request.path, exc_info=True, extra={ 'status_code': 500, 'request': request }) # Here we lie a little bit. Because we swallow the exception, # the BaseHandler doesn't get to send this signal. It sets the # sender argument to self.__class__, in case the BaseHandler # is subclassed. got_request_exception.send(sender=BaseHandler, request=request) return http.HttpResponseServerError(content, content_type=JSON)
def _wrapped(request, *args, **kwargs): try: ret = f(request, *args, **kwargs) # Some errors are not exceptions if isinstance(ret, http.HttpResponseNotAllowed): return http.HttpResponse(json_dumps(_make_error(_('HTTP method not allowed.'))), status=405, content_type=JSON) if isinstance(ret, http.HttpResponseBadRequest): return http.HttpResponse(json_dumps(_make_error(_('Bad Request'))), status=400, content_type=JSON) # Allow other HttpResponses through if isinstance(ret, http.HttpResponse): return ret # Functions without return values default to a dict which just contains {success: true} if ret is None: ret = {} if include_success and 'success' not in ret: ret['success'] = True content = json_dumps(ret) return http.HttpResponse(content, status=200, content_type=JSON) except http.Http404 as e: logger.warning('Not found: %s', request.path, extra={ 'status_code': 404, 'request': request, }) return http.HttpResponseNotFound(json_dumps(_make_error(str(e))), content_type=JSON) except PermissionDenied as e: logger.warning( 'Forbidden (Permission denied): %s', request.path, extra={ 'status_code': 403, 'request': request, }) return http.HttpResponseForbidden(json_dumps(_make_error(str(e))), content_type=JSON) except BadRequest as e: return http.HttpResponseBadRequest(json_dumps(_make_error(str(e))), content_type=JSON) except ValidationError as e: # Validation errors are raised for errors such as invalid file names. # We return HTTP 400s in these cases, and send back a comma separated string of errors. # (although generally there will only be one error) return http.HttpResponseBadRequest(json_dumps(_make_error(", ".join(e.messages))), content_type=JSON) except Exception as e: data = _make_error(_('An error has occurred')) if settings.DEBUG or isinstance(e, InternalServerError): data['error'] = str(e) if settings.DEBUG: data['traceback'] = traceback.format_exc() content = json_dumps(data) # Generate the usual 500 error email with stack trace and full # debugging information logger.error( 'Internal Server Error: %s', request.path, exc_info=True, extra={ 'status_code': 500, 'request': request } ) # Here we lie a little bit. Because we swallow the exception, # the BaseHandler doesn't get to send this signal. It sets the # sender argument to self.__class__, in case the BaseHandler # is subclassed. got_request_exception.send(sender=BaseHandler, request=request) return http.HttpResponseServerError(content, content_type=JSON)
def dispatch(self, request, *args, **kwargs): try: return super().dispatch(request, *args, **kwargs) except Exception as e: got_request_exception.send(sender=self, request=request) return self.respond({"error": str(e)}, status=500)
def custom_exception_handler(exc, context=None): """ Custom exception handler for DRF, which ensures every exception we throw is caught, returned as a nice DRF Response, while still going to sentry etc. This is mostly copied from DRF exception handler, with the following changes/additions: - A condition preventing set_rollback() from being called in some cases where we know there might be something to record in the database - Handling of non-API exceptions, returning an 500 error that looks like an API response, while still logging things to Sentry. """ # If propagate is true, bail early. if settings.DEBUG_PROPAGATE_EXCEPTIONS: raise if isinstance(exc, Http404): exc = exceptions.NotFound() elif isinstance(exc, PermissionDenied): exc = exceptions.PermissionDenied() if isinstance(exc, exceptions.APIException): headers = {} if getattr(exc, 'auth_header', None): headers['WWW-Authenticate'] = exc.auth_header if getattr(exc, 'wait', None): headers['Retry-After'] = '%d' % exc.wait if isinstance(exc.detail, (list, dict)): data = exc.detail code_or_codes = exc.get_codes() else: data = {'detail': exc.detail} code_or_codes = exc.get_codes() # If it's not a throttled/permission denied coming from a restriction, # we can roll the current transaction back. Otherwise don't, we may # need to record something in the database. # Note: `code_or_codes` can be a string, or a list of strings, or even # a dict of strings here, depending on what happened. Fortunately the # only thing we care about is the most basic case, a string, we don't # need to test for the rest. if not isinstance(exc, exceptions.Throttled) and not ( isinstance(exc, exceptions.PermissionDenied) and code_or_codes == 'permission_denied_restriction'): set_rollback() if isinstance(exc, UnavailableForLegalReasons): url = 'https://www.mozilla.org/about/policy/transparency/' headers['Link'] = f'<{url}>; rel="blocked-by"' return Response(data, status=exc.status_code, headers=headers) else: # Not a DRF exception, we want to return an APIfied 500 error while # still logging it to Sentry. data = base_500_data() # Send the got_request_exception signal so other apps like sentry # are aware of the exception. The sender does not match what a real # exception would do (we don't have access to the handler here) but it # should not be an issue, what matters is the request. request = context.get('request') sender = context.get('view').__class__ got_request_exception.send(sender, request=request) # Send the 500 response back. response = Response(data, status=status.HTTP_500_INTERNAL_SERVER_ERROR) return response
def process_exception(self, request, exception): if isinstance(exception, RecordModifiedError): got_request_exception.send(sender=self, request=request) callback = get_callable(handler409) return callback(request, target=exception.target)
def _wrapped(request, *a, **kw): try: status = 200 headers = {} ret = f(request, *a, **kw) if isinstance(ret, tuple): if len(ret) == 3: ret, status, headers = ret else: ret, status = ret if isinstance(ret, http.HttpResponseNotAllowed): blob = _dump_json({ 'error': 405, 'message': 'HTTP method not allowed.' }) return http.HttpResponse(blob, status=405, content_type=JSON) if isinstance(ret, http.HttpResponse): return ret blob = _dump_json(ret) response = http.HttpResponse(blob, status=status, content_type=content_type) for k in headers: response[k] = headers[k] return response except http.Http404 as e: blob = _dump_json({ 'error': 404, 'message': str(e), }) logger.warning('Not found: %s', request.path, extra={ 'status_code': 404, 'request': request, }) return http.HttpResponseNotFound(blob, content_type=JSON) except BadRequest as e: blob = _dump_json({ 'error': 400, 'message': str(e), }) return http.HttpResponseBadRequest(blob, content_type=JSON) except Exception as e: exc_data = { 'error': 500, 'message': 'An error occurred', } if settings.DEBUG: exc_data['message'] = str(e) exc_data['traceback'] = traceback_prettify( traceback.format_exc())[8:] blob = _dump_json(exc_data) logger.error('Internal Server Error: %s', request.path, exc_info=True, extra={ 'status_code': 500, 'request': request }) got_request_exception.send(sender=BaseHandler, request=request, exception=e, exc_data=exc_data) return http.HttpResponseServerError(blob, content_type=JSON)
def error_handler(self, e, request, meth): """ Override this method to add handling of errors customized for your needs """ debug_msg = None if request.REQUEST.get('debug') or settings.DEBUG: if isinstance(e, api_errors.APIException) and e.debug: debug_msg = e.debug else: exc_type, exc_value, tb = sys.exc_info() debug_msg = '%s\n' % ''.join(traceback.format_exception(exc_type, exc_value, tb, 20)) print debug_msg if isinstance(e, TypeError): result = rc.ALL_OK hm = HandlerMethod(meth) sig = hm.signature msg = 'Method signature does not match.\n\n' if sig: msg += 'Signature should be: %s' % sig else: msg += 'Resource does not expect any parameters.' if self.display_errors: msg += '\n\nException was: %s' % str(e) error_dict = { 'code': api_errors.ERROR_GENERAL_BAD_SIGNATURE, 'message': msg } if request.REQUEST.get('debug') or settings.DEBUG: error_dict['debug'] = debug_msg result.content = { 'success': False, 'error': error_dict } return result elif isinstance(e, Http404): return make_error_response(api_errors.ERROR_GENERAL_NOT_FOUND) elif isinstance(e, api_errors.APIException): return make_error_response(e.code, debug_msg) elif isinstance(e, User.DoesNotExist): return make_error_response(api_errors.ERROR_GENERAL_USER_NOT_FOUND, debug_msg) elif isinstance(e, InvalidId): return make_error_response(api_errors.ERROR_GENERAL_BAD_ID_FORMAT, debug_msg) elif isinstance(e, ObjectDoesNotExist): return make_error_response(api_errors.ERROR_GENERAL_TARGET_NOT_FOUND, debug_msg) else: """ On errors (like code errors), we'd like to be able to give crash reports to both admins and also the calling user. There's two setting parameters for this: Parameters:: - `PISTON_EMAIL_ERRORS`: Will send a Django formatted error email to people in `settings.ADMINS`. - `PISTON_DISPLAY_ERRORS`: Will return a simple traceback to the caller, so he can tell you what error they got. If `PISTON_DISPLAY_ERRORS` is not enabled, the caller will receive a basic "500 Internal Server Error" message. """ # report the error to django got_request_exception.send(sender=self, request=request) exc_type, exc_value, tb = sys.exc_info() rep = ExceptionReporter(request, exc_type, exc_value, tb.tb_next) if self.email_errors: self.email_exception(rep) if self.display_errors: return make_error_response(api_errors.ERROR_GENERAL_UNKNOWN_ERROR, debug_msg) # return HttpResponseServerError( # format_error('\n'.join(rep.format_exception()))) else: return make_error_response(api_errors.ERROR_GENERAL_UNKNOWN_ERROR)
def process_exception(self, request, exception): # Make sure the exception signal is fired for Sentry got_request_exception.send(sender=self, request=request) return HttpResponse('foo')
def _wrapped(request, *a, **kw): try: status = 200 headers = {} ret = f(request, *a, **kw) if isinstance(ret, tuple): if len(ret) == 3: ret, status, headers = ret else: ret, status = ret # Some errors are not exceptions. :\ if isinstance(ret, http.HttpResponseNotAllowed): blob = json.dumps({ 'error': 405, 'message': 'HTTP method not allowed.' }) return http.HttpResponse(blob, status=405, content_type=JSON) if isinstance(ret, (str, unicode)): blob = ret else: blob = json.dumps(ret) response = http.HttpResponse(blob, status=status, content_type=JSON) for k in headers: response[k] = headers[k] return response except http.Http404 as e: blob = json.dumps({ 'error': 404, 'message': unicode(e), }) logger.warning('Not found: %s', request.path, extra={ 'status_code': 404, 'request': request, }) return http.HttpResponseNotFound(blob, content_type=JSON) except PermissionDenied as e: logger.warning('Forbidden (Permission denied): %s', request.path, extra={ 'status_code': 403, 'request': request, }) blob = json.dumps({ 'error': 403, 'message': unicode(e), }) return http.HttpResponseForbidden(blob, content_type=JSON) except BadRequest as e: blob = json.dumps({ 'error': 400, 'message': unicode(e), }) return http.HttpResponseBadRequest(blob, content_type=JSON) except Exception as e: blob = json.dumps({ 'error': 500, 'message': unicode(e), }) logger.exception(unicode(e)) # Here we lie a little bit. Because we swallow the exception, the # BaseHandler doesn't get to send this signal. It sets the sender # argument to self.__class__, in case the BaseHandler is # subclassed. got_request_exception.send(sender=BaseHandler, request=request) return http.HttpResponseServerError(blob, content_type=JSON)