adding the logs service
All checks were successful
Build and Deploy Beta / build-and-push (push) Successful in 1m21s
Build and Deploy Beta / deploy (push) Successful in 11s

This commit is contained in:
vickytechkey 2026-08-09 17:24:57 +05:30
parent 1591802c8e
commit 22800ab230
4 changed files with 126 additions and 1 deletions

1
.gitignore vendored
View file

@ -57,6 +57,7 @@ cover/
# Django stuff: # Django stuff:
*.log *.log
logs/
local_settings.py local_settings.py
db.sqlite3 db.sqlite3
db.sqlite3-journal db.sqlite3-journal

View file

@ -1,3 +1,4 @@
import logging
import random import random
from datetime import date from datetime import date
from django.contrib.auth import authenticate, login from django.contrib.auth import authenticate, login
@ -13,6 +14,8 @@ from .serializers import (
OrderSerializer, ReturnRequestSerializer, WalletSerializer OrderSerializer, ReturnRequestSerializer, WalletSerializer
) )
logger = logging.getLogger('api')
def get_active_user(request): def get_active_user(request):
if request.user and request.user.is_authenticated: if request.user and request.user.is_authenticated:
return request.user return request.user
@ -30,7 +33,9 @@ class RegisterView(APIView):
if serializer.is_valid(): if serializer.is_valid():
user = serializer.save() user = serializer.save()
login(request, user) login(request, user)
logger.info('New supplier registered: username=%s email=%s', user.username, user.email)
return Response(UserSerializer(user).data, status=status.HTTP_201_CREATED) return Response(UserSerializer(user).data, status=status.HTTP_201_CREATED)
logger.warning('Registration failed: %s', serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class LoginView(APIView): class LoginView(APIView):
@ -40,7 +45,9 @@ class LoginView(APIView):
user = authenticate(username=username, password=password) user = authenticate(username=username, password=password)
if user: if user:
login(request, user) login(request, user)
logger.info('Login successful: username=%s', username)
return Response(UserSerializer(user).data) return Response(UserSerializer(user).data)
logger.warning('Login failed: username=%s', username)
return Response({'error': 'Invalid credentials'}, status=status.HTTP_400_BAD_REQUEST) return Response({'error': 'Invalid credentials'}, status=status.HTTP_400_BAD_REQUEST)
class VerifyOtpView(APIView): class VerifyOtpView(APIView):
@ -190,9 +197,11 @@ class WithdrawView(APIView):
try: try:
amount = float(amount_str) amount = float(amount_str)
except (TypeError, ValueError): except (TypeError, ValueError):
logger.error('Withdraw failed for user=%s: invalid amount value=%s', user.username, amount_str)
return Response({'error': 'Invalid amount'}, status=status.HTTP_400_BAD_REQUEST) return Response({'error': 'Invalid amount'}, status=status.HTTP_400_BAD_REQUEST)
if amount <= 0 or amount > float(wallet.outstanding): if amount <= 0 or amount > float(wallet.outstanding):
logger.warning('Withdraw rejected for user=%s: amount=%.2f outstanding=%.2f', user.username, amount, float(wallet.outstanding))
return Response({'error': 'Insufficient funds or invalid amount'}, status=status.HTTP_400_BAD_REQUEST) return Response({'error': 'Insufficient funds or invalid amount'}, status=status.HTTP_400_BAD_REQUEST)
wallet.outstanding = float(wallet.outstanding) - amount wallet.outstanding = float(wallet.outstanding) - amount
@ -207,4 +216,5 @@ class WithdrawView(APIView):
status='Transferred' status='Transferred'
) )
logger.info('Withdraw successful: user=%s amount=%.2f tx_id=%s', user.username, amount, tx.tx_id)
return Response(WalletSerializer(wallet).data) return Response(WalletSerializer(wallet).data)

View file

@ -10,6 +10,7 @@ For the full list of settings and their values, see
https://docs.djangoproject.com/en/6.1/ref/settings/ https://docs.djangoproject.com/en/6.1/ref/settings/
""" """
import os
from pathlib import Path from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
@ -139,3 +140,106 @@ REST_FRAMEWORK = {
'api.authentication.CsrfExemptSessionAuthentication', 'api.authentication.CsrfExemptSessionAuthentication',
), ),
} }
# ---------------------------------------------------------------------------
# Logging
# Writes to /app/logs/ (volume-mounted on host) and to stdout.
# Log files are also picked up by the CloudWatch Agent on the EC2 host.
# ---------------------------------------------------------------------------
LOGS_DIR = BASE_DIR / 'logs'
os.makedirs(LOGS_DIR, exist_ok=True)
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
# ----- Formatters -----
'formatters': {
'verbose': {
'format': '[{asctime}] {levelname} {name} {process:d} {thread:d} | {message}',
'style': '{',
'datefmt': '%Y-%m-%d %H:%M:%S',
},
'simple': {
'format': '[{asctime}] {levelname} | {message}',
'style': '{',
'datefmt': '%Y-%m-%d %H:%M:%S',
},
},
# ----- Filters -----
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
},
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
# ----- Handlers -----
'handlers': {
# Writes every log line to stdout (visible via `docker logs`)
'console': {
'class': 'logging.StreamHandler',
'formatter': 'simple',
},
# Rotating file for all application logs (INFO+)
'app_file': {
'class': 'logging.handlers.RotatingFileHandler',
'filename': str(LOGS_DIR / 'app.log'),
'maxBytes': 10 * 1024 * 1024, # 10 MB
'backupCount': 7,
'formatter': 'verbose',
'encoding': 'utf-8',
},
# Dedicated rotating file for ERROR+ only
'error_file': {
'class': 'logging.handlers.RotatingFileHandler',
'filename': str(LOGS_DIR / 'error.log'),
'maxBytes': 10 * 1024 * 1024, # 10 MB
'backupCount': 7,
'formatter': 'verbose',
'level': 'ERROR',
'encoding': 'utf-8',
},
# Django request/response log
'request_file': {
'class': 'logging.handlers.RotatingFileHandler',
'filename': str(LOGS_DIR / 'requests.log'),
'maxBytes': 10 * 1024 * 1024, # 10 MB
'backupCount': 7,
'formatter': 'simple',
'encoding': 'utf-8',
},
},
# ----- Loggers -----
'loggers': {
# Root logger catches everything not matched below
'': {
'handlers': ['console', 'app_file', 'error_file'],
'level': 'INFO',
'propagate': False,
},
# Your application code
'api': {
'handlers': ['console', 'app_file', 'error_file'],
'level': 'DEBUG',
'propagate': False,
},
# Django HTTP request log (4xx / 5xx)
'django.request': {
'handlers': ['console', 'request_file', 'error_file'],
'level': 'INFO',
'propagate': False,
},
# Suppress noisy security middleware warnings in prod
'django.security': {
'handlers': ['error_file'],
'level': 'ERROR',
'propagate': False,
},
},
}

View file

@ -4,9 +4,19 @@ services:
web: web:
build: . build: .
ports: ports:
- "8000:8000" - "8080:8000"
volumes: volumes:
- .:/app - .:/app
- ./logs:/app/logs # persists log files on the host
environment: environment:
- DEBUG=1 - DEBUG=1
restart: always restart: always
# Forward Gunicorn access + error logs to /app/logs
command: >
gunicorn config.wsgi:application
--bind 0.0.0.0:8000
--workers 2
--access-logfile /app/logs/gunicorn-access.log
--error-logfile /app/logs/gunicorn-error.log
--log-level info
--capture-output