on
#37 로깅(Logging)
#37 로깅(Logging)
서버가 사용자의 요청을 처리하다보면 예기치 못한 동작으로 오류가 발생할 때도 있을 것이다. 개발환경에서는
DEBUG 가 True 로 설정되어있어 이러한 오류가 발생했을 때 웹 페이지상에 상세 정보가 표시되며 명령 프롬프트에서도
이를 확인할 수 있다. 하지만 운영 환경에서는 DEBUG 를 False 로 해두었기 때문에 에러가 발생해도 자세한 내용을
알 수가 없다. 이런 상황에서 발생한 오류의 상세 내역들을 기록한 로그 파일을 사용하면 운영 환경에서 정보를
노출하지 않으면서도 오류의 상세 내용도 확인할 수 있다.
1. DEFAULT_LOGGING
로그를 파일로 저장하기 위해 DEFAULT_LOGGING 설정에 대해 알아야 한다. 장고의 DEFAULT_LOGGING 설정은
다음과 같다.
DEFAULT_LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'filters': { 'require_debug_false': { '()': 'django.utils.log.RequireDebugFalse', }, 'require_debug_true': { '()': 'django.utils.log.RequireDebugTrue', }, }, 'formatters': { 'django.server': { '()': 'django.utils.log.ServerFormatter', 'format': '[{server_time}] {message}', 'style': '{', }, }, 'handlers': { 'console': { 'level': 'INFO', 'filters': ['require_debug_true'], 'class': 'logging.StreamHandler', }, 'django.server': { 'level': 'INFO', 'class': 'logging.StreamHandler', 'formatter': 'django.server', }, 'mail_admins': { 'level': 'ERROR', 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler' }, }, 'loggers': { 'django': { 'handlers': ['console', 'mail_admins'], 'level': 'INFO', }, 'django.server': { 'handlers': ['django.server'], 'level': 'INFO', 'propagate': False, }, } }
version 은 logging 모듈이 업그레이드되어도 현재 설정을 보장하기 위해 항상 고정값 1을 사용해야 한다.
disable_existing_loggers 는 True로 설정하면 기존에 설정된 로거를 비활성화시킨다. 여기서는 그럴 이유가 없으니
False 로 설정한다.
filters 는 특정 조건에서 로그를 출력하거나 출력하지 않기 위해 사용한다. require_debug_false 필터는 DEBUG 값이
False 인지 판단하는 필터이며 require_debug_true는 그 반대로 DEBUG 값이 True 인지 판단하는 필터이다.
각각 django.utils.log.RequireDebugFalse, django.utils.log.RequireDebugTrue 함수를 호출하여 이를 판단한다.
formatters 는 로그를 출력할 형식을 정의한다. server_time 은 서버의 시간, message 는 출력 내용을 의미한다.
handlers 는 로그의 출력 방법을 정의한다. DEFAULT_LOGGING 설정에 등록된 핸들러는 다음과 같다.
console : 콘솔에 로그를 출력. 로그 레벨이 INFO 이상이고 DEBUG 가 True 일 때만 로그를 출력
django.server : python manage.py runserver 로 구동하는 개발용 서버에서만 사용하는 핸들러이다.
콘솔에 로그를 출력한다.
콘솔에 로그를 출력한다. mail_admins : 로그 내용을 이메일로 전송하는 핸들러로, 로그 레벨이 ERROR 이상이고 DEBUG 가 False 일 때만
로그를 전송한다. 환경설정 파일에 ADMINS 항목을 추가하고 관리자 이메일을 등록, 이메일 발송을
위한 SMTP 설정해야 사용 가능하다.
loggers 는 로그를 출력하는 프로그램에서 사용하는 로거의 이름을 의미한다. DEFAULT_LOGGING 설정에 등록된
로거는 다음과 같다.
django : django 프레임워크가 사용하는 로거로 로그 레벨이 INFO 이상일 경우에만 로그를 출력한다.
django.server : 개발 서버가 사용하는 로거로 로그 레벨이 INFO 이상일 경우에만 로그를 출력한다.
'propagate': False 의 의미는 django.server 가 출력하는 로그를 django 로거로 전달하지
않는다는 의미이다. 로그가 이중으로 출력되는 것을 막기 위해서이다.
2. 로그 레벨
로그의 레벨은 다음의 5 단계로 분류된다.
1단계 : DEBUG : 디버깅 목적으로 사용
2단계 : INFO : 일반 정보를 출력할 목적으로 사용
3단계 : WARNING : 경고 정보를 출력할 목적으로 사용 (작은 문제)
4단계 : ERROR : 오류 정보를 출력할 목적으로 사용 (큰 문제)
5단계 : CRITICAL : 아주 심각한 문제를 출력할 목적으로 사용
단계가 높아질수록 심각한 오류이며 로그는 설정한 레벨 이상의 로그만이 출력된다.
3. 로그 파일
현재 서버환경에서 오류가 발생하면 확인할 방법이 없다. 이를 해결하기 위해 다음의 두 가지 방법을 사용할 수 있다.
오류 발생시 관리자 이메일로 오류내용을 발송한다. mail_admins 핸들러가 존재하기 때문에 이메일 발송을 위한
관리자 이메일 등록과 SMTP 설정만으로 사용 가능해진다.
관리자 이메일 등록과 SMTP 설정만으로 사용 가능해진다. 서버 환경에서 오류 발생 시 특정 파일에 로그 출력
우선 여기서는 파일에 로그를 출력하는 방식을 알아보자.
먼저 위에서 살펴본 DEFAULT_LOGGING 설정을 변수명만 LOGGING 으로 바꾸어 config/settings/base.py 에 추가해준다.
formatters 에 앞으로 사용할 로그의 formatter인 standard 를 추가해준다.
'현재시간 [로그레벨] 로거명: 메시지' 의 형태로 로그를 출력할 것이다.
handlers 에 파일에 로그를 저장할 핸들러인 file 을 추가해준다.
level 은 INFO 레벨 이상의 에러에 대해 로그를 출력하도록 하며
filters 는 운영 환경에서 사용할 것이니 required_debug_false 필터를 적용한다.
class 는 logging.handleres.RotatingFileHandler 를 사용한다. 이 클래스를 사용하면 로그파일이 지정크기 이상으로
커질 경우 파일에 인덱스를 붙여 정해진 파일 갯수를 유지하며 로깅하기 때문에 로그파일로 디스크가 포화되는 위험을
방지할 수 있다.
filename 은 logs 디렉토리 내의 mysite.log 로 지정한다.
maxBytes 는 로그파일의 최대크기이다. 5MB로 설정한다.
backupCount 는 유지할 로그파일의 갯수이다. 여기서는 우선 5개의 파일로 유지되도록 설정한다.
formatter 는 위에서 만들었던 standard 를 사용한다.
마지막으로 loggers 의 django 로거에 file 핸들러를 등록해주고 commit, push 한뒤 서버에 반영해준다.
또한, 서버환경과 로컬환경 모두에서 로그가 저장될 logs 디렉토리를 생성해줘야한다. 로컬 환경에서는 DEBUG 값이
True 이기 때문에 로그가 파일형태로 출력되지 않지만 디렉토리가 없으면 에러가 발생한다.
로그파일이 버전관리의 대상이 되지 않도록 gitignore 에 추가해준다.
이제 일부러 에러가 발생할 코드를 삽입하여 서버에 반영한 뒤 서버에 접속해보자
500 에러가 발생한 것을 확인할 수 있다. 이제 로그 파일을 확인해보자.
pybo/base_views.py 의 index 함수에서 3 / 0 으로 인해 ZeroDivisionERror 가 발생했음을 기록한 것을 볼 수 있다.
4. 로거 추가
이번엔 django 나 dajngo.server 와 같은 기존의 로거가 아닌 직접 만든 로거로 로그를 출력하는 방법을 알아보자.
pybo/base_views.py 를 위와 같이 수정한다. logging 모듈을 import 하여 pybo 라는 로거를 통해 원하는 레벨의
로그를 출력할 수 있다.
config/settings/base.py 에서 pybo 로거를 등록해준 뒤 서버에 반영시켜보자.
먼저 pybo 에 접속한 뒤에 로그를 확인해보면 출력한 로그가 제대로 쓰여진 것을 볼 수 있다.
※ logger = logging.getLogger('pybo') 에서 'pybo' 대신 __name__ 을 사용해도 __name__ 이 실행중인 모듈의
이름이고 현재 실행중인 파일은 pybo.views.base_views.py 이기 때문에 모듈명이 pybo가 되어 'pybo' 를 넣어준
것과 동일하게 동작한다.
from http://scala0114.tistory.com/126 by ccl(A) rewrite - 2021-10-16 00:01:20