Logging 모듈
Python에서 로그를 출력하기 위한 기본 라이브러리
이 글에서는 Logging 모듈 사용 방법을 간단하게 정리한다.
사용
logging 모듈을 import 한 후, 출력할 로그 메시지를 전달하여 사용할 수 있다.
import logging
logging.debug("debug message")
logging.info("info message")
logging.warning("warning message")
logging.error("error message")
logging.critical("critical message")
아무 처리도 하지 않고 로그 메세지를 출력한 결과는 아래와 같다.
실행 결과
debug, info level에 해당하는 메시지는 출력하지 않았음을 확인할 수 있다.
Log Level
메세지의 중요도와 심각한 정도를 구분하는 기준으로, 5개의 level이 기본으로 제공된다.
Level | 설명 |
DEBUG | 문제 해결에 필요한 세부 정보 |
INFO | 작업이 정상적으로 동작하고 있다는 확인 메세지 |
WARNING | 예상치 못한 일 또는 발생 가능한 문제점 명시 |
ERROR | 프로그램이 함수를 실행하지 못할 정도의 심각한 문제 |
CRITICAL | 프로그램이 동작하지 못할 정도의 심각한 문제 |
Log Level의 심각도를 오름차순으로 정렬하면 DEBUG - INFO - WARNING - ERROR - CRITICAL로 정렬되며, Python은 기본적으로 WARNING 수준의 메시지부터 출력한다.
즉, WARNING, ERROR, CRITICAL에 해당하는 메세지만 출력한다.
Logging 구성 요소
Logging 모듈은 크게 아래와 같은 구성 요소를 가지고 있다.
- Loggers : 애플리케이션 코드가 직접 사용할 수 있는 인터페이스 제공
- Handlers : Loggers에 의해 생성된 LogRecord를 처리하여 적절한 위치로 전달
- Filters : 출력되어야 하는 로그 필터링
- Formatters : LogRecord의 출력 형태 지정
로그 이벤트는 LogRecord 형태로 Loggers부터 Handlers, Formatters 순서로 전달된다. Flow chart는 아래와 같다.
Loggers
Logger는 아래 코드와 같이 getLogger() 함수를 통해 사용할 수 있다.
import logging
logger = logging.getLogger("<NAME>")
역할
- 로그 생성 method 제공
- 로그 레벨과 Logger에 적용된 filter를 바탕으로 처리해야 할 메세지 판단
- 로그 메세지에 부가 정보가 더해진 LogRecord 인스턴스를 적절한 Handler로 전달
특징
- name을 전달하면 해당 이름에 해당하는 Logger를, name을 전달하지 않으면 모든 logger의 부모에 해당하는 Root Logger를 반환한다.
- Logger의 level이 정해지지 않으면 부모 Logger의 level을 사용한다.
Logger 설정 함수
- Logger.setLevel() : 처리할 메시지의 최소 레벨 설정. (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
- Logger.addHandler(), Logger.removeHandler() : Handler 추가 또는 제거. 하나의 Logger는 여러 개의 Handler를 가질 수 있다.
- Logger.addFilter(), Logger.removeFilter() : Filter 추가 또는 제거
로그 생성 함수
- Logger.debug()
- Logger.info()
- Logger.warning()
- Logger.error()
- Logger.critical()
- Logger.exception() : Exception hadler 내에서만 사용 가능하며, stack trace 정보가 포함된 ERROR level의 로그 발생
- Logger.log()
Handlers
로그 메세지를 출력하는 역할을 한다. StreamHandler, FileHandler, RotatingFileHander, SocketHandler 등 다양한 종류(https://docs.python.org/3.7/howto/logging.html#useful-handlers)가 존재한다.
Handler 설정 함수
- Handler.setLevel() : 처리할 메시지의 최소 레벨 설정. Logger의 레벨과 다를 수 있으며, Logger에서 통과된 메시지가 Handler에서 통과되지 않을 수 있다.
- Handler.setFormatter() : Handler가 사용할 formatter 설정
- Handler.addFilter(), Handler.removeFilter() : filter 추가 또는 제거
StreamHanlder 사용 예시
import logging
logger = logging.getLogger("<NAME>")
logger.setLevel(logging.DEBUG)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
logger.info("INFO MESSAGE")
Formatter
출력되는 로그 메세지의 formatting에 관여한다.
생성 코드
formatter는 아래와 같이 생성할 수 있다.
import logging
logging.Formatter(
fmt = None, # 메시지 출력 형태. None일 경우 raw 메시지를 출력.
datefmt = None, # 날짜 출력 형태. None일 경우 '%Y-%m-%d %H:%M:%S'.
style = '%' # '%', '{', '$' 중 하나. `fmt`의 style을 결정.
)
format 정의 속성
속성 | format | 설명 |
asctime | %(asctime)s | 인간이 읽을 수 있는 시각 |
created | %(created)f | LogRecord가 생성된 시각 |
filename | %(filename)s | pathname의 file 이름 |
funcName | %(funcName)s | logging call을 포함하는 function 이름 |
levelname | %(levelname)s | 메세지의 log level |
lineno | %(lineno)d | logging call이 발생한 코드의 line |
module | %(module)s | filename의 모듈 이름 |
message | %(message)s | 메세지 |
name | %(name)s | logger 이름 |
pathname | %(pathname)s | full pathname |
thread | %(thread)d | thread ID |
threadName | %(threadName)s | thread 이름 |
위의 속성을 이용해 "로그 발생 시각 [LOG_LEVEL] 메시지"의 형식의 로그 메시지를 출력하게끔 설정할 수 있다.
import logging
logging.Formatter(
fmt="%(asctime)s [%(levelname)s] %(message)s",
datefmt = None,
style = '%'
)
활용
위에서 다뤘던 내용을 기반으로 원하는 로거를 생성하여 사용한다.
요구 사항
- INFO LEVEL 이상의 로그를 출력한다.
- 출력하는 모든 로그는 file로 저장한다. 즉, fileHandler를 사용한다.
- 로그 발생 시각, Log Level과 그 메세지를 출력한다.
코드
import logging
# Logger
logger = logging.getLogger("stu")
logger.setLevel(logging.DEBUG)
# Handler
file_handler = logging.FileHandler(filename="run.log")
file_handler.setLevel(logging.INFO)
# Formatter
formatter = logging.Formatter(
fmt="%(asctime)s [%(levelname)s] %(message)s",
datefmt=None,
style='%'
)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.info("info message")
logger.error("error message")
실행 결과
달리 파일 경로를 지정하지 않으면 프로젝트의 최상위 경로에 log 파일을 생성한다.
JSON 파일로 Logger 설정
다른 프로그램에서도 동일한 Logger를 사용할 수 있도록 즉, 재사용성을 위해 관련 설정은 json 또는 yaml 파일로 저장한 뒤 로드하여 사용하려고 한다.
설정 파일
{
"version": 1,
"formatters": {
"basic": {
"format": "%(asctime)s [%(levelname)s] %(message)s"
}
},
"handlers": {
"file_handler": {
"class": "logging.FileHandler",
"level": "INFO",
"formatter": "basic",
"filename": "run.log"
}
},
"root": {
"level": "DEBUG",
"handlers": ["file_handler"]
}
}
설정 파일 사용
import logging
import logging.config
import json
config = json.load(open('/LOGGER/CONF/PATH/logger.json'))
logging.config.dictConfig(config)
logger = logging.getLogger("<NAME>")
참고 문서
https://hwangheek.github.io/2019/python-logging/
https://greeksharifa.github.io/%ED%8C%8C%EC%9D%B4%EC%8D%AC/2019/12/13/logging/
https://snowdeer.github.io/python/2017/11/17/python-logging-example/