1. 장고의 로깅
- 파이썬의 로깅 체계를 따르면서 일부만 추가되었다.
- settings.py에 정의된 LOGGIN, LOGGIN_CONFIG 속성을 참고하여 로깅 관련 설정을 처리하는데, 이 속성이 없더라도 리폴트 로깅 설정으로 처리한다.
2. 파이썬의 로깅 모듈
1) 로거
- 로그 메시지를 처리하기 위해 메시지를 담아두는 곳
- 모든 로거는 이름과 로그 레벨을 갖고 있으며, 로그 레벨은 어느 레벨 이상의 메시지를 처리할지에 대한 기준이다.
- NOTSET (정수 값 0) : 리폴트 로그 레벨
- DEBUG (정수 값 10) : 디버그 용도로 사용
- INFO (정수 값 20) : 일반적인 정보
- WARNING (정수 값 30) : 주의할 만한 문제점에 대한 정보
- ERROR (정수 값 40) : 주요 문제점에 대한 정보
- CRITICAL (정수 값 50) : 치명적인 문제점에 대한 정보
- 로거에 저장되는 메시지를 로그 레코드라고 하며, 이 또한 로그 레벨을 가진다. 로그 레코드는 로그 이벤트에 대해 스택 트레이스 정보나 에러 코드와 같은 메타 정보도 가질 수 있다.
- 한 개의 로거에 여러 개의 핸들러를 지정할 수 있다.
- 동작 방식 : 메시지가 로거에 도착하면 로거와 로그 레코드의 로그 레벨을 비교해서 로그 레코드 >= 로거 이면 메시지를 핸들러에게 넘겨주고, 로그 레코드 < 로거 이면 메시지를 무시한다.
2) 핸들러
- 로거로부터 받은 메시지에 무슨 작업을 할지 결정하는 엔진
- 메시지를 어디에 기록할 것인지와 같은 로그 동작을 정의한다.
※ 자주 사용되는 설정
- 로그 메시지를 표준 에러로 출력 ("class": "logging.StreamHandler")
- 로그 메시지를 파일에 기록 ("class": "logging.FileHandler")
- 로그 메시지를 사이트 관리자의 이메일로 전송 ("class": "django.utils.log.AdminEmailHandler")
- 핸들러도 로그 레벨을 가지고 있는데, 로그 레벨이 로그 레코드 < 핸들러 이면 메시지를 무시한다.
3) 필터
- 메시지가 로거에서 핸들러로 넘겨지는 과정에 개입하여 로그 처리 기준을 추가하거나 메시지를 수정하는 등의 추가적인 제어를 수행해주는 것
- 로거와 핸들러 양쪽에 적용 가능하며, 필터 체인도 가능하다.
4) 포맷터
- 로그 레코드 텍스트의 포맷을 지정해준다.
- 보통 파이썬의 포맷 스트링을 사용하지만, 사용자 정의 포맷터도 만들 수 있다.
3. 로거 사용
- 로거, 핸들러, 필터, 포맷터 등을 settings.py에 설정하고 코드 내에서 로깅 메소드를 호출하면 된다.
[settings.py 예시]
- 장고는 사전형 설정(dictConfig) 방식을 디폴트로 로깅을 설정한다.
# https://docs.djangoproject.com/ko/4.1/topics/logging/
# settings.py
...
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
'mylogger' : {
'handlers': ['console'],
'level': 'WARNING',
},
},
}
[로깅 메소드 호출 예시]
# views.py
import logging
logger = logging.getLogger("mylogger") # settings.py에 정의한 로거의 이름으로 로거를 취득
def my_view(request, arg):
# 로직
if bad_mojo:
logger.error('Something went wrong') # ERROR 레벨의 로그 레코드를 생성
1) 로거의 계층화
- 로거를 취득할 때 __name__ 구문을 사용할 수도 있다. __name__은 이 구문이 있는 파일의 파이썬 모듈 경로다. 로거를 계층화하면 로깅 호출을 모듈 단위로 처리할 수 있게 된다.
logger = logging.getLogger(__name__) # __name__ -> 'a.b.views'
a.b.views 로거의 부모는 a.b 로거이고, a.b 로거의 부모는 a 로거가 된다. 로거의 이름을 빈 문자열로 지정하면 루트 로거를 의미하게 된다.
- 로거의 계층화를 사용하면 기본적으로 로깅 호출을 부모 로거에게 전파시킨다. 이렇게 하면 루트 로거에서 핸들러 하나만을 만들어도 하위 로거의 모은 로깅 호출을 잡을 수 있다. 특정 로거에서 상위 로거로 전파되는 것을 원하지 않으면 다음과 같이 전파 기능을 비활성화시킬 수도 있다.
'myproject.custom': {
...
'propagate': False,
},
2) 로거 객체의 로깅 호출 메소드
- logger.debug() : DEBUG 레벨의 로그 레코드를 생성
- logger.info() : INFO 레벨의 로그 레코드를 생성
- logger.warning() : WARNING 레벨의 로그 레코드를 생성
- logger.error() : ERROR 레벨의 로그 레코드를 생성
- logger.critical() : CRITICAL 레벨의 로그 레코드를 생성
- logger.log() : 원하는 로그 레벨을 정해서 로그 레코드를 생성
- logger.exception() : 익셉션 스택 트레이스 정보를 포함하는 ERROR 레벨의 로그 메시지를 생성
4. 장고의 디폴트 로깅 설정
- 장고의 디폴트 로깅 설정은 django/utils/log.py에서 확인할 수 있다.
DEFAULT_LOGGING = {
"version": 1, # 설정 버전 1
"disable_existing_loggers": False, # 기존의 로거들을 비활성화하지 않음
"filters": {
"require_debug_false": { # DEBUG=False인 경우에만 핸들러가 동작
"()": "django.utils.log.RequireDebugFalse", # ()는 장고에서 별도로 정의한 클래스라는 의미
},
"require_debug_true": { # DEBUG=True인 경우에만 핸들러가 동작
"()": "django.utils.log.RequireDebugTrue",
},
},
"formatters": {
"django.server": { # 로그 생성 시각과 로그 메시지만을 출력
"()": "django.utils.log.ServerFormatter",
"format": "[{server_time}] {message}",
"style": "{",
}
},
"handlers": {
"console": { # INFO 레벨 이상의 메시지를 표준 에러로 출력, require_debug_true 필터 사용
"level": "INFO",
"filters": ["require_debug_true"],
"class": "logging.StreamHandler",
},
"django.server": { # INFO 레벨 이상의 메시지를 표준 에러로 출력, django.server 포맷터 사용
"level": "INFO",
"class": "logging.StreamHandler",
"formatter": "django.server",
},
"mail_admins": { # ERROR 레벨 이상의 메시지를 사이트 관리자에게 이메일로 전송, require_debug_false 필터 사용
"level": "ERROR",
"filters": ["require_debug_false"],
"class": "django.utils.log.AdminEmailHandler",
},
},
"loggers": {
"django": { # INFO 레벨 이상의 메시지를 console 및 mail_admins 핸들러로 전송
"handlers": ["console", "mail_admins"],
"level": "INFO",
},
"django.server": { # INFO 레벨 이상의 메시지를 django.server 핸들러로 전송, 상위 로그로 메시지를 전파하지 않음
"handlers": ["django.server"],
"level": "INFO",
"propagate": False,
},
},
}
※ django.server 로거는 runserver에서 사용하는 로거다. 5xx 응답은 ERROR 메시지로, 4xx 응답은 WARNING 메시지로, 그 외는 INFO 메시지로 출력된다.
5. 개발자가 로깅 설정하기
- settings.py에서 LOGGING 항목을 사용하면 된다. 여기에 로거를 새롭게 추가할 수도 있고, 이미 디폴트로 설정된 로거들을 오버라이딩하여 동작을 변경할 수도 있다.
6. 디폴트 로깅 설정 무시
- 장고에서 이미 정의한 로거 설정을 무시하고 싶다면 LOGGING_CONFIG를 None으로 지정해주면 된다. 그리고 자신만의 로깅 설정을 LOGGING 항목에 작성하고, logging.config의 dictConfig() 함수를 통해 LOGGING에 정의된 내용을 설정하면 된다.
LOGGING_CONFIG=None
LOGGING = {
...
}
import logging.config
logging.config.dictConfig(LOGGING)
7. 장고 패키지에 추가된 그 외의 사항
([4. 장고의 디폴트 로깅 설정]에서 이미 설명한 사항은 생략한다)
1) 로거
- django.request : 요청 처리 관련 메시지를 기록한다. 이 로거에 담기는 메시지는 추가적으로 status_code, request 메타 항목을 가진다.
- django.template : 템플릿 렌더링 과정에서 발생하는 로그 메시지를 기록한다.
- django.db.backends : DB 관련 메시지를 기록한다. 이 로거에 담기는 메시지는 추가적으로 duration, sql, params 메타 항목을 가진다. SQL 로깅은 settings.DEBUG 속성이 True인 경우에만 활성화된다.
- django.security.* : 사용자가 보안 측면에서 위험한 동작을 실행한 경우, 이에 대한 메시지를 기록한다. 예를 들어, HTTP Host 헤더가 ALLOWED_HOSTS에 없는 경우에 반응한다.
- django.db.backends.schema : DB 스키마 변경 시 사용된 SQL 쿼리를 기록한다.
2) 필터
- CallBackFilter : 콜백 함수를 지정해서 필터를 통과하는 모든 메시지에 대해 콜백 함수를 호출한다. 콜백 함수의 리턴값이 False이면 메시지 로깅은 더 이상 처리하지 않는다.
● 장고 로깅 공식 문서 : https://docs.djangoproject.com/en/4.1/howto/logging/#customize-logging-configuration
'Django' 카테고리의 다른 글
[Django] apps.py의 역할 (0) | 2023.01.26 |
---|---|
[Django] 프로젝트 개발 순서 (0) | 2023.01.25 |
[Django] 클래스형 뷰와 제네릭 뷰 소개 (0) | 2023.01.24 |
[Django] 템플릿 시스템 (0) | 2023.01.24 |
[Django] 장고 파이썬 쉘 / Model CRUD API (0) | 2023.01.24 |
댓글