로그 남기기

  • 파이썬 로깅 모듈 4가지
    • 로거
    • 핸들러
    • 필터
    • 포맷터
  • 로깅 관련 설정 파일
    • 장고 디폴트 로그 설정 : [장고 설치 홈]/site-package/utils/log.py
    • 사용자 로그 설정 : settings.py의 LOGGING_CONFIG, LOGGING 항목
  • 로깅 주요 컴포넌트 관계

    [Logger]------------>[Handler]<--------------[Fomatter]
             /   |  \
            /    |___\__>[Handler]<--------------[Fomatter]
           /          \
          /            \
   ---------------------------------
   | [Filter]-->[Filter]-->[Filter] |    
   ---------------------------------       

  • 한개의 Logger에 여러 개의 Handler 지정 가능
  • 필터 체인 가능, 필터는 Logger 나 Handler 양쪽에 적용 가능

1. 로거

  • 로거 : 로그 메시지를 처리하기 위해 메시지를 담아두는 저장소
  • 로거 레벨

    로그 레벨 정수값 설명
    NOTSET 0 로그레벨 최하위 수준
    별도의 로거 또는 핸들러가 없을 때 디폴트 로그 레벨
    DEBUG 10 디버그 용도
    INFO 20 일반적인 정보
    WARNING 30 덜 중요한 문제점 발생시 문제에 대한 정보
    ERROR 40 주요 문제점 발생시 문제에 대한 정보
    CRITICAL 50 치명적인 문제점 발생시 문제에 대한 정보
  • 로그 레코드 : 로거에 저장되는 메시지, 레코드도 로그레벨을 가짐
  • ‘로그 레코드의 로그 레벨 >= 로거의 로그 레벨' 일 때, 메시지 처리가 진행되며 그 반대는 무시됨

2. 핸들러

  • 핸들러
    • 메시지에 무슨 작업을 할지 결정하는 엔진
    • 메시지를 화면이나 콘솔, 파일, 네트워크 소켓등 어디에 기록할 것인지 같은 로그 동작을 정의함
    • 핸들러도 로그 레벨을 가지고 있음
    • 로그 레코드의 로그레벨 >= 로그 핸들러의 로그레벨 일 때, 메시지 처리가 진행되며 그 반대는 무시됨
    • 각 핸들러는 서로 다른 로그레벨을 가질 수 있음
      • (예시) : ERROR 또는 CRITICAL 메시지는 표준 출력하는 핸들러, 모든 메시지를 파일에 기록하는 또 다른 핸들러

3. 필터

  • 로그레코드가 로거에서 핸들러로 넘겨 질때 필터를 이용해 레코드에 추가적인 제어를 할 수 있음
    • 예를 들어,
    • 필터를 추가하여, 특정 소스로 부터 오는 메시지만 핸들러로 넘기거나, _ 어떤 조건을 추가하여 조건에 맞으면, ERROR 로그를 WARNNING 로그로 낮추는 등

4. 포맷터

  • 출력하는 텍스트의 형식

5. 로그의 설정

(1) 별도의 설정을 하지 않았을 때, django의 기본설정을 따름

  • [django_home]/site-packages/utils/log.py
DEFAULT_LOGGING = {
    'version': 1, # dicConfig 버전1 형식
    'disable_existing_loggers': False, # 기존의 로거들을 비활성화 할것인가?, jango는 False를 권장
    'filters': {
        'require_debug_false': { # 디버그가 False인 경우만 핸들러를 동작함
            '()': 'django.utils.log.RequireDebugFalse', # ()는, 필터 객체 생성 클래스로 장고에서 생성한 클래스
        },
        'require_debug_true': { # 디버그가 True인 경우만 핸들러를 동작함
            '()': 'django.utils.log.RequireDebugTrue', # ()는 필터 객체 생성 클래스
        },
    },
    'formatters': {
        'django.server': { # 로그 생성시간과 메시지만을 출력
            '()': 'django.utils.log.ServerFormatter',
            'format': '[{server_time}] {message}',
            'style': '{',
        }
    },
    'handlers': {
        'console': { # INFO 이상의 메시지를 표준에러로 출력해주는 StreamHandler 클래스를 사용함.
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
        },
        'django.server': { 
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'django.server',
        },
        'mail_admins': {# ERROR 그 이상의 메시지를 관리자 메일로 보내주는 AdminEmailHandler 클래스를 생성
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django': { # django.* 계층, 즉  최상위 로거
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
        },
        'django.server': { # 상위로거로 메시지를 전파하지 않음. 개발용 웹서버인 runserver에서 사용하는 로거. 5XX는 Error로, 4XX는 WARNNING 으로 메시지 출력
            'handlers': ['django.server'],
            'level': 'INFO',
            'propagate': False,
        },
    }
}

