import logging from functools import partial from typing import List, Optional from django.conf import settings from django.http import HttpRequest, HttpResponse from owslib.dictutil import exclude from owslib.ext.django.typing import GetResponseCallable from owslib.logger.utils import get_status_code_log_level from owslib.urlpath import is_path_match EXCLUDE_PATHS: Optional[List[str]] = getattr( settings, "REQUEST_LOGGER_EXCLUDE_PATHS", None ) EXTRA_HEADERS: Optional[bool] = getattr(settings, "REQUEST_LOGGER_EXTRA_HEADERS", False) logger = logging.getLogger(__name__) safe_headers = partial(exclude, keys=["authorization"]) class RequestLoggerMiddleware: LOG_MESSAGE = "{status} - {verb} {resource}" def __init__(self, get_response: GetResponseCallable) -> None: self.get_response = get_response self.exclude_paths = EXCLUDE_PATHS self.extra_headers = EXTRA_HEADERS def __call__(self, request: HttpRequest) -> HttpResponse: if is_path_match(request.path, match=self.exclude_paths): return self.get_response(request) try: response = self.get_response(request) except Exception as exc: self.log_request(request, status_code=500) raise exc self.log_request(request, status_code=response.status_code, response=response) return response def log_request( self, request: HttpRequest, status_code: int, response: Optional[HttpResponse] = None, ) -> None: level = get_status_code_log_level(status_code) extra = {} if self.extra_headers: extra.update({"request.headers": safe_headers(dict(request.headers))}) if response: extra.update({"response.headers": safe_headers(dict(response.headers))}) logger.log( level, self.LOG_MESSAGE.format( status=status_code, verb=request.method, resource=request.path, ), extra=extra, )