Add support for request ID headers

This commit is contained in:
Raphael Michel
2022-10-25 17:17:59 +02:00
parent 45f579caf2
commit 51768eaef9
3 changed files with 61 additions and 5 deletions

View File

@@ -117,6 +117,9 @@ Example::
``loglevel`` ``loglevel``
Set console and file log level (``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` or ``CRITICAL``). Defaults to ``INFO``. Set console and file log level (``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` or ``CRITICAL``). Defaults to ``INFO``.
``request_id_header``
Specifies the name of a header that should be used for logging request IDs. Off by default.
Locale settings Locale settings
--------------- ---------------

View File

@@ -21,9 +21,49 @@
# #
import logging import logging
import sentry_sdk
from django.core.signals import request_finished
from django.dispatch import receiver
try:
from asgiref.local import Local
except ImportError:
from threading import local as Local
from django.conf import settings from django.conf import settings
class AdminExistsFilter(logging.Filter): class AdminExistsFilter(logging.Filter):
def filter(self, record): def filter(self, record):
return not settings.DEBUG and len(settings.ADMINS) > 0 return not settings.DEBUG and len(settings.ADMINS) > 0
local = Local()
class RequestIdFilter(logging.Filter):
def filter(self, record):
record.request_id = getattr(local, 'request_id', None)
return True
class RequestIdMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if settings.REQUEST_ID_HEADER and settings.REQUEST_ID_HEADER in request.headers:
local.request_id = request.request_id = request.headers[settings.REQUEST_ID_HEADER]
if settings.SENTRY_ENABLED:
sentry_sdk.set_tag("request_id", request.request_id)
else:
local.request_id = request.request_id = None
return self.get_response(request)
@receiver(request_finished)
def on_request_finished(sender, **kwargs):
# not part of middleware, since things could be logged after the middleware stack is finished
local.request_id = None

View File

@@ -178,6 +178,8 @@ CSRF_TRUSTED_ORIGINS = [urlparse(SITE_URL).hostname]
TRUST_X_FORWARDED_FOR = config.get('pretix', 'trust_x_forwarded_for', fallback=False) TRUST_X_FORWARDED_FOR = config.get('pretix', 'trust_x_forwarded_for', fallback=False)
REQUEST_ID_HEADER = config.get('pretix', 'request_id_header', fallback=False)
if config.get('pretix', 'trust_x_forwarded_proto', fallback=False): if config.get('pretix', 'trust_x_forwarded_proto', fallback=False):
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
@@ -439,6 +441,7 @@ CORE_MODULES = {
} }
MIDDLEWARE = [ MIDDLEWARE = [
'pretix.helpers.logs.RequestIdMiddleware',
'pretix.api.middleware.IdempotencyMiddleware', 'pretix.api.middleware.IdempotencyMiddleware',
'pretix.multidomain.middlewares.MultiDomainMiddleware', 'pretix.multidomain.middlewares.MultiDomainMiddleware',
'pretix.base.middleware.CustomCommonMiddleware', 'pretix.base.middleware.CustomCommonMiddleware',
@@ -684,31 +687,41 @@ LOGGING = {
'disable_existing_loggers': False, 'disable_existing_loggers': False,
'formatters': { 'formatters': {
'default': { 'default': {
'format': '%(levelname)s %(asctime)s %(name)s %(module)s %(message)s' 'format': (
'%(levelname)s %(asctime)s RequestId=%(request_id)s %(name)s %(module)s %(message)s'
if REQUEST_ID_HEADER
else '%(levelname)s %(asctime)s %(name)s %(module)s %(message)s'
)
}, },
}, },
'filters': { 'filters': {
'require_admin_enabled': { 'require_admin_enabled': {
'()': 'pretix.helpers.logs.AdminExistsFilter', '()': 'pretix.helpers.logs.AdminExistsFilter',
} },
'request_id': {
'()': 'pretix.helpers.logs.RequestIdFilter'
},
}, },
'handlers': { 'handlers': {
'console': { 'console': {
'level': loglevel, 'level': loglevel,
'class': 'logging.StreamHandler', 'class': 'logging.StreamHandler',
'formatter': 'default' 'formatter': 'default',
'filters': ['request_id'],
}, },
'csp_file': { 'csp_file': {
'level': loglevel, 'level': loglevel,
'class': 'logging.FileHandler', 'class': 'logging.FileHandler',
'filename': os.path.join(LOG_DIR, 'csp.log'), 'filename': os.path.join(LOG_DIR, 'csp.log'),
'formatter': 'default' 'formatter': 'default',
'filters': ['request_id'],
}, },
'file': { 'file': {
'level': loglevel, 'level': loglevel,
'class': 'logging.FileHandler', 'class': 'logging.FileHandler',
'filename': os.path.join(LOG_DIR, 'pretix.log'), 'filename': os.path.join(LOG_DIR, 'pretix.log'),
'formatter': 'default' 'formatter': 'default',
'filters': ['request_id'],
}, },
'mail_admins': { 'mail_admins': {
'level': 'ERROR', 'level': 'ERROR',