(2) 사용자 정의 로거

  • mysite/settings.py
  • LOGGING 항목에 새로운 로거를 추가하거나, django 디폴트 로거들을 오버라이딩하는 것도 가능
LOGGING_CONFIG = 'logging.config.dictConfig'    # 설정하지 않아도 디폴트가 dictConfig이므로 생략 가능, 로깅 설정에 사용하는 함수를 지정
LOGGING = { # 개발자가 로깅을 설정할때 LOGGING 항목을 사용
    'version':1,
    'disable_existing_loggers':False,
    'formatters':{
        'verbose':{ # verbose 포맷터 정의
            'format':"[%(asctime)s] %(levelname)s %[%(name)s:%(lineno)s] %(message)s", # [로그메시지 기록시간], 로그레벨 이름, [로거이름:라인번호],로그메시지 순으로 출력 , 
            'datefmt':"%d/%b/%Y %H:%M:%S" # 시간의 포맷은 날짜/월축약형/연도 시(24시기준)/분/초 형식으로 출력
        },
    },
    'handlers':{
        'file': {
            'level':'DEBUG',
            'class':'logging.FileHandler',
            'filename':os.path.join(BASE_DIR,'logs','mysite.log'), # root디렉토리/logs/mysite.log 파일로 출력
            'formatter':'verbose'
        },
        'loggers':{
            'django':{ # 디폴트로 설정되어 있는 로거인데, 오버라이딩 하고 있음
                'handlers':['file'],
                'level': 'DEBUG',
            },
            'mysite':{ 
                'handlers':['file'],
                'level':'DEBUG',
            }
        }
    }
}

3. django 디폴트 로깅설정 무시하는 설정

# settings.py

LOGGING_CONFIG = None
LOGGING = {
    # 내가 원하는 로깅 컴포넌트를 설정함
}

import logging.config
logging.config.dictConfig(LOGGING)

4. 설정한 로거를 소스에서 사용하는 방법

# some_app/views.py
import logging

logger = logging.getLogger('mylogger')

def my_view(request, arg1, arg):
    # 로직
    if bad_mojo:
        # ERROR 레벨의 로그 레코드 생성함
        logger.error('Something went wrong!')
  • logging.getLogger() : 관행적으로 __name__ (해당 파일 이름) 구문을 사용, ‘' 로 설정하면 최상위 루트 로거가 됨
    • 만일 ch3/polls/views 파일이라면, __name__은 polls.views 가 됨
    • 로깅 호출은, 부모에게서 전파되므로 최상위 루트 로거에서 핸들러 하나만 만들어도 하위 로거의 모든 로깅 호출함
    • 예시 : project 이름공간에 정의된 로그 핸들러는 project.interesting 로거 및 project.interesting.stuff 로거가 보내주는 모든 로그 메시지를 잡음
        # 로거 이름으로 계층화
        logger = logging.getLogger('project.interesting.stuff')
      
  • 로깅 메소드 : 로거 객체는 로그 레벨별로 로그 호출 메소드를 갖고 있음
    • logger.debug()
    • logger.info()
    • logger.warning()
    • logger.error()
    • logger.critical()

    • logger.log()
    • logger.exception() : 익셉션 스택 트레이스 정보를 포함하는 ERROR 레벨의 로그 메시지 생성