Logger(로거)

역할

  • 역할 : 로깅 시스템의 진입점이자 구심점이 되는 객체. 개발자가 로깅 메시지를 생성하고 관리하는 역할을 한다.

주요 기능

  • 로깅 메시지 생성 : logger.debug(), logger.error() 등 메서드를 사용해 로그 레코드를 생성한다.
  • 레벨 검사 : 자신에게 설정된 로그 레벨 미만의 메시지는 처리하지 않고 무시한다.
  • 핸들러 전달 : 생성 및 레벨 검사에서 통과된 로그 레코드를 하나 이상의 Handler 에 전달한다.
  • 계층 구조 : 로거는 계층적 구조를 가질 수 있으며(e.g. main.sub) 메시지는 기본적으로 상위 로거로 전파(propagation) 된다.

로거 사용하기

사용 예시

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
import logging

def about_logger():
    
    # 로거 인스턴스를 생성
    # getLogger 는 이름이 제공되면 해당 이름을 가진 로거 인스턴스를 반환한다.
    # 그렇지 않으면 루트 인스턴스를 반환한다.
    # 서로 다른 이름의 로거는 각기 다른 메모리 주소를 가진다.
    logger_name = "about_logger"
    logger = logging.getLogger(logger_name)
    
    # setLevel
    # 로거가 처리할 가장 낮은 심각도의 로그 레벨을 지정
    # 로그 레벨은 logging.INFO 처럼 쓰거나, 로그 레벨에 해당하는 정수값을 넣어도 된다. (아래 둘은 동일)
    logger.setLevel(logging.INFO)
    logger.setLevel(20)
    
    # addHandler
    # 핸들러를 로거에 할당한다.
    # Hnadler에 대해서는 Handler 소개 글에서 자세히 다루겠다.
    handler = logging.StreamHandler()
    handler.setLevel(level = logging.INFO)
    formatter = logging.Formatter()
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    
    # 로그 레코드 생성 및 핸들러에 전달
    # debug(), info(), error().. 등의 메서드를 통해 로그 레코드를 생성하고, 핸들러에 전달한다.  
    # 각각의 메서드는 자신의 이름과 동일한 레벨의 로그 레벨을 가진 로그 레코드를 만들게 된다.  
    # 예를 들어, debug() 메서드는 logging.DEBUG 레벨의 로그 레코드를 만든다.  
    logger.debug("debug message")
    logger.error("error message")

로거 생성 흐름

No 흐름 설명
1 로거 생성 로깅을 수행할 로거를 생성하고, 로그레벨 등 관련 설정을 수행한다.
2 핸들러 생성 로거가 만든 로그 레코드를 전송하는 핸들러를 생성하고, 로그레벨 등 관련 설정을 수행한다.
3 포매터 생성 로그 레코드를 지정 형식의 로그 메시지로 만드는 포매터를 생성하고, 관련 설정을 수행한다.
4 포매터 할당 핸들러에 포매터를 할당한다.
5 핸들러 할당 로거에 핸들러를 할당한다.

로거의 메서드

메서드 설명
logger.addHandler(handler) 핸들러를 로거에 할당한다.
logger.debug(m) logging.DEBUG 레벨의 로그 레코드를 생성한다.
logger.info(m) logging.INFO 레벨의 로그 레코드를 생성한다.
logger.warning(m) logging.WARNING 레벨의 로그 레코드를 생성한다.
logger.error(m) logging.ERROR 레벨의 로그 레코드를 생성한다.
logger.critical(m) logging.CRITICAL 레벨의 로그 레코드를 생성한다.

로거 이름에 따른 인스턴스 구분

  • 로거는 logger_name 에 따라 각기 다른 인스턴스로 구분된다.
  • 각각의 인스턴스는 각각의 메모리 주소를 갖는다.
1
2
3
4
5
6
7
8
9
10
11
12
# ... 위 코드 생략

# logger 이름에 따른 인스턴스 생성
# logger 인스턴스는 "이름"에 따라 생성되며 관리된다.
# 이름이 다르면 서로 다른 로거 인스턴스이다.
# 서로 다른 인스턴스는 당연히 서로 다른 메모리 주소를 갖는다.
print(f"{logger_name} 로거의 id          : {id(logger)}")
new_logger_name = "new_logger"
logger = logging.getLogger("new_logger")
print(f"{new_logger_name} 로거의 id      : {id(logger)}")
logger = logging.getLogger(logger_name)
print(f"다시 돌아온 {logger_name} 로거의 id : {id(logger)}")
1
2
3
4
# 출력 결과
about_logger 로거의 id          : 4364629968
new_logger 로거의 id            : 4364864304
다시 돌아온 about_logger 로거의 id : 4364629968

Reference

https://docs.python.org/3/library/logging.html
https://docs.python.org/ko/3/howto/logging.html

Comments