본문 바로가기
Python/Common

[Python] Logging 모듈을 이용하여 Log 생성하는 법

by jiyoon_92 2022. 6. 16.
반응형

python

 

오늘은 프로그램 배포 전 필수 요소인 Log를 생성하는 걸 알아보자.

*보통 Log는 프로그램 사용 시 에러가 났을 때 세세히 남겨 놓을수록 어느 부분에서 에러가 났는지 파악하기 쉽다. 

Logging, Datetime 모듈 Import하기

Logging 모듈은 기본적으로 내장되어 있으므로 아래와 같이 Import 하여 사용하면 된다. 보통 Log를 남길 시엔 날짜와 시간을 남기므로 Datetime 모듈도 import 해준다.

import logging
from datetime import datetime

Logger를 전역으로 생성하여 사용하기 (코드)

다른 파일 및 클래스에서도 같은 Log를 사용하게 하기 위해 LoggerFactory를 만들어 다음과 같이 코드를 작성한다.

반응형
import logging
from datetime import datetime
import os

class LoggerFactory(object) :
    _LOGGER = None
    
    @staticmethod
    def create_logger() :
        #루트 로거 생성
        LoggerFactory._LOGGER = logging.getLogger()
        LoggerFactory._LOGGER.setLevel(logging.INFO)
        #log 폴더 없을 시 생성
        if (os.path.exists('./log') == False) :
            os.makedirs('./log')
        #로그 포맷 생성
        formatter = logging.Formatter('[%(asctime)s][%(levelname)s|%(filename)s-%(funcName)s:%(lineno)s] >> %(message)s')    
        #핸들러 생성
        stream_handler = logging.StreamHandler()
        stream_handler.setFormatter(formatter)
        file_handler = logging.FileHandler('./log/' + datetime.now().strftime('%Y%m') +'.log')
        file_handler.setFormatter(formatter)
        LoggerFactory._LOGGER.addHandler(stream_handler)
        LoggerFactory._LOGGER.addHandler(file_handler)
    @classmethod
    def get_logger(cls) :
        return cls._LOGGER

@staticmethod는 전역 함수 선언 시 사용되며 다른 class 및 파일에서도 호출할 수 있다. 프로그램 시작 시 main() 함수 안에서 create_logger()를 호출하여 logger를 생성해준다. 이때 logging.getLogger()를 호출하면 Root Logger를 가져올 수 있으며 기본 로그 레벨은 INFO로 설정했다.


Logging Level(로깅 레벨) 설정

logger.setLevel(level=level)로 설정한다. 설정된 레벨 외의 값을 입력하여 커스텀하게 사용할 수 도 있다. (ex : CUSTOM = 15)

LoggerFactory._LOGGER.setLevel(logging.INFO)
CRITICAL = 50
ERROR = 40
WARNING = 30
INFO = 20
DEBUG = 10
NOTSET = 0

아니면 레벨을 설정하지 않고 바로바로. error(msg=message) ,. info(msg=message),. debug(msg=message) 이런 식으로 바로 레벨에 맞는 로그를 남길 수도 있다.


Formatter로 로그 포맷 설정

Formatter를 이용하면 기록될 로그의 형식을 기호에 맞게 설정하여 사용할 수 있다. 막일로 값을 받아 작성할 수는 있지만 내장되어있는 style 매개변수를 참조하여 작성하였다. (시간, 로그 레벨, 파일명, 함수, 코드 라인 번호, 메시지 순)

참조 :https://docs.python.org/ko/3/library/logging.html#formatter-objects

formatter = logging.Formatter('[%(asctime)s][%(levelname)s|%(filename)s-%(funcName)s:%(lineno)s] >> %(message)s')

Logger에 Handler 생성하여 추가하기

StreamHandler를 통해 쉽게 터미널 창에 나타내거나 FileHandler를 통해 log파일에 로그를 기록할 수 있다. 이를 위해 생성된 Logger에 Handler를 만들어서 AddHandler 해준다. 각 Handler에 위에서 만들어 두었던 Formatter를 적용한다.

        stream_handler = logging.StreamHandler()
        stream_handler.setFormatter(formatter)
        file_handler = logging.FileHandler('./log/' + datetime.now().strftime('%Y%m') +'.log')
        file_handler.setFormatter(formatter)
        LoggerFactory._LOGGER.addHandler(stream_handler)
        LoggerFactory._LOGGER.addHandler(file_handler)

log 파일을 월별로 나누기 위해 datetime을 strftime() 함수를 이용하여 년월만 표시하여 파일명을 정했다.


Logger 사용하기

Main함수에서 create_logger()를 호출하여 Logger를 생성한 후 사용해본다.

    util.LoggerFactory.create_logger()
    if (window.login(args[1], args[2], args[3]) == True) :
        util.LoggerFactory._LOGGER.info('로그인 성공')
        window.setUIMode(int(args[4]))
        window.updateUI()
    else :
        util.LoggerFactory._LOGGER.info('로그인 실패')

터미널 로그 결과
파일 로그 결과

각각 터미널과 파일에 로그가 정상적으로 기록되는 걸 확인할 수 있다. 이미 생성된 Logger로 다른 파일 및 클래스에서도 호출할 수 있다.

    def setUIMode(self, mode) :
        self.current_mode = Mode(mode)
        util.LoggerFactory._LOGGER.info('현재 모드 : ' + '프린트 모드' if mode == 1 else '채점 모드')

터미널 로그 결과
파일 로그 결과

호출된 위치의 파일명, 함수명, 코드 줄 번호도 정상적으로 기록된다.

log시스템을 만들어놨으니 곳곳에 추가하는 일만 남았다. 배포 전 예외처리 및 에러가 날 만한 곳에 세세하게 추가해 놓는 게 좋다. 한번 짜 놓으면 유용하게 쓰일 것~~

 

반응형

댓글