복붙노트

[PYTHON] 파이썬의 로깅 형식이 메시지 로그 수준에 따라 수정 될 수 있습니까?

PYTHON

파이썬의 로깅 형식이 메시지 로그 수준에 따라 수정 될 수 있습니까?

파이썬의 로깅 메커니즘을 사용하여 출력을 화면에 출력하고 있습니다. print 문을 사용하여이 작업을 수행 할 수 있지만 사용자가 특정 유형의 출력을 사용하지 않도록 미세 조정 된 세분화를 허용하려고합니다. 나는 오류에 대해 인쇄 된 형식을 좋아하지만 출력 수준이 "정보"일 때 더 간단한 형식을 선호합니다.

예 :

  logger.error("Running cmd failed")
  logger.info("Running cmd passed")

이 예제에서는 오류 형식을 다르게 인쇄하고 싶습니다.

여러 로깅 개체가 없어도 서로 다른 로그 수준에 다른 형식을 사용할 수 있습니까? 로거가 수정되면 로거를 수정하지 않고이 작업을 수행하기를 원합니다. 출력이 로깅되는 방식을 결정하는 if / else 문 수가 많기 때문입니다.

해결법

  1. ==============================

    1.예, 사용자 정의 Formatter 클래스를 사용하여이 작업을 수행 할 수 있습니다.

    예, 사용자 정의 Formatter 클래스를 사용하여이 작업을 수행 할 수 있습니다.

    class MyFormatter(logging.Formatter):
        def format(self, record):
            #compute s according to record.levelno
            #for example, by setting self._fmt
            #according to the levelno, then calling
            #the superclass to do the actual formatting
            return s
    

    그런 다음 MyFormatter 인스턴스를 핸들러에 연결하십시오.

  2. ==============================

    2.방금이 문제에 직면했고 위의 예에서 남겨진 "구멍"을 채우는 데 문제가있었습니다. 여기에 내가 사용한보다 완벽하고 효과적인 버전이 있습니다. 희망적으로 이는 누군가에게 도움이되기를 바랍니다.

    방금이 문제에 직면했고 위의 예에서 남겨진 "구멍"을 채우는 데 문제가있었습니다. 여기에 내가 사용한보다 완벽하고 효과적인 버전이 있습니다. 희망적으로 이는 누군가에게 도움이되기를 바랍니다.

    # Custom formatter
    class MyFormatter(logging.Formatter):
    
        err_fmt  = "ERROR: %(msg)s"
        dbg_fmt  = "DBG: %(module)s: %(lineno)d: %(msg)s"
        info_fmt = "%(msg)s"
    
    
        def __init__(self, fmt="%(levelno)s: %(msg)s"):
            logging.Formatter.__init__(self, fmt)
    
    
        def format(self, record):
    
            # Save the original format configured by the user
            # when the logger formatter was instantiated
            format_orig = self._fmt
    
            # Replace the original format with one customized by logging level
            if record.levelno == logging.DEBUG:
                self._fmt = MyFormatter.dbg_fmt
    
            elif record.levelno == logging.INFO:
                self._fmt = MyFormatter.info_fmt
    
            elif record.levelno == logging.ERROR:
                self._fmt = MyFormatter.err_fmt
    
            # Call the original formatter class to do the grunt work
            result = logging.Formatter.format(self, record)
    
            # Restore the original format configured by the user
            self._fmt = format_orig
    
            return result
    

    편집하다:

    Halloleo의 칭찬은 스크립트에 위의 내용을 사용하는 방법에 대한 예입니다.

    fmt = MyFormatter()
    hdlr = logging.StreamHandler(sys.stdout)
    
    hdlr.setFormatter(fmt)
    logging.root.addHandler(hdlr)
    logging.root.setLevel(DEBUG)
    

    편집 2 :

    Python3 로깅이 조금 변경되었습니다. Python3 접근법을 보려면 여기를 참조하십시오.

  3. ==============================

    3.그리고 JS 답은 비슷하지만 좀 더 콤팩트합니다.

    그리고 JS 답은 비슷하지만 좀 더 콤팩트합니다.

    class SpecialFormatter(logging.Formatter):
        FORMATS = {logging.DEBUG :"DBG: %(module)s: %(lineno)d: %(message)s",
                   logging.ERROR : "ERROR: %(message)s",
                   logging.INFO : "%(message)s",
                   'DEFAULT' : "%(levelname)s: %(message)s"}
    
        def format(self, record):
            self._fmt = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT'])
            return logging.Formatter.format(self, record)
    
    hdlr = logging.StreamHandler(sys.stderr)
    hdlr.setFormatter(SpecialFormatter())
    logging.root.addHandler(hdlr)
    logging.root.setLevel(logging.INFO)
    
  4. ==============================

    4.이는 로깅의 새로운 구현에 대한 estani의 대답에 대한 적응입니다. 이제 형식화 스타일에 의존하는 형식화 프로그램입니다. 광산은 '{'스타일 형식을 사용하지만 적응할 수 있습니다. 좀 더 일반적인 것으로 세련되고 __init__에 인자로 서식 스타일과 커스텀 메시지를 선택할 수 있습니다.

    이는 로깅의 새로운 구현에 대한 estani의 대답에 대한 적응입니다. 이제 형식화 스타일에 의존하는 형식화 프로그램입니다. 광산은 '{'스타일 형식을 사용하지만 적응할 수 있습니다. 좀 더 일반적인 것으로 세련되고 __init__에 인자로 서식 스타일과 커스텀 메시지를 선택할 수 있습니다.

    class SpecialFormatter(logging.Formatter):
        FORMATS = {logging.DEBUG : logging._STYLES['{']("{module} DEBUG: {lineno}: {message}"),
               logging.ERROR : logging._STYLES['{']("{module} ERROR: {message}"),
               logging.INFO : logging._STYLES['{']("{module}: {message}"),
               'DEFAULT' : logging._STYLES['{']("{module}: {message}")}
    
        def format(self, record):
            # Ugly. Should be better
            self._style = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT'])
            return logging.Formatter.format(self, record)
    
    hdlr = logging.StreamHandler(sys.stderr)
    hdlr.setFormatter(SpecialFormatter())
    logging.root.addHandler(hdlr)
    logging.root.setLevel(logging.INFO)
    
  5. ==============================

    5.스타일이나 내부 필드를 사용하는 대신 record.levelno (또는 다른 기준)에 따라 다른 포맷터를 위임하는 Formatter를 만들 수도 있습니다. 이것은 나의 겸허 한 의견에서 약간 더 깨끗한 해결책이다. 아래 코드는 파이썬 버전> = 2.7 이상에서 작동합니다 :

    스타일이나 내부 필드를 사용하는 대신 record.levelno (또는 다른 기준)에 따라 다른 포맷터를 위임하는 Formatter를 만들 수도 있습니다. 이것은 나의 겸허 한 의견에서 약간 더 깨끗한 해결책이다. 아래 코드는 파이썬 버전> = 2.7 이상에서 작동합니다 :

    간단한 방법은 다음과 같이 보일 것입니다 :

    class MyFormatter(logging.Formatter):
    
        default_fmt = logging.Formatter('%(levelname)s in %(name)s: %(message)s')
        info_fmt = logging.Formatter('%(message)s')
    
        def format(self, record):
            if record.levelno == logging.INFO:
                return self.info_fmt.format(record)
            else:
                return self.default_fmt.format(record)
    

    하지만 좀 더 일반적인 것으로 만들 수 있습니다.

    class VarFormatter(logging.Formatter):
    
        default_formatter = logging.Formatter('%(levelname)s in %(name)s: %(message)s')
    
        def __init__(self, formats):
            """ formats is a dict { loglevel : logformat } """
            self.formatters = {}
            for loglevel in formats:
                self.formatters[loglevel] = logging.Formatter(formats[loglevel])
    
        def format(self, record):
            formatter = self.formatters.get(record.levelno, self.default_formatter)
            return formatter.format(record)
    

    여기서 입력으로 딕테이션을 사용했지만 분명히 보트를 뜨는 튜플이나 kwargs도 사용할 수 있습니다. 그러면 다음과 같이 사용됩니다.

    formatter = VarFormatter({logging.INFO: '[%(message)s]', 
                              logging.WARNING: 'warning: %(message)s'})
    <... attach formatter to logger ...>
    
  6. ==============================

    6.위의 솔루션은 3.3.3 릴리스와 함께 작동합니다. 그러나 3.3.4를 사용하면 다음 오류가 발생합니다.

    위의 솔루션은 3.3.3 릴리스와 함께 작동합니다. 그러나 3.3.4를 사용하면 다음 오류가 발생합니다.

    FORMATS = { logging.DEBUG : logging._STYLES['{']("{module} DEBUG: {lineno}: {message}"),
    

    TypeError : 'tuple'객체를 호출 할 수 없습니다.

    로깅 클래스에서 주위를 검색 한 후 Lib \ logging__init __. py 데이터 구조가 3.3.3에서 3.3.4로 변경되어 문제가 발생 함을 발견했습니다.

    _STYLES = {
        '%': PercentStyle,
        '{': StrFormatStyle,
        '$': StringTemplateStyle
    }
    
    _STYLES = {
       '%': (PercentStyle, BASIC_FORMAT),
       '{': (StrFormatStyle, '{levelname}:{name}:{message} AA'),
        '$': (StringTemplateStyle, '${levelname}:${name}:${message} BB'),
    }
    

    따라서 업데이트 된 솔루션은

    class SpecialFormatter(logging.Formatter):
         FORMATS = {logging.DEBUG : logging._STYLES['{'][0]("{module} DEBUG: {lineno}: {message}"),
           logging.ERROR : logging._STYLES['{'][0]("{module} ERROR: {message}"),
           logging.INFO : logging._STYLES['{'][0]("{module}: {message}"),
           'DEFAULT' : logging._STYLES['{'][0]("{module}: {message}")}
    
     def format(self, record):
        # Ugly. Should be better
        self._style = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT'])
        return logging.Formatter.format(self, record)
    
  7. ==============================

    7.특정 수준의 서식을 건너 뛰려는 경우 다음과 같은 다른 대답보다 간단한 것을 할 수 있습니다.

    특정 수준의 서식을 건너 뛰려는 경우 다음과 같은 다른 대답보다 간단한 것을 할 수 있습니다.

    class FormatterNotFormattingInfo(logging.Formatter):
        def __init__(self, fmt = '%(levelname)s:%(message)s'):
            logging.Formatter.__init__(self, fmt)
    
        def format(self, record):
            if record.levelno == logging.INFO:
                return record.getMessage()
            return logging.Formatter.format(self, record)
    

    이것은 또한 self._fmt 나 self._style과 같은 내부 변수를 사용하지 않음으로써 3.2 릴리스 전과 후에 작업 할 수 있다는 이점이 있습니다.

  8. from https://stackoverflow.com/questions/1343227/can-pythons-logging-format-be-modified-depending-on-the-message-log-level by cc-by-sa and MIT license