Skip to content

Commit

Permalink
fix: add extra info to logs
Browse files Browse the repository at this point in the history
Hicham committed Nov 26, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 19c20d5 commit a40675e
Showing 5 changed files with 57 additions and 19 deletions.
18 changes: 18 additions & 0 deletions .conf/gunicorn.conf.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
from logging.handlers import DEFAULT_TCP_LOGGING_PORT

from gunicorn.glogging import Logger


workers = 7
threads = 10
limit_request_line = 8190


class CustomLogger(Logger):

def atoms(self, resp, req, environ, request_time):
atoms = super().atoms(resp, req, environ, request_time)
atoms.update({
"user_id": environ.get('user_id', '---'),
"trace_id": environ.get('trace_id', '---'),
"impersonating": environ.get('impersonating', '---'),
})
return atoms


logger_class = CustomLogger

logconfig_dict = dict(
version=1,
disable_existing_loggers=False,
22 changes: 20 additions & 2 deletions admin_cohort/middleware/context_request_middleware.py
Original file line number Diff line number Diff line change
@@ -2,9 +2,11 @@
from contextvars import ContextVar, Token
from typing import Optional, Any, Type

import jwt
from django.conf import settings
from django.http import HttpRequest


context_request: ContextVar[Optional[HttpRequest]] = ContextVar("context_request", default=None)


@@ -13,8 +15,19 @@ def get_trace_id() -> str:
if not request:
return str(uuid.uuid4())
trace_id_header = settings.TRACE_ID_HEADER
trace_id = request.headers.get(trace_id_header, request.META.get(f"HTTP_{trace_id_header}"))
return trace_id
return request.headers.get(trace_id_header, request.META.get(f"HTTP_{trace_id_header}"))

def get_request_user_id(request) -> str:
user_id = "Anonymous"
bearer_token = request.META.get("HTTP_AUTHORIZATION")
auth_token = bearer_token and bearer_token.split("Bearer ")[1] or None
if auth_token is not None:
try:
decoded = jwt.decode(jwt=auth_token, options={'verify_signature': False})
user_id = decoded.get("preferred_username", decoded.get("username"))
except jwt.PyJWTError:
pass
return user_id


class ContextRequestHolder:
@@ -38,6 +51,11 @@ def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
request.environ.update({
'user_id': get_request_user_id(request),
'trace_id': request.headers.get(settings.TRACE_ID_HEADER, str(uuid.uuid4())),
'impersonating': request.headers.get(settings.IMPERSONATING_HEADER, "-")
})
with ContextRequestHolder(request):
response = self.get_response(request)
return response
11 changes: 5 additions & 6 deletions admin_cohort/settings.py
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
from celery.schedules import crontab

TITLE = "Portail/Cohort360 API"
VERSION = "3.24.1"
VERSION = "3.24.2"
AUTHOR = "Assistance Publique - Hopitaux de Paris, Département I&D"
DESCRIPTION_MD = f"""Supports the official **Cohort360** web app and **Portail**
Built by **{AUTHOR}**
@@ -66,13 +66,12 @@
loggers={
'info': {
'level': "INFO",
'handlers': ['info_handler'] + (DEBUG and ['console'] or []),
'handlers': ['info'] + (DEBUG and ['console'] or []),
'propagate': False
},
'django.request': {
'level': "ERROR",
'handlers': ['error_handler'] + (DEBUG and ['console'] or []) + (
NOTIFY_ADMINS and ['mail_admins'] or []),
'handlers': ['error'] + (DEBUG and ['console'] or []) + (NOTIFY_ADMINS and ['mail_admins'] or []),
'propagate': False
}
},
@@ -87,14 +86,14 @@
'class': "logging.StreamHandler",
'filters': ["request_headers_interceptor"]
},
'info_handler': {
'info': {
'level': "INFO",
'class': "admin_cohort.tools.logging.CustomSocketHandler",
'host': "localhost",
'port': DEFAULT_TCP_LOGGING_PORT,
'filters': ["request_headers_interceptor"]
},
'error_handler': {
'error': {
'level': "ERROR",
'class': "admin_cohort.tools.logging.CustomSocketHandler",
'host': "localhost",
12 changes: 10 additions & 2 deletions admin_cohort/tools/logging.py
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
import traceback
from logging.handlers import SocketHandler

from gunicorn.glogging import SafeAtoms
from django.conf import settings

from admin_cohort.middleware.context_request_middleware import context_request
@@ -41,12 +42,19 @@ def makePickle(self, record):

trace_id, user_id, impersonating = None, None, None

request_metadata = d.pop("request_metadata", None)
if request_metadata is not None:
# logs from Django
request_metadata = d.pop("request_metadata", {})
if request_metadata:
trace_id = request_metadata.get("trace_id")
user_id = request_metadata.get("user_id")
impersonating = request_metadata.get("impersonating")

# logs from Gunicorn
if isinstance(record.args, SafeAtoms):
trace_id = record.args.get("trace_id")
user_id = record.args.get("user_id")
impersonating = record.args.get("impersonating")

d['trace_id'] = trace_id
d['user_id'] = user_id
d['impersonating'] = impersonating
13 changes: 4 additions & 9 deletions setup_logging.py
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@
import logging
import socketserver
import struct
import sys
from logging.handlers import DEFAULT_TCP_LOGGING_PORT
from pathlib import Path

@@ -31,14 +30,12 @@ def handle(self, record):


def configure_handlers() -> [logging.Handler]:
stream_handler = logging.StreamHandler(stream=sys.stdout)
dj_info_handler = CustomFileHandler(name='info', filename=BASE_DIR / "log/django.log")
dj_error_handler = CustomFileHandler(name='django.request', filename=BASE_DIR / "log/django.error.log")
guni_error_handler = CustomFileHandler(name='gunicorn.error', filename=BASE_DIR / "log/gunicorn.error.log")
guni_access_handler = CustomFileHandler(name='gunicorn.access', filename=BASE_DIR / "log/gunicorn.access.log")

handlers = [stream_handler,
dj_info_handler,
handlers = [dj_info_handler,
dj_error_handler,
guni_error_handler,
guni_access_handler]
@@ -55,8 +52,9 @@ def configure_handlers() -> [logging.Handler]:
" - %(message)s",
rename_fields={
"asctime": "timestamp",
"trace_id": "traceId",
"user_id": "userId",
"trace_id": "x_traceId",
"user_id": "x_userId",
"impersonating": "x_impersonating",
"levelname": "level",
"threadName": "thread",
"filename": "logger"
@@ -110,10 +108,7 @@ def serve_until_stopped(self):


def main():
fmt = "%(levelname)s %(asctime)s <%(name)s> traceId=%(trace_id)s " \
"pid=%(process)d module=%(filename)s msg=`%(message)s`"
logging.basicConfig(level=logging.INFO,
format=fmt,
handlers=configure_handlers())
tcp_server = LogRecordSocketReceiver()
tcp_server.serve_until_stopped()

0 comments on commit a40675e

Please sign in to comment.