diff --git a/rest_framework_tracking/migrations/0003_add_errors.py b/rest_framework_tracking/migrations/0003_add_errors.py new file mode 100644 index 0000000..4a8a3fa --- /dev/null +++ b/rest_framework_tracking/migrations/0003_add_errors.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("rest_framework_tracking", "0002_auto_20170118_1713"), + ] + + operations = [ + migrations.AddField( + 'APIRequestLog', + 'errors', + models.TextField(null=True, blank=True), + ), + ] diff --git a/rest_framework_tracking/mixins.py b/rest_framework_tracking/mixins.py index b4b2214..7e4c34c 100644 --- a/rest_framework_tracking/mixins.py +++ b/rest_framework_tracking/mixins.py @@ -1,5 +1,6 @@ from .models import APIRequestLog from django.utils.timezone import now +import traceback class LoggingMixin(object): @@ -71,6 +72,18 @@ def initial(self, request, *args, **kwargs): finally: self.request.log.save() + def handle_exception(self, exc): + # basic handling + response = super(LoggingMixin, self).handle_exception(exc) + + # log error + self.request.log.errors = traceback.format_exc() + self.request.log.status_code = response.status_code + self.request.log.save() + + # return + return response + def finalize_response(self, request, response, *args, **kwargs): # regular finalize response response = super(LoggingMixin, self).finalize_response(request, response, *args, **kwargs) diff --git a/rest_framework_tracking/models.py b/rest_framework_tracking/models.py index fc23ae3..75f0d4b 100644 --- a/rest_framework_tracking/models.py +++ b/rest_framework_tracking/models.py @@ -41,6 +41,9 @@ class BaseAPIRequestLog(models.Model): # response response = models.TextField(null=True, blank=True) + # error traceback + errors = models.TextField(null=True, blank=True) + # status code status_code = models.PositiveIntegerField(null=True, blank=True) diff --git a/tests/test_mixins.py b/tests/test_mixins.py index 4fde812..caa8912 100644 --- a/tests/test_mixins.py +++ b/tests/test_mixins.py @@ -178,6 +178,14 @@ def test_log_request_404_error(self): log = APIRequestLog.objects.first() self.assertEqual(log.status_code, 404) self.assertIn('Not found', log.response) + self.assertIn('Traceback', log.errors) + + def test_log_request_500_error(self): + self.client.get('/500-error-logging') + log = APIRequestLog.objects.first() + self.assertEqual(log.status_code, 500) + self.assertIn('response', log.response) + self.assertIn('Traceback', log.errors) def test_log_request_415_error(self): content_type = 'text/plain' diff --git a/tests/test_models.py b/tests/test_models.py index 102e30d..30e45d8 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -76,6 +76,11 @@ def test_status_code(self): status_code=200) self.assertEqual(log.status_code, 200) + def test_errors(self): + log = APIRequestLog.objects.create(remote_addr=self.ip, requested_at=now(), + errors='dummy') + self.assertEqual(log.errors, 'dummy') + def test_queries_anon(self): for i in range(100): APIRequestLog.objects.create(remote_addr=self.ip, requested_at=now()) diff --git a/tests/urls.py b/tests/urls.py index 37acadd..06679c0 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -15,6 +15,7 @@ url(r'^json-logging$', test_views.MockJSONLoggingView.as_view()), url(r'^validation-error-logging$', test_views.MockValidationErrorLoggingView.as_view()), url(r'^404-error-logging$', test_views.Mock404ErrorLoggingView.as_view()), + url(r'^500-error-logging$', test_views.Mock500ErrorLoggingView.as_view()), url(r'^415-error-logging$', test_views.Mock415ErrorLoggingView.as_view()), url(r'^no-view-log$', test_views.MockNameAPIView.as_view()), url(r'^view-log$', test_views.MockNameViewSet.as_view({'get': 'list'})), diff --git a/tests/views.py b/tests/views.py index f0ff655..dd7a165 100644 --- a/tests/views.py +++ b/tests/views.py @@ -4,6 +4,7 @@ from rest_framework.response import Response from rest_framework.views import APIView from rest_framework import serializers, viewsets, mixins +from rest_framework.exceptions import APIException from rest_framework_tracking.mixins import LoggingMixin from rest_framework_tracking.models import APIRequestLog from tests.test_serializers import ApiRequestLogSerializer @@ -71,6 +72,11 @@ def get(self, request): return get_list_or_404(empty_qs) +class Mock500ErrorLoggingView(LoggingMixin, APIView): + def get(self, request): + raise APIException('response') + + class Mock415ErrorLoggingView(LoggingMixin, APIView): def post(self, request): return request.data