Merge pull request #3679 from cisagov/rjm/3602-router-logs

#3602: Middleware router logs
This commit is contained in:
Rachid Mrad 2025-03-25 13:36:33 -04:00 committed by GitHub
commit 7a9a274bea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 78 additions and 0 deletions

View file

@ -203,6 +203,8 @@ MIDDLEWARE = [
"registrar.registrar_middleware.CheckPortfolioMiddleware",
# Restrict access using Opt-Out approach
"registrar.registrar_middleware.RestrictAccessMiddleware",
# Our own router logs that included user info to speed up log tracing time on stable
"registrar.registrar_middleware.RequestLoggingMiddleware",
]
# application object used by Django's built-in servers (e.g. `runserver`)

View file

@ -222,3 +222,31 @@ class RestrictAccessMiddleware:
raise PermissionDenied # Deny access if the view lacks explicit permission handling
return self.get_response(request)
class RequestLoggingMiddleware:
"""
Middleware to log user email, remote address, and request path.
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
# Only log in production (stable)
if getattr(settings, "IS_PRODUCTION", False):
# Get user email (if authenticated), else "Anonymous"
user_email = request.user.email if request.user.is_authenticated else "Anonymous"
# Get remote IP address
remote_ip = request.META.get("REMOTE_ADDR", "Unknown IP")
# Get request path
request_path = request.path
# Log user information
logger.info(f"Router log | User: {user_email} | IP: {remote_ip} | Path: {request_path}")
return response

View file

@ -0,0 +1,48 @@
from django.test import TestCase, RequestFactory, override_settings
from unittest.mock import patch, MagicMock
from django.contrib.auth.models import AnonymousUser, User
from registrar.registrar_middleware import RequestLoggingMiddleware
class RequestLoggingMiddlewareTest(TestCase):
"""Test 'our' middleware logging."""
def setUp(self):
self.factory = RequestFactory()
self.get_response_mock = MagicMock()
self.middleware = RequestLoggingMiddleware(self.get_response_mock)
@override_settings(IS_PRODUCTION=True) # Scopes change to this test only
@patch("logging.Logger.info")
def test_logging_enabled_in_production(self, mock_logger):
"""Test that logging occurs when IS_PRODUCTION is True"""
request = self.factory.get("/test-path", **{"REMOTE_ADDR": "Unknown IP"}) # Override IP
request.user = User(username="testuser", email="testuser@example.com")
self.middleware(request) # Call middleware
mock_logger.assert_called_once_with(
"Router log | User: testuser@example.com | IP: Unknown IP | Path: /test-path"
)
@patch("logging.Logger.info")
def test_logging_disabled_in_non_production(self, mock_logger):
"""Test that logging does not occur when IS_PRODUCTION is False"""
request = self.factory.get("/test-path")
request.user = User(username="testuser", email="testuser@example.com")
self.middleware(request) # Call middleware
mock_logger.assert_not_called() # Ensure no logs are generated
@override_settings(IS_PRODUCTION=True) # Scopes change to this test only
@patch("logging.Logger.info")
def test_logging_anonymous_user(self, mock_logger):
"""Test logging for an anonymous user"""
request = self.factory.get("/anonymous-path", **{"REMOTE_ADDR": "Unknown IP"}) # Override IP
request.user = AnonymousUser() # Simulate an anonymous user
self.middleware(request) # Call middleware
mock_logger.assert_called_once_with("Router log | User: Anonymous | IP: Unknown IP | Path: /anonymous-path")