From 926b6edabba210911ca4d141bc8ebaa2d7d232dd Mon Sep 17 00:00:00 2001 From: vickytechkey Date: Thu, 15 Oct 2026 20:57:55 +0530 Subject: [PATCH] feat: add comprehensive logging configuration, rotating file handlers, request middleware, and gunicorn log integration --- .gitignore | 1 + beta-documentverification.service | 2 +- docverify/middleware.py | 30 +++++++++++++ docverify/settings.py | 70 +++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 docverify/middleware.py diff --git a/.gitignore b/.gitignore index b10bc98..fc58971 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ ENV/ db.sqlite3 db.sqlite3-journal *.log +logs/ local_settings.py # Environment variables & secrets diff --git a/beta-documentverification.service b/beta-documentverification.service index 426ebc2..b5f1ccf 100644 --- a/beta-documentverification.service +++ b/beta-documentverification.service @@ -6,7 +6,7 @@ After=network.target User=ubuntu Group=ubuntu WorkingDirectory=/home/ubuntu/beta-documentverification -ExecStart=/home/ubuntu/beta-documentverification/venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8092 docverify.wsgi:application +ExecStart=/home/ubuntu/beta-documentverification/venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8092 --access-logfile /home/ubuntu/beta-documentverification/logs/gunicorn-access.log --error-logfile /home/ubuntu/beta-documentverification/logs/gunicorn-error.log --capture-output docverify.wsgi:application Restart=always RestartSec=3 diff --git a/docverify/middleware.py b/docverify/middleware.py new file mode 100644 index 0000000..2288d96 --- /dev/null +++ b/docverify/middleware.py @@ -0,0 +1,30 @@ +import logging +import time + +logger = logging.getLogger("django.request") + + +class RequestLoggingMiddleware: + """ + Captures incoming HTTP requests, client IPs, response status codes, + and end-to-end processing durations to log to requests.log and console. + """ + + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + start_time = time.time() + response = self.get_response(request) + duration_ms = (time.time() - start_time) * 1000 + + ip = ( + request.META.get("HTTP_X_FORWARDED_FOR", "").split(",")[0].strip() + or request.META.get("REMOTE_ADDR", "unknown") + ) + + logger.info( + f"IP: {ip} | {request.method} {request.get_full_path()} | " + f"Status: {response.status_code} | Duration: {duration_ms:.2f}ms" + ) + return response diff --git a/docverify/settings.py b/docverify/settings.py index 64575df..4579663 100644 --- a/docverify/settings.py +++ b/docverify/settings.py @@ -37,6 +37,7 @@ INSTALLED_APPS = [ MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", + "docverify.middleware.RequestLoggingMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", @@ -120,4 +121,73 @@ CODEPLUS_BASE_URL = os.environ.get("CODEPLUS_BASE_URL", "https://apihub.services CODEPLUS_CLIENT_API_ID = os.environ.get("CODEPLUS_CLIENT_API_ID", "CAPI-YYR0YJIE0VMTDENY") CODEPLUS_CLIENT_API_SECRET = os.environ.get("CODEPLUS_CLIENT_API_SECRET", "s24Ts9wFsgl64mFzA61OqG0RDLRs2HFCpmOZBmqs") +# ────────────────────────────────────────────────────────────────────────────── +# Comprehensive Logging Configuration & CloudWatch Shipments +# ────────────────────────────────────────────────────────────────────────────── +LOGS_DIR = BASE_DIR / "logs" +LOGS_DIR.mkdir(exist_ok=True) + +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "verbose": { + "format": "{levelname} {asctime} [{name}] {process:d} {thread:d} {message}", + "style": "{", + }, + "simple": { + "format": "{levelname} {asctime} {message}", + "style": "{", + }, + }, + "handlers": { + "console": { + "class": "logging.StreamHandler", + "formatter": "simple", + }, + "app_file": { + "level": "INFO", + "class": "logging.handlers.RotatingFileHandler", + "filename": str(LOGS_DIR / "app.log"), + "maxBytes": 10 * 1024 * 1024, # 10 MB + "backupCount": 5, + "formatter": "verbose", + }, + "error_file": { + "level": "ERROR", + "class": "logging.handlers.RotatingFileHandler", + "filename": str(LOGS_DIR / "error.log"), + "maxBytes": 10 * 1024 * 1024, # 10 MB + "backupCount": 5, + "formatter": "verbose", + }, + "requests_file": { + "level": "INFO", + "class": "logging.handlers.RotatingFileHandler", + "filename": str(LOGS_DIR / "requests.log"), + "maxBytes": 10 * 1024 * 1024, # 10 MB + "backupCount": 5, + "formatter": "simple", + }, + }, + "loggers": { + "django": { + "handlers": ["console", "app_file", "error_file"], + "level": "INFO", + "propagate": True, + }, + "django.request": { + "handlers": ["console", "requests_file", "error_file"], + "level": "INFO", + "propagate": False, + }, + "verifier": { + "handlers": ["console", "app_file", "error_file"], + "level": "INFO", + "propagate": True, + }, + }, +} + +