나만의 커스텀 미들웨어로 API 로깅과 모니터링 구현하기

Django 미들웨어를 직접 구현하여 API 요청과 응답 과정을 기록하고 모니터링하는 시스템 구축

미들웨어 개념과 필요성

미들웨어(Middleware) 는 Django의 요청-응답 처리 과정에 개입하는 훅 시스템으로, 웹 요청이 뷰에 도달하기 전과 뷰가 생성한 응답이 클라이언트에게 전달되기 전에 특정 작업 수행

  • 중앙 집중식 관리: 여러 뷰에서 반복되는 로직을 한 곳에서 관리

  • API 성능 측정: 모든 API 요청의 처리 시간을 정확하게 측정하여 병목 지점 파악

  • 풍부한 컨텍스트 로깅: 요청의 IP, 사용자 정보, 헤더와 응답 상태 등을 종합한 상세 로그 생성

  • 요청/응답 데이터 정제: 조건에 따른 요청 데이터 가공 및 응답 형식 일괄 처리

커스텀 미들웨어 구현

1. 기본 미들웨어 구조 생성

# your_app/middleware.py
import time
import logging
from uuid import uuid4

logger = logging.getLogger(__name__)

class APILoggingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 요청 전 실행 코드
        
        response = self.get_response(request)
        
        # 응답 후 실행 코드

        return response

2. 요청 추적 및 성능 측정

def __call__(self, request):
    # 고유한 요청 ID 생성
    request.id = str(uuid4())
    
    # 요청 처리 시작 시간 기록
    start_time = time.time()

    response = self.get_response(request)

    # 처리 시간 계산 및 헤더 추가
    duration = time.time() - start_time
    response['X-Response-Time-ms'] = str(round(duration * 1000, 2))
    
    return response

3. 상세 로깅 구현

def __call__(self, request):
    request.id = str(uuid4())
    start_time = time.time()

    # 요청 본문 처리
    request_body = request.body
    if request_body:
        try:
            request_body = json.loads(request_body)
        except (json.JSONDecodeError, UnicodeDecodeError):
            request_body = "Could not decode body"

    response = self.get_response(request)

    duration = time.time() - start_time
    response_time_ms = round(duration * 1000, 2)
    response['X-Response-Time-ms'] = str(response_time_ms)

    # 사용자 정보 추출
    user = "anonymous"
    if request.user and request.user.is_authenticated:
        user = request.user.username

    # 로깅 데이터 구조화
    log_data = {
        'request_id': request.id,
        'user': user,
        'method': request.method,
        'path': request.path,
        'query_params': request.GET.dict(),
        'request_headers': dict(request.headers),
        'request_body': request_body,
        'remote_addr': request.META.get('REMOTE_ADDR'),
        'status_code': response.status_code,
        'response_time_ms': response_time_ms,
    }

    # 에러 시 응답 본문 포함
    if response.status_code >= 400 and response.content:
        try:
            log_data['response_body'] = json.loads(response.content)
        except (json.JSONDecodeError, UnicodeDecodeError):
            log_data['response_body'] = "Could not decode body"

    logger.info("API Request/Response", extra=log_data)

    return response

4. 미들웨어 등록

# settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'your_app.middleware.APILoggingMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    # ... 기타 미들웨어
]

실무 고려사항

보안 및 성능

  • 민감 정보 마스킹: 비밀번호, API 키, 개인정보는 반드시 로그에서 제외 또는 마스킹 처리

  • 성능 최적화: 미들웨어는 모든 요청마다 실행되므로 무거운 작업 금지

  • 선택적 로깅: 특정 경로(/health-check, /admin)는 로깅에서 제외

def __call__(self, request):
    if request.path.startswith('/admin') or request.path == '/health-check':
        return self.get_response(request)
    # ... 로깅 로직

모니터링 시스템 연동

구조화된 로그 데이터를 Datadog, ELK Stack, Grafana Loki 등의 도구로 전송하여 실시간 대시보드 구축 및 API 성능 지속 모니터링

Last updated