mirror of
https://github.com/django/django.git
synced 2025-08-03 10:34:04 +00:00
Fixed #26688 -- Fixed HTTP request logging inconsistencies.
* Added logging of 500 responses for instantiated responses. * Added logging of all 4xx and 5xx responses.
This commit is contained in:
parent
2e1f674897
commit
10b44e4525
10 changed files with 226 additions and 57 deletions
|
@ -6,15 +6,18 @@ from admin_scripts.tests import AdminScriptTestCase
|
|||
|
||||
from django.conf import settings
|
||||
from django.core import mail
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.core.files.temp import NamedTemporaryFile
|
||||
from django.core.management import color
|
||||
from django.http.multipartparser import MultiPartParserError
|
||||
from django.test import RequestFactory, SimpleTestCase, override_settings
|
||||
from django.test.utils import LoggingCaptureMixin, patch_logger
|
||||
from django.test.utils import LoggingCaptureMixin
|
||||
from django.utils.log import (
|
||||
DEFAULT_LOGGING, AdminEmailHandler, CallbackFilter, RequireDebugFalse,
|
||||
RequireDebugTrue, ServerFormatter,
|
||||
)
|
||||
|
||||
from . import views
|
||||
from .logconfig import MyEmailBackend
|
||||
|
||||
# logging config prior to using filter with mail_admins
|
||||
|
@ -106,16 +109,95 @@ class DefaultLoggingTests(SetupDefaultLoggingMixin, LoggingCaptureMixin, SimpleT
|
|||
self.assertEqual(self.logger_output.getvalue(), '')
|
||||
|
||||
|
||||
class LoggingAssertionMixin(object):
|
||||
|
||||
def assertLogsRequest(self, url, level, msg, status_code, logger='django.request', exc_class=None):
|
||||
with self.assertLogs(logger, level) as cm:
|
||||
try:
|
||||
self.client.get(url)
|
||||
except views.UncaughtException:
|
||||
pass
|
||||
self.assertEqual(
|
||||
len(cm.records), 1,
|
||||
"Wrong number of calls for logger %r in %r level." % (logger, level)
|
||||
)
|
||||
record = cm.records[0]
|
||||
self.assertEqual(record.getMessage(), msg)
|
||||
self.assertEqual(record.status_code, status_code)
|
||||
if exc_class:
|
||||
self.assertIsNotNone(record.exc_info)
|
||||
self.assertEqual(record.exc_info[0], exc_class)
|
||||
|
||||
|
||||
@override_settings(DEBUG=True, ROOT_URLCONF='logging_tests.urls')
|
||||
class HandlerLoggingTests(SetupDefaultLoggingMixin, LoggingCaptureMixin, SimpleTestCase):
|
||||
class HandlerLoggingTests(SetupDefaultLoggingMixin, LoggingAssertionMixin, LoggingCaptureMixin, SimpleTestCase):
|
||||
|
||||
def test_page_found_no_warning(self):
|
||||
self.client.get('/innocent/')
|
||||
self.assertEqual(self.logger_output.getvalue(), '')
|
||||
|
||||
def test_redirect_no_warning(self):
|
||||
self.client.get('/redirect/')
|
||||
self.assertEqual(self.logger_output.getvalue(), '')
|
||||
|
||||
def test_page_not_found_warning(self):
|
||||
self.client.get('/does_not_exist/')
|
||||
self.assertEqual(self.logger_output.getvalue(), 'Not Found: /does_not_exist/\n')
|
||||
self.assertLogsRequest(
|
||||
url='/does_not_exist/',
|
||||
level='WARNING',
|
||||
status_code=404,
|
||||
msg='Not Found: /does_not_exist/',
|
||||
)
|
||||
|
||||
def test_page_not_found_raised(self):
|
||||
self.assertLogsRequest(
|
||||
url='/does_not_exist_raised/',
|
||||
level='WARNING',
|
||||
status_code=404,
|
||||
msg='Not Found: /does_not_exist_raised/',
|
||||
)
|
||||
|
||||
def test_uncaught_exception(self):
|
||||
self.assertLogsRequest(
|
||||
url='/uncaught_exception/',
|
||||
level='ERROR',
|
||||
status_code=500,
|
||||
msg='Internal Server Error: /uncaught_exception/',
|
||||
exc_class=views.UncaughtException,
|
||||
)
|
||||
|
||||
def test_internal_server_error(self):
|
||||
self.assertLogsRequest(
|
||||
url='/internal_server_error/',
|
||||
level='ERROR',
|
||||
status_code=500,
|
||||
msg='Internal Server Error: /internal_server_error/',
|
||||
)
|
||||
|
||||
def test_internal_server_error_599(self):
|
||||
self.assertLogsRequest(
|
||||
url='/internal_server_error/?status=599',
|
||||
level='ERROR',
|
||||
status_code=599,
|
||||
msg='Unknown Status Code: /internal_server_error/',
|
||||
)
|
||||
|
||||
def test_permission_denied(self):
|
||||
self.assertLogsRequest(
|
||||
url='/permission_denied/',
|
||||
level='WARNING',
|
||||
status_code=403,
|
||||
msg='Forbidden (Permission denied): /permission_denied/',
|
||||
exc_class=PermissionDenied,
|
||||
)
|
||||
|
||||
def test_multi_part_parser_error(self):
|
||||
self.assertLogsRequest(
|
||||
url='/multi_part_parser_error/',
|
||||
level='WARNING',
|
||||
status_code=400,
|
||||
msg='Bad request (Unable to parse request body): /multi_part_parser_error/',
|
||||
exc_class=MultiPartParserError,
|
||||
)
|
||||
|
||||
|
||||
@override_settings(
|
||||
|
@ -401,19 +483,25 @@ class SetupConfigureLogging(SimpleTestCase):
|
|||
|
||||
|
||||
@override_settings(DEBUG=True, ROOT_URLCONF='logging_tests.urls')
|
||||
class SecurityLoggerTest(SimpleTestCase):
|
||||
class SecurityLoggerTest(LoggingAssertionMixin, SimpleTestCase):
|
||||
|
||||
def test_suspicious_operation_creates_log_message(self):
|
||||
with patch_logger('django.security.SuspiciousOperation', 'error') as calls:
|
||||
self.client.get('/suspicious/')
|
||||
self.assertEqual(len(calls), 1)
|
||||
self.assertEqual(calls[0], 'dubious')
|
||||
self.assertLogsRequest(
|
||||
url='/suspicious/',
|
||||
level='ERROR',
|
||||
msg='dubious',
|
||||
status_code=400,
|
||||
logger='django.security.SuspiciousOperation',
|
||||
)
|
||||
|
||||
def test_suspicious_operation_uses_sublogger(self):
|
||||
with patch_logger('django.security.DisallowedHost', 'error') as calls:
|
||||
self.client.get('/suspicious_spec/')
|
||||
self.assertEqual(len(calls), 1)
|
||||
self.assertEqual(calls[0], 'dubious')
|
||||
self.assertLogsRequest(
|
||||
url='/suspicious_spec/',
|
||||
level='ERROR',
|
||||
msg='dubious',
|
||||
status_code=400,
|
||||
logger='django.security.DisallowedHost',
|
||||
)
|
||||
|
||||
@override_settings(
|
||||
ADMINS=[('admin', 'admin@example.com')],
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
from django.conf.urls import url
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^innocent/$', views.innocent),
|
||||
path('redirect/', views.redirect),
|
||||
url(r'^suspicious/$', views.suspicious),
|
||||
url(r'^suspicious_spec/$', views.suspicious_spec),
|
||||
path('internal_server_error/', views.internal_server_error),
|
||||
path('uncaught_exception/', views.uncaught_exception),
|
||||
path('permission_denied/', views.permission_denied),
|
||||
path('multi_part_parser_error/', views.multi_part_parser_error),
|
||||
path('does_not_exist_raised/', views.does_not_exist_raised),
|
||||
]
|
||||
|
|
|
@ -1,14 +1,48 @@
|
|||
from django.core.exceptions import DisallowedHost, SuspiciousOperation
|
||||
from django.http import HttpResponse
|
||||
from django.core.exceptions import (
|
||||
DisallowedHost, PermissionDenied, SuspiciousOperation,
|
||||
)
|
||||
from django.http import (
|
||||
Http404, HttpResponse, HttpResponseRedirect, HttpResponseServerError,
|
||||
)
|
||||
from django.http.multipartparser import MultiPartParserError
|
||||
|
||||
|
||||
def innocent(request):
|
||||
return HttpResponse('innocent')
|
||||
|
||||
|
||||
def redirect(request):
|
||||
return HttpResponseRedirect('/')
|
||||
|
||||
|
||||
def suspicious(request):
|
||||
raise SuspiciousOperation('dubious')
|
||||
|
||||
|
||||
def suspicious_spec(request):
|
||||
raise DisallowedHost('dubious')
|
||||
|
||||
|
||||
class UncaughtException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def uncaught_exception(request):
|
||||
raise UncaughtException('Uncaught exception')
|
||||
|
||||
|
||||
def internal_server_error(request):
|
||||
status = request.GET.get('status', 500)
|
||||
return HttpResponseServerError('Server Error', status=int(status))
|
||||
|
||||
|
||||
def permission_denied(request):
|
||||
raise PermissionDenied()
|
||||
|
||||
|
||||
def multi_part_parser_error(request):
|
||||
raise MultiPartParserError('parsing error')
|
||||
|
||||
|
||||
def does_not_exist_raised(request):
|
||||
raise Http404('Not Found')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue