print()
를 통해 예외처리를 기록하고, sh파일을 실행할때 표준출력을 저장하는 방식(2>&1)
으로 로그를 남겼었다.
이 방식의 문제점은 복잡하고 긴 코드 속에서 정확히 언제 어떤 code line에서 예외가 발생했는지
를 찾기 힘들었다.
그리고 이러한 방식이 서버에서 내 프로세스를 모니터링할 때 큰 단점이라고 느꼈고..
그동안 귀찮아서 모두 print() 로 나름의 로그를 남기던 방식을 바꾸기로 결심했다.
그래서 공부하게 된 logging 모듈 !
logging
모듈은 진단 정보를 기록하기 위한 표준 라이브러리 모듈
import logging
log = logging.getLogger(__name__)
getLogger
를 통해 객체를 생성하고, __name__
에 원하는 로그 이름을 적어주면 된다.
아무것도 입력하지 않을 시, root
로그 생성
logging모듈은 심각도에 따라 5개의 level로 나누어 로깅 메시지를 출력한다.
자신이 정한 특정 레벨 이상부터만 콘솔창에 출력될 수 있도록 하는 역할
Level | Value | When to use |
---|---|---|
debug | 10 | (문제를 진단할 때) 자세한 정보 |
info | 20 | 예상대로 작동하는지 확인 |
warning | 30 | 예상치 못한 일이 발생했다는 표시, 작업은 정상적으로 진행 |
error | 40 | 프로그램이 일부 기능을 수행할 수 없음 |
critical | 50 | 프로그램 자체를 계속 실행할 수 없음 |
아무것도 설정하지 않을 시, default
= warning
따라서 warning
과 그 이상인 error
, critical
만 출력된다.
import logging
mylog = logging.getLogger('log')
mylog.setLevel(logging.DEBUG)
Handlers
: 로그 출력을 처리하여 지정된 위치로 보내는 역할 (file? or stream?)
StreamHandler
: 스트림(콘솔)에 로그 출력을 보냄FileHandler
: 파일로 로그 출력을 저장import logging
mylog = logging.getLogger('log')
mylog.setLevel(logging.DEBUG)
stream_handler = logging.StreamHandler()
mylog.addHandler(stream_handler)
file_handler = logging.FileHandler('test.log')
mylog.addHandler(file_handler)
스트림 핸들러와 파일 핸들러를 동시에 같이 설정할 수 있다.
Formatter
: 최종적으로 출력될 로그 메시지의 포맷을 설정
import logging
mylog = logging.getLogger('log')
#level 설정
mylog.setLevel(logging.DEBUG)
#Handler 설정
stream_handler = logging.StreamHandler()
mylog.addHandler(stream_handler)
file_handler = logging.FileHandler('test.log')
mylog.addHandler(file_handler)
#Format 설정
formatter = logging.Formatter('[%(asctime)s][%(funcName)s:%(lineno)s] %(message)s')
mylog.setFormatter(formatter)
asctime
: LogRecord가 생성된 시간 (%Y-%m-%d %H:%M:%S 형식)
funcName
: LogRecord가 발생한 함수의 이름
lineno
: LogRecord가 발생한 소스파일 내의 라인 번호
message
: 로그 메시지 내용
#SetLogger.json file
{
'version':1,
'formatters' : {
'default' : {
'format' : '[%(asctime)s][%(funcName)s:%(lineno)s] %(message)s',
'datefmt' : '%Y-%m-%d %H:%M:%S'
}
},
'handlers' : {
'file' : {
'level' :'DEBUG',
'class' : 'logging.FileHandler',
'filename' : 'debug.log',
'formatter': 'default'
}
},
'loggers' : {
'root': {
'level' :'DEBUG',
'handlers' : ['file']
}
}
}
딕셔너리 형태의 json파일로 자신의 환경에 맞게 설정을 해준 뒤,
import logging.config
import json
with open("SetLogger.json", "r") as f:
config = json.load(f)
logging.config.dictConfig(config)
logger = logging.getLogger()
logger.debug("debug message")
해당 코드를 실행하면, 파일에 디버그 메세지가 기록된다!
root
로거를 비롯하여 그 밑으로 상속되는 로거들에 대해서도 세팅해보고 그 구조에 대해 더 공부해봐야겠다.
level
별로 로그 파일을 다르게 기록하여 좀 더 구체적이고 편리한 디버깅이 가능하도록 코드를 수정해야겠다.
확실히 print()
로 기록하는 방식보다는 디버그하기 편하고, 모니터링이 수월해졌다.
linux 서버에서 로그파일을 실시간으로 보고 싶을 때
tail -n 1 -f logfilename
https://wikidocs.net/123324
https://wikidocs.net/84432
https://docs.python.org/3.7/howto/logging.html#when-to-use-logging
https://zephyrus1111.tistory.com/442
https://jh-bk.tistory.com/40