Django 프로젝트 로그 설정 및 응답 포맷 통합 구현 가이드

목차

    1. 서버 로그 시스템 구현
    1. 전역 예외 처리机制 구축
    1. 응답 포맷 통합 포장
    1. 데이터베이스 연결 및 설정
    1. 소프트웨어 개발 방법론
    1. 사용자 인증 모듈 구현
    1. Django 설정 파일 심층 분석
    1. 미디어 파일 서빙 설정
  1. 서버 로그 시스템 구현

대규모 프로젝트에서는 체계적인 로깅 시스템이 필수적입니다. 로그를 통해 애플리케이션의 상태를 모니터링하고, 오류 발생 시 원인을 파악할 수 있습니다.

로그 시스템의 핵심 기능

- 콘솔 출력 로그
- 파일 기반 로그 저장
- 데이터베이스 로그 저장
- 통합 로그 관리 시스템 (Sentry 등)

개발 환경에서는 print() 문을 사용해도 되지만, 운영 환경에서는 logger 객체를 활용한 로깅을 권장합니다. 로깅 레벨을 조정하면 불필요한 로그 출력을 효과적으로 제어할 수 있습니다.

Django 프로젝트 로그 설정

Django는 Python 내장 로깅 모듈을 기반으로 합니다. 설정 파일(dev.py)에 다음과 같이 로그 구성을 추가합니다.

코드 보기

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
        },
    },
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            'level': 'WARNING',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            'level': 'ERROR',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(os.path.dirname(BASE_DIR), "logs", "app.log"),
            'maxBytes': 300 * 1024 * 1024,
            'backupCount': 10,
            'formatter': 'verbose',
            'encoding': 'utf-8'
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'file'],
            'propagate': True,
        },
    }
}

로거 객체 생성

utils 디렉토리에 custom_logger.py 파일을 생성합니다.

import logging

logger = logging.getLogger('django')

로그 활용 예시

# views.py
from utils.custom_logger import logger
from django.http import JsonResponse

def system_check(request):
    logger.info('시스템 점검 로그')
    logger.warning('경고 발생 로그')
    logger.error('오류 발생 로그')
    return JsonResponse({'status': 'running'})
  1. 전역 예외 처리机制 구축

RESTful API 개발 시 일관된 응답 형식은 매우 중요합니다. DRF(Django REST Framework)와 Django 자체 예외를 모두 처리하는 통합 예외 핸들러를 구현합니다.

IP 라우팅 차이점

주소 접근 범위
127.0.0.1 로컬 컴퓨터만 접근 가능
0.0.0.0 동일 네트워크 내 모든 장치 접근 가능

전역 예외 핸들러 구현

# utils/exception_handler.py
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import Response
from utils.custom_logger import logger


def global_exception_handler(exc, context):
    request = context.get('request')
    
    # 사용자 정보 추출
    try:
        user_id = request.user.pk if hasattr(request.user, 'pk') else '익명'
    except:
        user_id = '익명'
    
    view = context.get('view')
    
    # 오류 로깅
    logger.error('사용자:[%s], 방법:[%s], 경로:[%s], 뷰:[%s], 오류:[%s]',
        user_id, request.method, request.get_full_path(), str(view), str(exc)
    )
    
    # DRF 예외 처리
    response = drf_exception_handler(exc, context)
    
    if response:
        response = Response({
            'code': 999,
            'msg': response.data.get('detail', '서버 오류 발생')
        })
    else:
        response = Response({
            'code': 888,
            'msg': str(exc)
        })
    
    return response

DRF 설정 수정

# settings/dev.py
INSTALLED_APPS = [
    'rest_framework',
    'home',
    'user',
]

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'utils.exception_handler.global_exception_handler',
}

예제 뷰

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import APIException

class SystemTestView(APIView):
    def get(self, request):
        raise APIException('DRF 테스트 예외 발생')
        return Response({'status': 'ok'})
  1. 응답 포맷 통합 포장

일관된 API 응답 구조를 위해 Response 클래스를 재정의합니다.

통합 응답 클래스

# utils/response_wrapper.py
from rest_framework.response import Response

class ApiResponse(Response):
    def __init__(self, code=100, msg='success', status=None, headers=None, **kwargs):
        data = {'code': code, 'msg': msg}
        
        if kwargs:
            data.update(kwargs)
        
        super().__init__(data=data, status=status, headers=headers)

사용 예시

from utils.response_wrapper import ApiResponse

class UserView(APIView):
    def get(self, request):
        # 기본 응답
        return ApiResponse()
    
    def post(self, request):
        # 추가 데이터 포함 응답
        return ApiResponse(token='abc123', user={'name': '홍길동'})
    
    def delete(self, request):
        # 사용자 정의 코드
        return ApiResponse(code=101, msg='deleted')
  1. 데이터베이스 연결 및 설정

