로깅 파헤치기 - python logging 모듈 사용기

코딩을 하다보면 단순히, 일시적으로 print를 찍어서 확인하면 '편하다', '아무 위치에 넣을 수 있다', '무언가를 처리하는데 신경쓰지 않아도 된다' 때문에 사용한다.

하지만 편했다 라는 말에 숨지않고 누군가와 같이 작업을 할 때 로그를 분류하고 관리의 필요성을 느끼게 되었다. 또한, 문제가 발생했을 때 원하는 포맷과 방식으로 처리하여 유용한 정보를 확인하고자 한다. 로그 주체 프로그램에 따라 다르겠지만, 프로그래머(?) 관점에서 원인 분석 용도에서 더 나아가 로그 데이터는 수집 목적에 따라 성능과 같은 품질 확보, 사용자 분석 지표, 마케팅 ROI 진단 및 효과 측정, 비즈니스 성과 진단에 사용되기도 하므로 기초적인 로그의 개념과 python logging 모듈 사용 방법에 짜집기 알아본다.


로그 레벨

프로그래밍 언어마다 로깅 라이브러리가 존재하며 일반적으로 다음과 같은 레벨로 나누어서 사용한다.

Level Description
DEBUG (주로 문제 해결을 할 때 필요한) 자세한 정보
INFO 작업이 정상적으로 작동하고 있다는 확인 메시지
WARNING 예상하지 못한 일이 발생하거나, 발생 가능한 문제점을 명시
ERROR 프로그램이 함수를 실행하지 못 할 정도의 심각한 문제
CRITICAL 프로그램이 동작할 수 없을 정도의 심각한 문제

 

로그를 남겨야 하는 상황은 다양한데 보통 고려되는 상황은 다음과 같다.

  • 일반적인 콘솔 혹은 파일 출력
  • 특정 정상 이벤트 발생 시 알림
  • 런타임중 경고가 필요한 상황
  • 예상된 exception 처리 상황

 

이 때 Warning인지 Info로 남길지는 본인 판단하에 결정하여 남기게 되는데, 어느 레벨까지, 어느 범위까지 의도된 상황인지 미리 생각하여 정의를 해두면 상황에 직면했을 때 좋다.


로깅 시 주의사항

  • 로그파일 크기 및 저장소 용량
  • 로그의 생명주기
  • 개인정보
  • 시스템 주요 정보

로그를 설계할 때 시행착오에 대한 좋은 글이 있어 소개한다.

https://zzsza.github.io/data/2021/06/13/data-event-log-definition/

 

데이터 로그 설계, 데이터 로깅, 이벤트 로그 설계, 데이터 QA의 모든 것

이벤트 데이터 로그 설계, 데이터 로그 설계, 데이터 로깅, 데이터 QA에 대해 작성한 글입니다 키워드: 데이터 로깅, 데이터 로깅이란, 데이터 로깅 시스템, Firebase event logging, 이벤트 로그 설계,

zzsza.github.io

 

구현 전 체크사항

  • 로그 데이터 아키텍쳐 혹은 관련 문서 유무 확인
  • 로그 데이터 활용 계획 및 지표
  • 로그 저장 방식의 효율성
  • 데이터 보는 방법과 권한. tracking plan
  • 로깅 가이드 문서(이벤트명, 세부 파라미터, 네이밍 룰 등)
  • 로그파일이 저장되는 저장소(DB or File) 용량에 맞춰 파일 크기를 정해 생성 시점을 명확하게 수립
  • ex)파일로 저장하는 경우 덮어쓸지, 용량을 넘으면 새로운 파일로 작성할지, 압축 등
  • 중요한 개인정보 및 시스템 정보를 노출되어서는 안된다. 로깅 메시지에 포함되지 않도록 주의
  • 생명주기(수집, 저장, 분석, 폐기)

python logging을 이제 사용해보자!

로깅 사용해보기

Point Keyword

  • logger object
  • Handler
  • Formatter

