[시리즈] 파이썬 로깅 Python Logging
안정적인 서비스 운영을 위한 파이썬 로깅 시스템 설계
Handler(핸들러)
역할
- Logger 로부터 받은 로그 레코드를 실제 출력 위치로 전송하는 역할을 한다.
- 하나의 Logger에 1개 이상의 Handler를 할당할 수 있다.
- 개인적으로 로깅 기능을 구축할 때, 가장 중요한 역할을 하는 요소라고 생각한다.
주요 기능
- 출력 대상 결정 : 콘솔(스트림), 파일, 이메일, HTTP 서버 등 다양한 대상으로 로그 전송
- 포매터 연결 : Formatter 객체를 연결해 로그 레코드를 원하는 문자열 형식으로 변환한다.
- 레벨 검사 : 핸들러 자체의 레벨이 설정되어 있어, 해당 레벨 이하의 로그 레코드는 처리하지 않는다.
- 개발자가 직접 핸들러가 처리할 로직을 구성하여 새로 만들 수도 있다.
핸들러의 종류
| 종류 | 설명 | 선언된 파일 |
|---|---|---|
| Handler | 여러 핸들러를 추상화한 클래스(인터페이스) | logging.__init__.py |
| StreamHandler | 콘솔(sys.stderr 또는 sys.stdout)에 출력 | logging.__init__.py |
| FileHandler | 지정된 파일에 출력(기록) | logging.__init__.py |
| NullHandler | 모든 로그 레코드를 처리하지 않고 단순히 버리는(=아무것도 하지 않는) 역할 | logging.__init__.py |
| RotatingFileHandler | 파일의 크기가 일정 수준을 넘으면 자동으로 파일을 교체(로테이션) | logging.handlers.py |
| TimedRotatingFileHandler | 시간의 흐름에 따라 자동으로 파일을 교체(로테이션) | logging.handlers.py |
| SMTPHandler | 로그를 메일로 전송 | logging.handlers.py |
| SocketHandler | TCP/IP 소켓을 통해 네트워크로 로그 전송 | logging.handlers.py |
| DatagramHandler | UDP를 통해 네트워크로 로그 전송 | logging.handlers.py |
| HTTPHandler | HTTP GET 또는 POST 요청을 통해 로그 전송 | logging.handlers.py |
| SysLogHandler | Unix/Linux 표준 로깅 메커니즘을 사용, syslog서버로 전송도 가능 | logging.handlers.py |
| NTEventLogHandler | Windows 운영체제 전용, 로그를 Windows 이벤트 뷰어에 기록 | logging.handlers.py |
| WatchedFileHandler | 파일이 외부에서 삭제되거나 리네임될 때 자동으로 다시 열어 로깅을 계속함 | logging.handlers.py |
| BufferingHandler | 로그 레코드를 메모리 버퍼에 쌓아둠 | logging.handlers.py |
| MemoryHandler | BufferingHandler와 유사하지만, 특정 레벨의 로그가 들어올 때만 플러시 | logging.handlers.py |
| QueueHandler | 로그 레코드를 queue.Queue 객체로 넣어 처리 | logging.handlers.py |
Handler 사용하기
사용 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import logging
def about_handler():
# Logger 인스턴스 생성 및 설정
logger_name = "about_handler"
logger = logging.getLogger(logger_name)
logger.setLevel(logging.INFO)
# StreamHandler 인스턴스 생성
stream_handler = logging.StreamHandler() # 핸들러의 종류를 정할 수 있다.
stream_handler.setLevel(level = logging.INFO) # 핸들러가 처리할 최소 로그 레벨을 설정한다.
formatter = logging.Formatter() # Formatter 생성 : 추후에 다룸
stream_handler.setFormatter(formatter) # Formatter 할당
# FileHandler 인스턴스 생성
file_handler = logging.FileHandler(
filename="logs/handler_log.log",
mode="a",
encoding="utf-8"
)
file_handler.setLevel(logging.ERROR) # 핸들러마다 각기 다른 로그 레벨을 설정할 수 있다.
new_formatter = logging.Formatter() # Formatter 생성 : 추후에 다룸
file_handler.setFormatter(new_formatter) # 핸들러마다 각기 다른 포매터를 설정할 수 있다.
# addHandler : Logger 에 Handler 할당
# 하나의 Logger 에 다수 개의 Handler 를 할당할 수 있다.
logger.addHandler(stream_handler)
logger.addHandler(file_handler)
# 로그 레코드 생성 및 핸들러에 전달
logger.info("info message")
logger.error("error message")
if __name__ == "__main__":
about_handler()
Handler 의 메서드
| 메서드 | 설명 |
|---|---|
setLevel() |
핸들러가 처리할 가장 최소릐 로그 레벨을 설정한다. |
setFormatter() |
핸들러에 인입된 로그 레코드를 로그 메시지로 변환할 포매터를 설정한다. |
addFilter() |
핸들러에 필터를 추가한다. |
removeFilter() |
핸들러에 필터를 제거한다. |
Handler 생성 및 사용 흐름
- 1개 이상의 로거가 생성되어있다는 전제 하에
| No | 흐름 | 설명 |
|---|---|---|
| 1 | 핸들러 생성 | 로거가 만든 로그 레코드를 전송하는 핸들러를 생성하고, 로그레벨 등 관련 설정을 수행한다. |
| 2 | 포매터 생성 | 로그 레코드를 지정 형식의 로그 메시지로 만드는 포매터를 생성하고, 관련 설정을 수행한다. |
| 3 | 포매터 할당 | 핸들러에 포매터를 할당한다. |
| 4 | 핸들러 할당 | (생성되어있는)로거에 핸들러를 할당한다. |
Logger 와 Handler 의 로그 레벨에 따른 처리
- 위 사용 예시에서 생성된 로그 메시지에 대해서는 아래와 같이 처리될 것이다.
| Logger | Handler | Method | 로그 레코드 생성 및 핸들러로 전달 | 로그 메시지 전송 |
|---|---|---|---|---|
| DEBUG | ERROR | logging.info() | O | X |
| DEBUG | ERROR | logging.error() | O | O |
- 더 많은 경우의 수
| Logger | Handler | Method | 로그 레코드 생성 및 핸들러로 전달 | 로그 메시지 전송 |
|---|---|---|---|---|
| ERROR | DEBUG | logging.debug() | X | X |
| DEBUG | DEBUG | logging.info() | O | O |
| INFO | WARNING | logging.info() | O | X |
Reference
https://docs.python.org/3/library/logging.html
https://docs.python.org/ko/3/howto/logging.html
Comments