본문 바로가기
자습

Python Logging

by litaro 2019. 7. 26.

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

 

로깅 요리책 — Python 3.7.4 문서

로깅 호출에 전달된 매개 변수 외에도 로깅 출력에 문맥 정보가 포함되기 원하는 경우가 있습니다. 예를 들어, 네트워크 응용 프로그램에서, (원격 클라이언트의 사용자 이름 또는 IP 주소와 같은) 클라이언트별 정보를 로그에 기록하는 것이 바람직 할 수 있습니다. 이를 달성하기 위해 extra 매개 변수를 사용할 수는 있지만, 이러한 방식으로 정보를 전달하는 것이 항상 편리하지는 않습니다. 연결마다 Logger 인스턴스를 만들고 싶을지 모르지만, 이러한 인스

docs.python.org

Python Logging에 대해 제대로 본적이 없어서 평소에 궁금했던 점에 대해 정리한다.

1. Singletone Logger 만들기 

https://codeday.me/ko/qa/20190316/1317.html

 

파이썬에서 싱글 톤 만들기 - 코드 로그

이 질문은 singleton design pattern이 바람직한지, 반 패턴인가, 종교 전쟁 이냐에 대한 논의가 아니라이 패턴이 파이썬에서 가장 실용적이지 않은 방식으로 가장 잘 구현되는 방법에 대해 토론하는 것입니다. 이 예에서 나는 ‘가장 불쾌감의 원칙’을 따르는 것을 ‘가장 무저 よう’이라고 정의한다. 싱글 톤이 될 여러 클래스가 있습니다 (사용 사례는 로거 용이지만 중요하지는 않습니다). 나는 단순히 상속하거나 장식 할 수있을 때 추가 된 잇몸으

codeday.me

Python 에서 metaclass를 사용하면 다중 상속이 가능한 Singletone을 만들 수 있다.

class SingletonType(type):
    def __call__(cls, *args, **kwargs):
        try:
            return cls.__instance
        except AttributeError:
            cls.__instance = super(SingletonType, cls).__call__(*args, **kwargs)
            return cls.__instance


class BasicLogger:
    logger_level = logging.DEBUG
    format = '%(name)s %(levelname)s %(message)s'


class Logger(BasicLogger, metaclass=SingletonType):
    _logger = None

    def __init__(self):
        self._logger = logging.getLogger('BasicLogger')
        self._logger.setLevel(self.logger_level)

        formatter = logging.Formatter(self.format)
        formatter.converter = (datetime.datetime.utcnow() + datetime.timedelta(hours=9)).timetuple()
        rotating_handler = TimedRotatingFileHandler('basic.log', when='h', interval=1, backupCount=72)
        rotating_handler.setFormatter(formatter)
        stream_handler = logging.StreamHandler()
        stream_handler.setFormatter(formatter)

        self._logger.addHandler(rotating_handler)
        self._logger.addHandler(stream_handler)
        print('Logger Initialized')

    def debug(self, msg):
        self._logger.debug(msg)

    def info(self, msg):
        self._logger.info(msg)

    def warning(self, msg):
        self._logger.warning(msg)

사용하는 예제로 Single Instance가 생성되었는지 확인해보자.

logger1 = Logger()
logger2 = Logger()

if logger1 == logger2:
    print('Same Instance')

logger3 = Logger()

logger1.info("logger1 message")
logger2.info("logger2 message")
logger3.debug("logger3 message")

실행 로그

Logger Initialized
Same Instance
BasicLogger INFO logger1 message
BasicLogger INFO logger2 message
BasicLogger DEBUG logger3 message

2. Custom Logger Format

https://docs.python.org/3/library/logging.html#logrecord-attributes

 

logging — Logging facility for Python — Python 3.7.4 documentation

logging — Logging facility for Python Source code: Lib/logging/__init__.py This module defines functions and classes which implement a flexible event logging system for applications and libraries. The key benefit of having the logging API provided by a sta

docs.python.org

기본으로 제공하는 format은 위의 Record Attributes를 참고하면 된다.

만약 Custom Format을 만들고 싶으면, LoggerAdapter를 이용한다.

class CustomAdapter(logging.LoggerAdapter):

    def process(self, msg, kwargs):
        _message = {
            'instance_id': self.extra.get('instance_id', ''),
            'message_id': self.extra['message_id'],
            'module_name': self.extra.get('module_name', ''),
            'message': msg,
        }

        return '[%s] %s' % (self.name, _message), kwargs

호출하는 방법은 CustomAdapter 객체 생성시 logger와 custom parameter를 dict 형태로 넘긴다.

logger = logging.getLogger('test')
logger.setLevel(logging.INFO)
stream_handler = logging.StreamHandler()
logger.addHandler(stream_handler)

logger1 = CustomAdapter(logger, {'instance_id': 'logger1', 'message_id': '1'})
logger1.info("logger1 1 message")

logger2 = logging.getLogger('test')
logger2 = CustomAdapter(logger2, {'instance_id': 'logger2', 'module_name': 'module1', 'message_id': '2'})
logger2.info("logger1 2 message")

실행 로그

[test] {'instance_id': 'logger1', 'message_id': '1', 'module_name': '', 'message': 'logger1 1 message'}
[test] {'instance_id': 'logger2', 'message_id': '2', 'module_name': 'module1', 'message': 'logger1 2 message'}

'자습' 카테고리의 다른 글

click을 이용한 python CLI  (0) 2019.09.08
pre-commit 활용하기  (0) 2019.08.31
파이썬 클린 코드 CH3. 좋은 코드의 일반적인 특징  (0) 2019.08.17
AWS Lambda@Edge  (0) 2019.08.10
AWS S3-Select  (0) 2019.07.20