파이썬에서의 로깅
logging 라이브러리
기초 사용법
  - (1) 
import logging 을 통해 표준 라이브러리를 임포트한다. 
  - (2) 
logging.getLogger() 를 이용해 로거 인스턴스를 생성한다. 
  - (3) 처리할 로그 레벨, 수행할 작업(파일 기록/스트림 등), 기록할 파일명 등 설정을 수행한다.
 
  - (4) 
logger.info(message) 와 같은 함수를 이용해 로깅을 수행한다. 
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
  | import logging  # logging 표준 라이브러리를 사용한다.
def logging_basic():
    
    # 로거 객체를 생성
    logger_name = "logging_basic"             # 로거 이름 설정
    logger = logging.getLogger(logger_name)
    # 로깅 설정
    filename = "logs/logging_basic_log.log"    # 로그를 기록할 파일 경로 설정
    logging.basicConfig(        
        filename=filename,      # 로그를 기록할 파일 경로
        level=logging.DEBUG,    # 로거가 처리할 최소 로그 레벨
        encoding='utf-8'        # 파일 인코딩
        )
        # basicConfig : 간단한 기본 로깅 설정
        # filename 을 지정하면 FileHandler 로 파일에 로그를 기록하며,
        # filename 을 지정하지 않으면 StreamHandler 로 콘솔에 로그를 출력한다.
    # 로그 메시지를 기록한다.
    logger.info("info 메시지입니다.")
    logger.debug("debug 메시지입니다.")
    logger.warning("warning 메시지입니다.")
    logger.error("error 메시지입니다.")
    
if __name__ == "__main__":
    logging_basic()
 | 
 
로그 레벨
  - 로그 레벨은 기본적으로 
NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL 6단계로 구성된다. 
  - 이들은 각각 정수값으로 표현되는데, 순서대로 0, 10, 20, 30, 40, 50 이다.
 
  - 여기에 사용자가 커스터마이징 하여 새로운 로그 레벨을 넣을 수도 있다.
 
  - 로그 레벨은 아래 세 부분에서 사용된다.
 
  - (1) 로거가 처리할 최소의 로그 레벨
 
  - (2) 핸들러가 처리할 최소의 로그 레벨
 
  - (3) 로그 메시지의 로그 레벨
 
  - 로거 또는 핸들러는, 자신에게 설정된 로그 레벨 미만의 로그는 처리하지 않는다.
 
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
from logging import LogRecord
def log_level_test():
    # 로거 객체를 생성
    logger_name = "log_level"
    logger = logging.getLogger(logger_name)
    # 로깅 설정
    filename = "logs/log_level_log.log"
    logging.basicConfig(filename=filename,
                        level=logging.INFO, # 로거가 처리할 최소의 로그 레벨을 INFO 로 정함
                        encoding='utf-8')
    # 로그 레벨은 기본적으로 6개의 단계로 이루어져 있다.  
    # 그리고 이들은 정수값을 가지고 있다.
    # logging.__init__.py 파일에서 자세하게 살펴볼 수 있다.  
    """
    CRITICAL = FATAL = 50
    ERROR = 40
    WARNING = WARN = 30
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    """
    # 로그 메시지를 기록한다.
    # 설정한 레벨 미만의 로그는 기록되지 않는다.
    logger.debug("debug 메시지입니다.")
    logger.info("info 메시지입니다.")
    logger.warning("warning 메시지입니다.")
    logger.error("error 메시지입니다.")
        
if __name__ == "__main__":
    log_level_test()
 | 
 
  - 아래는 로그가 저장된 log_level_log.log 파일이다.
 
  - 로거의 로그 레벨인 
INFO 미만인 logger.debug()를 통해 보내진 로그메시지는 기록되지 않은 것을 볼 수 있다. 
1
2
3
4
  | # log_level_log.log
INFO:log_level:info 메시지입니다.
WARNING:log_level:warning 메시지입니다.
ERROR:log_level:error 메시지입니다.
  | 
 
