JustDoEat
백엔드 로그를 찍어보자 본문
api에 간단한 로그를 찍어보자!
elk를 연동하던중.. 프론트엔드 쪽 로그가 아닌 백엔드쪽 로그를 만들어서 elasticsearch에 보내보고 싶어서 시작을 하였지만, 아래 방식처럼 찍으면 elasticsearch에서 인식을 못한다는걸 알아버렸다. logstash에 필터를 걸어도 계속 인식을 못하고.. 추가로 docker도 말썽을 부리고 미치겠다.. 현제 테스크가 마땅히 없어서 죽어라 4일째 해보고있는데 내가 바보인건지 elk 연동을 못시키겠다.
그래서 아래는! logging.filehandler를 이용해서 간단하게 로그를 찍는법을 기록해보겠다.
설정
settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False, # 디폴트 : True, 장고의 디폴트 로그 설정을 대체. / False : 장고의 디폴트 로그 설정의 전부 또는 일부를 다시 정의
'formatters': { # message 출력 포맷 형식
'verbose': {
'format': "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
'datefmt': "%d/%b/%Y %H:%M:%S"
},
'simple': {
'format': '%(levelname)s %(message)s'
},
},
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': os.path.join(BASE_DIR, 'logs') + "/log", # message가 저장될 파일명(파일명 변경 가능)
'formatter': 'verbose'
},
'member_file': {
'level': 'INFO',
'class': "logging.FileHandler",
'filename': os.path.join(BASE_DIR, 'logs') + "/member_log"
},
'calendar_file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': os.path.join(BASE_DIR, 'logs') + "/calendar_log"
},
'diary_file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': os.path.join(BASE_DIR, 'logs') + "/diary_log"
},
'static_file':{
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': os.path.join(BASE_DIR, 'logs') + "/static_log"
},
},
'loggers': {
'django': {
'handlers': ['file'], # 'file' : handler의 이름
'propagate': True,
'level': 'DEBUG', # DEBUG 및 그 이상의 메시지를 file 핸들러에게 보내줍니다.
},
'member': { # Project에서 생성한 app의 이름
'handlers': ['member_file'], # 다른 app을 생성 후 해당 app에서도
'propagate': True,
'level': 'INFO', # 사용하고자 할 경우 해당 app 이름으로
},
'harucalendar': { # Project에서 생성한 app의 이름
'handlers': ['calendar_file'], # 다른 app을 생성 후 해당 app에서도
'propagate': True,
'level': 'INFO', # 사용하고자 할 경우 해당 app 이름으로
},
'diary': { # Project에서 생성한 app의 이름
'handlers': ['diary_file'], # 다른 app을 생성 후 해당 app에서도
'propagate': True,
'level': 'INFO', # 사용하고자 할 경우 해당 app 이름으로
},
'static': { # Project에서 생성한 app의 이름
'handlers': ['static_file'], # 다른 app을 생성 후 해당 app에서도
'propagate': True,
'level': 'INFO', # 사용하고자 할 경우 해당 app 이름으로
},
# 좌측 코드를 추가 작성해서 사용
}
}
설명
이부분을 로그를 찍기위한 settings.py 설정이고, 사용법은 오른쪽 주석과 아래 예시들을 참고하면 좋을거같다.
class:
핸들러의 종류를 정의하는 부분,
여기서는 logging.FileHandler만 사용하겠다.
logging.FileHandler:
파일에 로그를 기록하는 핸들러이다.
이 외 핸들러
StreamHandler: 콘솔에 직접 로그를 출력하는 핸들러
TimedRotatingFileHandler: 시간 주기에 따라 로그 파일을 자동으로 백업하는 핸들러.
SMTPHandler: 이메일로 로그를 보내는 핸들러.
SysLogHandler: 시스템 로그로 로그를 전송하는 핸들러.
등등이 있다.
filename: 파일 핸들러를 사용할 때 로그를 저장할 파일의 경로와 이름을 지정합니다.
os.path.join(BASE_DIR, 'logs') + "/member_log"
BASE_DIR에 'logs' 폴더를 만들고 그 안에 'member_log' 파일을 만든 다음, 그 파일에 로그를 기록하라는 의미입니다.
views.py
import logging
from datetime import datetime
logger = logging.getLogger(__name__)
설명 및 적용예시
logger = logging.getLogger(__name__)
logging객체를 생성 하는거고, 이 객체의 이름은 현제 모듈의 이름을 가진다는 의미이다.
예를들면 member라는 이름을 가진 디렉터리에 views.py에 위 코드를 적어주게 되면 member이라는 이름을 가진 로깅 객체가 생성이 된다.
이어서 settings.py를 다시 보자
settings.py
'loggers': {
'''
'member': { # Project에서 생성한 app의 이름
'''
'harucalendar': {
'''
'diary': { # Project에서 생성한 app의 이름
'''
settings.py 부분을 보면 logger 아래 부분에 보면 member, harucalendar, diary 이런식으로 이름을 정해주는데
이 이름은 말 그대로 내가 작업하고 있는 app의 디렉터리 이름을 적어주었었는데 위에 설명한 로깅객체가 이름을 바탕으로 자신에게 맞는부분으로 가서 실행이 되는것이다.
그럼 이제 views.py에 가서 로그를 찍어보겠다.
members/view.py
class SignUpView(APIView):
@swagger_auto_schema(
request_body=PostSignupRequestSerializer,
responses={"201": PostSignupResponseSerializer}
)
def post(self, request):
client_ip = request.META.get('REMOTE_ADDR', None)
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
'''코드생략'''
logger.info(f'{client_ip}-[{current_time}] "POST", "/members" 201 회원가입 성공 ')
return Response(response_data, status=201)
작성을 해준 후 해당 api를 실행을 해주면 아래 내가 설정한 파일에 로그가 찍히는걸 볼 수 있다.