logger

부모, 자식 로거로 여러 개의 로거를 생성할 수 있다. 로그를 핸들러로 전달.

warning log level이 default

root logger를 사용하기보다 클래스나 모듈마다 별도의 로거를 사용하는 것을 권장

import logging
#getlogger('원하는 로거명')
rootlogger = logging.getlogger()
mylogger = logging.getlogger('my')

 

Handler

콘솔, 파일 출력, 이메일 전송, 외부 로깅 서비스로 전달 등 record한 내용을 원하는 방법에 따라 처리(StreamHandler, FileHandler, NullHandler, RotatingFileHandler, SocketHandler, SysLogHandler, SMTPHandler, MemoryHandler...) https://docs.python.org/3/library/logging.handlers.html 참조

stream_handler = logging.StreamHandler()

#file 저장 시 사용. 로그 설계에 따라 적절한 file 관련 handler 사용 필요
file_handler = logging.FileHandler(filename='zxcv.log', encoding='utf-8')

#1024bytes를 넘으면 기록중인 파일의 이름을 1로 변경하고 새로운 log 파일 생성
rotating_file_handler = RotatingFileHandler(path,mode='a',maxBytes=1024,backupCount=3)

 

Formatter

#입력 parameter는 여러가지 존재
formatter = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s")

++FileHandler 사용을 위해 log 디렉터리 생성

try:
    if not os.path.isdir('./log'):
        os.mkdir('./log')
except Exception as e:
    print(e)

Formatter attribute


통합

logger = logging.getLogger()

log_dir = 'log'
log_fname = 'debug.log'

#fomatter 생성
formatter = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s")

#handler 생성
#stream_handler = logging.StreamHandler()
# file_handler = logging.FileHandler(filename='zxcv.log', encoding='utf-8')
rotating_file_handler = RotatingFileHandler(path,mode='a',maxBytes=1024,backupCount=3) #1024bytes를 넘으면 기록중인 파일의 이름을 1로 변경하고 새로운 log 파일 생성
rotating_file_handler.setFormatter(formatter)

#logger에 원하는 handler 추가
logger.addHandler(rotating_file_handler)

#set the log level
# file_handler.setLevel(logging.INFO)
# stream_handler.setLevel(logging.ERROR)

#set the format to handler
# file_handler.setFormatter(formatter)
# stream_handler.setFormatter(formatter)

# logger.addHandler(file_handler)

def hi():
    print('hi')
    logger.warning('hihi func')

 

결과

RotatingFileHandler 방식로 ./log/debug.log가 생성

log level을 따로 설정하지 않아 root의 level인 warning으로 표시

 

Logging flow 정리


++깊게 파헤칠 때 생각거리
멀티쓰레드 환경에서 (아마)파일 디스크립터가 달라 파일 접근 시 OS에 따라 문제가 발생할 수 있다.
윈도우즈에서 새 파일로 넘어갈 때, 이름 변경 등 꼬이므로 멀티 프로세스 큐 혹은 QueueHandler를 이용해 하나로 모아서 파일에 쓰게 하는 방식으로 쓴다.
파일 삭제 가능 여부가 다르다

 


마치며

QA할때 개발자가 로그를 너무 중구난방하게 작성하였었고,

프로그램이 터지는데 정작 중요한 root cause를 찾는데 도움은 되지 않았고...

했던 경험이 있어 재미있게 찾아보고 구현해봤는데, 현업에서 설계를 하라고 맡긴다면 머리가 터질 것 같다. 연습사마 한 파일에서 실습했지만 별도의 config 파일로 작성하고, 이걸 또 문서화하고... 만약에 게임 회사라면 단순 디버깅 수준의 로그가 아니라 활용 가치가 있게 해줘야 되고... 우욱

추가로 관련 읽을거리를 던지며 끝

https://sematext.com/guides/log-management/#popular-log-management-topicshttps://www.slideshare.net/jeongsangbaek/ss-80795259