2009-11-16 2 views
14

하나의 대상 (즉, FileHandler)에 여러 로거 (예 : logging.getLogger("base.foo")logging.getLogger("base.bar"))를 사용하여 로깅하고 각 로거마다 다른 포맷터를 사용할 수 있습니까?파이썬에서 동일한 로깅 처리기를 사용하여 다른 포맷터를 사용하는 방법

필자의 이해에 따라 각 핸들에 하나의 포맷터 만 할당 할 수 있습니다. 어쩌면 포맷터를 핸들러가 아닌 로거와 연결할 수 있습니까?

답변

11

record.name을 기반으로 다른 형식 지정자로 파견하기 쉽습니다.

import logging 


class DispatchingFormatter: 

    def __init__(self, formatters, default_formatter): 
     self._formatters = formatters 
     self._default_formatter = default_formatter 

    def format(self, record): 
     formatter = self._formatters.get(record.name, self._default_formatter) 
     return formatter.format(record) 


handler = logging.StreamHandler() 
handler.setFormatter(DispatchingFormatter({ 
     'base.foo': logging.Formatter('FOO: %(message)s'), 
     'base.bar': logging.Formatter('BAR: %(message)s'), 
    }, 
    logging.Formatter('%(message)s'), 
)) 
logging.getLogger().addHandler(handler) 

logging.getLogger('base.foo').error('Log from foo') 
logging.getLogger('base.bar').error('Log from bar') 
logging.getLogger('base.baz').error('Log from baz') 

또 다른 방법은 다른 포맷터로에서 두 개의 스트림 핸들러를 수동으로 파일을 열고 만드는 것입니다 : 아래의 증명 -의 - 개념 샘플 코드입니다.

+0

우수, 우아한 해결책 여기에 작업 (파이썬 3 코드)를 할 DispatchingFormatter의 버전입니다. 레코드의 경우 record.levelno를 기반으로 작동하므로 포맷터 사전 키는''base.foo'' 대신'logging.DEBUG'가 될 수 있습니다 – lorenzog

1

우수한 데니스 용액에 약간의 수정. 계층 구조에 기초

Logging name system :

namefoo.bar.baz 같은 잠재적으로 마침표로 분리 계층 값이다 (또한, 예를 들면, foo 평범한 일 수 있지만). 계층 적 목록에서 더 아래쪽에있는 로거는 목록에있는 상위 로거의 하위 항목입니다. 예를 들어, 이름이 이고 foo 인 로거가 주어진 경우 foo.bar, foo.bar.bazfoo.bam의 로거는 모두 foo 인 의 자손입니다. 이 수준은 또한 아이 로거에 적용됩니다 당신이 어떤 로거 setLevel() 예를 들어

. 그래서 포맷터를 로거에 사용하고 자식 로거를 사용하는 것이 좋습니다. 예를 들어 'one.two.three' 로거에 'one.two' 포맷터를 적용해야합니다 ('one.two.three'에 대한 포맷터가없는 경우).

class DispatchingFormatter: 
    """Dispatch formatter for logger and it's sub logger.""" 
    def __init__(self, formatters, default_formatter): 
     self._formatters = formatters 
     self._default_formatter = default_formatter 

    def format(self, record): 
     # Search from record's logger up to it's parents: 
     logger = logging.getLogger(record.name) 
     while logger: 
      # Check if suitable formatter for current logger exists: 
      if logger.name in self._formatters: 
       formatter = self._formatters[logger.name] 
       break 
      else: 
       logger = logger.parent 
     else: 
      # If no formatter found, just use default: 
      formatter = self._default_formatter 
     return formatter.format(record) 

예 :

handler = logging.StreamHandler() 
handler.setFormatter(DispatchingFormatter({ 
     'one': logging.Formatter('%(message)s -> one'), 
     'one.two': logging.Formatter('%(message)s -> one.two'), 
    }, 
    logging.Formatter('%(message)s -> <default>'), 
)) 
logging.getLogger().addHandler(handler) 

print('Logger used -> formatter used:') 
logging.getLogger('one').error('one') 
logging.getLogger('one.two').error('one.two') 
logging.getLogger('one.two.three').error('one.two.three') # parent formatter 'one.two' will be used here 
logging.getLogger('other').error('other') 

# OUTPUT: 
# Logger used -> formatter used: 
# one -> one 
# one.two -> one.two 
# one.two.three -> one.two 
# other -> <default> 
+0

이것을 파일 핸들러로하는 방법을 알고 계십니까? 같은 길? – Henry

+0

@Henry, 네, 두 번째 스 니펫 'StreamHandler()'를 'FileHandler (파일 이름)'로 변경하십시오. Formatter 자체는 모든 유형의 핸들러에 적용될 수 있습니다. –

관련 문제