Skip to content
Open
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ A `no_logging` decorator is included for views with sensitive data.
By default, value of Http headers `HTTP_AUTHORIZATION` and `HTTP_PROXY_AUTHORIZATION` are replaced wih `*****`. You can use `REQUEST_LOGGING_SENSITIVE_HEADERS` setting to override this default behaviour with your list of sensitive headers.

## Django settings
You can customized some behaves of django-request-logging by following settings in Django `settings.py`.
You can customize some behaviours of django-request-logging by following settings in Django `settings.py`.
### REQUEST_LOGGING_DATA_LOG_LEVEL
By default, data will log in DEBUG level, you can change to other valid level (Ex. logging.INFO) if need.
### REQUEST_LOGGING_ENABLE_COLORIZE
Expand All @@ -72,6 +72,10 @@ By default, max length of a request body and a response content is cut to 50000
By default, HTTP status codes between 400 - 499 are logged at ERROR level. You can set `REQUEST_LOGGING_HTTP_4XX_LOG_LEVEL=logging.WARNING` (etc) to override this.
If you set `REQUEST_LOGGING_HTTP_4XX_LOG_LEVEL=logging.INFO` they will be logged the same as normal requests.
### REQUEST_LOGGING_SENSITIVE_HEADERS
The value of the headers defined in this settings will be replaced with `'*****'` to hide the sensitive information while logging. E.g. `REQUEST_LOGGING_SENSITIVE_HEADERS = ['HTTP_AUTHORIZATION', 'HTTP_USER_AGENT']`
### REQUEST_LOGGING_SENSITIVE_VIEWS
A list of views (or view methods in case of class based views) that should not be logged. This has the same behaviour as the no_logging decorator, but can be used in case of 3rd party modules where the source cannot be modified
`REQUEST_LOGGING_SENSITIVE_VIEWS = ['dj_rest_auth.views.LoginView.post']`
The value of the headers defined in this settings will be replaced with `'*****'` to hide the sensitive information while logging. By default it is set as `REQUEST_LOGGING_SENSITIVE_HEADERS = ["HTTP_AUTHORIZATION", "HTTP_PROXY_AUTHORIZATION"]`


Expand Down
17 changes: 14 additions & 3 deletions request_logging/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@
] if IS_DJANGO_VERSION_GTE_3_2_0 else [
"HTTP_AUTHORIZATION", "HTTP_PROXY_AUTHORIZATION"
]
DEFAULT_SENSITIVE_VIEWS = []
SETTING_NAMES = {
"log_level": "REQUEST_LOGGING_DATA_LOG_LEVEL",
"http_4xx_log_level": "REQUEST_LOGGING_HTTP_4XX_LOG_LEVEL",
"legacy_colorize": "REQUEST_LOGGING_DISABLE_COLORIZE",
"colorize": "REQUEST_LOGGING_ENABLE_COLORIZE",
"max_body_length": "REQUEST_LOGGING_MAX_BODY_LENGTH",
"sensitive_headers": "REQUEST_LOGGING_SENSITIVE_HEADERS",
"sensitive_views": "REQUEST_LOGGING_SENSITIVE_VIEWS",
}
BINARY_REGEX = re.compile(r"(.+Content-Type:.*?)(\S+)/(\S+)(?:\r\n)*(.+)", re.S | re.I)
BINARY_TYPES = ("image", "application")
Expand Down Expand Up @@ -77,6 +79,7 @@ def __init__(self, get_response=None):
self.log_level = getattr(settings, SETTING_NAMES["log_level"], DEFAULT_LOG_LEVEL)
self.http_4xx_log_level = getattr(settings, SETTING_NAMES["http_4xx_log_level"], DEFAULT_HTTP_4XX_LOG_LEVEL)
self.sensitive_headers = getattr(settings, SETTING_NAMES["sensitive_headers"], DEFAULT_SENSITIVE_HEADERS)
self.sensitive_views = getattr(settings, SETTING_NAMES["sensitive_views"], DEFAULT_SENSITIVE_VIEWS)
if not isinstance(self.sensitive_headers, list):
raise ValueError(
"{} should be list. {} is not list.".format(SETTING_NAMES["sensitive_headers"], self.sensitive_headers)
Expand Down Expand Up @@ -129,6 +132,16 @@ def process_request(self, request, response=None):
else:
return self._log_request(request, response)

def _should_log_view(self, func):
full_path = '.'.join([func.__module__, func.__qualname__])
if full_path in self.sensitive_views:
no_logging = True
no_logging_msg = NO_LOGGING_MSG
else:
no_logging = getattr(func, NO_LOGGING_ATTR, False)
no_logging_msg = getattr(func, NO_LOGGING_MSG_ATTR, None)
return no_logging, no_logging_msg

def _should_log_route(self, request):
# request.urlconf may be set by middleware or application level code.
# Use this urlconf if present or default to None.
Expand Down Expand Up @@ -156,9 +169,7 @@ def _should_log_route(self, request):
elif hasattr(view, "view_class"):
# This is for django class-based views
func = getattr(view.view_class, method, None)
no_logging = getattr(func, NO_LOGGING_ATTR, False)
no_logging_msg = getattr(func, NO_LOGGING_MSG_ATTR, None)
return no_logging, no_logging_msg
return self._should_log_view(func)

def _skip_logging_request(self, request, reason):
method_path = "{} {}".format(request.method, request.get_full_path())
Expand Down