파일에 로깅하기 - 편집 모드
  - 파일에 로깅할 때는 w(쓰기), a(추가), r(읽기) 세 가지 모드(mode) 가 존재한다.
 
  - 모드는 로거 안의 파일 핸들러(추후에 소개)를 선언할 때 설정해줄 수 있다.
 
  w(쓰기) : 로그 파일을 새로 쓴다. 기존의 내용이 사라지니 주의! 
  a(추가) : 기존의 내용에 이어서 로그를 추가한다. 
  r(읽기) : 읽기 전용으로, 로깅에 사용할 수 없다. 오류가 발생하니 주의! 
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  | import logging  # logging 표준 라이브러리를 사용한다.
def logging_to_file():
    
        # 로거 객체를 생성
    logger_name = "log_to_file"
    logger = logging.getLogger(logger_name)
    logger.propagate = False # 전파 방지
    # 로깅 설정
    filename = "logs/log_to_file_log.log"
    logging.basicConfig(filename=filename,
                        level=logging.INFO,
                        encoding='utf-8')
    """
    파일에 로그를 작성할 때에는 "편집 모드" 를 지정할 수 있다.
    편집모드는 w(쓰기), a(추가), r(읽기) 세 가지가 있다.
    """
    
    # 기본 편집 모드는 a(추가) 이다.
    logger.info("file에 로깅하는 첫 메시지입니다.")
    logger.info("file에 로깅하는 두 번째 메시지입니다.")
    with open(filename, 'r') as f:
        print(f.readlines())
    
    # 편집 모드를 w(쓰기)로 하면 -> 이전의 내용이 없어지고, 새로 쓰여진다.
    logger.handlers.clear()
    file_handler = logging.FileHandler(filename=filename, mode='w',encoding='utf-8')
    file_handler.setLevel(logging.INFO)
    logger.addHandler(file_handler)
    logger.error("w(쓰기 모드)로 로깅한 새로운 로그입니다.")
    with open(filename, 'r') as f:
        print(f.readlines())
    
    # 편집 모드를 a(추가)로 바꾼다면 -> 이전의 내용에 이어서 로그가 작성된다.
    logger.handlers.clear()
    file_handler = logging.FileHandler(filename=filename, mode='a',encoding='utf-8')
    file_handler.setLevel(logging.INFO)
    logger.addHandler(file_handler)
    logger.error("a(추가 모드)로 로깅한 추가 편집 메시지입니다.")
    with open(filename, 'r') as f:
        print(f.readlines())
    
    # 로깅 설정을 "읽기"로 바꾼다면
    logger.handlers.clear()
    file_handler = logging.FileHandler(filename=filename, mode='r', encoding='utf-8')
    file_handler.setLevel(logging.INFO)
    logger.addHandler(file_handler)
    logger.error("읽기 전용 메시지입니다.") # 에러 발생 : io.UnsupportedOperation: not writable
if __name__ == "__main__":
    logging_to_file()
 | 
 
메시지 포맷 정하기 (간단)
  - 로그 메시지의 포맷을 정할 수 있다.
 
  - 자세한 내용은 추후 포매터(Formatter) 부분에서 다루도록 한다.
 
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
  | import logging  # logging 표준 라이브러리를 사용한다.
def change_message_format():
    # 로거 객체를 생성
    logger_name = "message_format"
    logger = logging.getLogger(logger_name)
    # 로깅 설정
    filename = "logs/message_format_log.log"
    logging.basicConfig(filename=filename, level=logging.INFO, encoding='utf-8')
    # 기본적인(basicConfig) 메시지 포맷 테스트
    logger.error("기본적인(basicConfig) 메시지 포맷 테스트")
    
    # 포맷 변경
    # 자세한 포맷 작성법은 logging.__init__.py 의 Formatter 클래스 부분에서 확인 가능
    logger.propagate = False # 전파 방지
    logger.handlers.clear()
    new_format = logging.Formatter("%(lineno)s %(levelname)s - %(process)s %(filename)s %(message)s") # 새로운 포맷
    file_handler = logging.FileHandler(filename=filename, mode='a', encoding='utf-8')
    file_handler.setLevel(logging.INFO)
    file_handler.setFormatter(new_format) # 포맷 설정
    logger.addHandler(file_handler)
    logger.error("로깅 포맷 설정을 바꿔보았습니다.")
    
if __name__ == "__main__":
    change_message_format()
 | 
 
1
2
  | ERROR:message_format:기본적인(basicConfig) 메시지 포맷 테스트
24 ERROR - 8912 logging_04_message_format.py 로깅 포맷 설정을 바꿔보았습니다.
  | 
 
날짜 표시 형식 바꾸기
  - 로그 생성 날짜(asctime) 의 표현 방식을 
datefmt 파라미터로 지정할 수 있다. 
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
  | import logging  # logging 표준 라이브러리를 사용한다.
import time
def log_datetime():
    # 로거 객체를 생성
    logger_name = "datetime_format"
    logger = logging.getLogger(logger_name)
    # 로깅 설정
    filename = "logs/datetime_format_log.log"
    logging.basicConfig(filename=filename, level=logging.INFO, encoding='utf-8',
                        format="%(asctime)s - %(message)s")
    # 기본적인 시간 표현
    logger.info("기본적인 datetime format 입니다.")
    
    # 시간 표현 방법 변경
    logger.propagate = False
    new_format = logging.Formatter(fmt="%(asctime)s - %(message)s",
                                   datefmt="%Y년 %m월 %d일 %H시 %M분 %S초") # 새로운 포맷
    file_handler = logging.FileHandler(filename=filename, mode='a', encoding='utf-8')
    file_handler.setLevel(logging.INFO)
    file_handler.setFormatter(new_format) # 포맷 설정
    logger.addHandler(file_handler)
    logger.error("변경된 datetime format 입니다.")
    
if __name__ == "__main__":
    log_datetime()
 | 
 
1
2
  | 2025-11-03 22:22:21,510 - 기본적인 datetime format 입니다.
2025년 11월 03일 22시 22분 21초 - 변경된 datetime format 입니다.
  | 
 
Reference
https://docs.python.org/3/library/logging.html
https://docs.python.org/ko/3/howto/logging.html
        
      
      
      
      
  
     
    
      
    
  
Comments