데이터베이스 및 사용자 생성

-- MySQL 명령어
CREATE DATABASE myproject DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

-- 프로젝트용 사용자 생성
GRANT ALL PRIVILEGES ON myproject.* TO 'projectuser'@'%' IDENTIFIED BY 'SecurePass123!';
GRANT ALL PRIVILEGES ON myproject.* TO 'projectuser'@'localhost' IDENTIFIED BY 'SecurePass123!';

FLUSH PRIVILEGES;

Django 데이터베이스 설정

# settings/dev.py
import pymysql
pymysql.install_as_MySQLdb()

# 환경 변수 활용 (보안 강화)
import os
db_user = os.environ.get('DB_USER', 'projectuser')
db_pass = os.environ.get('DB_PASSWORD', 'SecurePass123!')

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myproject',
        'USER': db_user,
        'PASSWORD': db_pass,
        'HOST': '127.0.0.1',
        'PORT': 3306
    }
}

# 또는 mysqlclient 사용 시 (추천)
# pip install mysqlclient

mysqlclient 설치

pip install mysqlclient
# 또는 PyCharm 패키지 관리자 사용
  1. 소프트웨어 개발 방법론

폭포수 모델 (Waterfall Model)

요구사항 분석 → 설계 → 구현 → 테스트 → 배포

각 단계가 완료되어야 다음 단계로 진행하는 전통적 방식입니다.

애자일 개발 (Agile Development)

스프린트 (2-4주 단위)
계획 → 설계 → 개발 → 테스트 → 배포 → 회고

점진적 기능 개발과 빠른 피드백을 중시하는 현대적 방법론입니다.

  1. 사용자 인증 모듈 구현

Django 인증 시스템을 확장하여 사용자 정의 모델을 구현합니다.

필수 패키지 설치

pip install Pillow

사용자 모델 정의

# user/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    phone = models.CharField(max_length=11, unique=True)
    avatar = models.ImageField(upload_to='avatars', default='avatars/default.png')
    
    class Meta:
        db_table = 'custom_user'
        verbose_name = '사용자'
        verbose_name_plural = verbose_name
    
    def __str__(self):
        return self.username

설정 업데이트

# settings/dev.py
AUTH_USER_MODEL = 'user.User'

마이그레이션 실행

python manage.py makemigrations
python manage.py migrate
  1. Django 설정 파일 심층 분석

# settings.py 핵심 설정 분석
from pathlib import Path
import os
import sys

# 프로젝트 루트 경로 설정
BASE_DIR = Path(__file__).resolve().parent.parent

# Python 경로에 앱 디렉토리 추가
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))

# 보안 키 (중요: 운영 환경에서 변경 필요)
SECRET_KEY = 'your-secret-key-here'

# 디버그 모드 (운영에서는 False 필수)
DEBUG = False
ALLOWED_HOSTS = ['*']

# 설치된 앱
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'home',
    'user',
]

# 미들웨어
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
]

# URL 설정
ROOT_URLCONF = 'project.urls'

# 템플릿 설정
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
            ],
        },
    },
]

# WSGI 애플리케이션
WSGI_APPLICATION = 'project.wsgi.application'

# 데이터베이스
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myproject',
        'USER': os.environ.get('DB_USER', 'projectuser'),
        'PASSWORD': os.environ.get('DB_PASSWORD', 'SecurePass123!'),
        'HOST': '127.0.0.1',
        'PORT': 3306
    }
}

# 국제화
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = False

# 정적 파일
STATIC_URL = '/static/'

# 미디어 파일
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# 기본 자동 증가 필드
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
  1. 미디어 파일 서빙 설정

사용자 업로드 이미지에 접근할 수 있도록 라우팅을 설정합니다.

설정 추가

# settings/dev.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

URL 라우팅 등록

# urls.py
from django.urls import path
from django.views.static import serve
from django.conf import settings

urlpatterns = [
    path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT}),
]

이제 브라우저를 통해 http://localhost:media/avatars/user.png 형식으로 업로드된 이미지에 접근할 수 있습니다.

부록

RDBAC 프로젝트 참고 자료

암호화 관련 면접 질문

MD5는 대칭 암호화인가, 비대칭 암호화인가?

MD5는 암호화가 아닌 해시(摘要) 알고리즘입니다. 복호화가 불가능하며, 동일한 입력에 대해 항상 동일한 출력(해시값)을 생성합니다.

유형 특징 예시
대칭 암호화 암호/복호 동일 키 AES, DES
비대칭 암호화 공개키로 암호, 개인키로 복호 RSA
해시 알고리즘 단방향 변환 MD5, SHA-256

태그: Django rest-framework python logging Exception-Handling

8월 14일 19:05에 게시됨