Python 로깅을 사용하고 있으며 어떤 이유로 모든 메시지가 두 번 나타납니다.
로깅을 구성하는 모듈이 있습니다.
# BUG: It's outputting logging messages twice - not sure why - it's not the propagate setting.
def configure_logging(self, logging_file):
self.logger = logging.getLogger("my_logger")
self.logger.setLevel(logging.DEBUG)
self.logger.propagate = 0
# Format for our loglines
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
# Setup console logging
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
self.logger.addHandler(ch)
# Setup file logging as well
fh = logging.FileHandler(LOG_FILENAME)
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
self.logger.addHandler(fh)
나중에이 메서드를 호출하여 로깅을 구성합니다.
if __name__ == '__main__':
tom = Boy()
tom.configure_logging(LOG_FILENAME)
tom.buy_ham()
그런 다음 buy_ham 모듈에서 다음을 호출합니다.
self.logger.info('Successfully able to write to %s' % path)
그리고 어떤 이유로 모든 메시지가 두 번 나타납니다. 나는 여전히 똑같은 스트림 핸들러 중 하나를 주석 처리했습니다. 이상한 일이지만 왜 이런 일이 발생하는지 모르겠습니다. 내가 명백한 것을 놓쳤다 고 가정합니다.
건배, 빅터
답변
configure_logging
두 번 호출합니다 (의 __init__
메서드에서 가능 Boy
) : getLogger
동일한 객체를 반환하지만 addHandler
유사한 핸들러가 이미 로거에 추가되었는지 확인하지 않습니다.
해당 메서드에 대한 호출을 추적하고 이들 중 하나를 제거하십시오. 아니면 플래그 설정 logging_initialized
으로 초기화 False
에서 __init__
의 방법 Boy
과 변화 configure_logging
하면 아무것도 할 수을 logging_initialized
것입니다 True
, 그리고 그것을 설정 True
하면 로거를 초기화 한 후.
프로그램이 여러 Boy
인스턴스를 생성 configure_logging
하는 경우 처리기를 추가 하는 전역 함수와 속성을 Boy.configure_logging
초기화하는 메서드 만 사용하여 작업을 수행하는 방식을 변경해야 self.logger
합니다.
이를 해결하는 또 다른 방법은 로거의 handlers 속성을 확인하는 것입니다.
logger = logging.getLogger('my_logger')
if not logger.handlers:
# create the handlers and call logger.addHandler(logging_handler)
답변
이 문제가 표시되고 핸들러를 두 번 추가하지 않으면 여기에서 abarnert의 답변을 참조 하십시오.
로부터 문서 :
참고 : 핸들러를 로거와 하나 이상의 상위 항목에 연결하면 동일한 레코드를 여러 번 내보낼 수 있습니다. 일반적으로 하나 이상의 로거에 핸들러를 연결할 필요가 없습니다. 로거 계층 구조에서 가장 높은 적절한 로거에 핸들러를 첨부하면 전파되는 경우 모든 하위 로거가 기록한 모든 이벤트를 볼 수 있습니다. 설정은 True로 설정되어 있습니다. 일반적인 시나리오는 처리기를 루트 로거에만 연결하고 전파가 나머지를 처리하도록하는 것입니다.
따라서 “test”에서 사용자 지정 처리기를 원하고 메시지가 루트 처리기로 전달되는 것을 원하지 않는 경우 대답은 간단합니다. 전파 플래그를 끕니다.
logger.propagate = 거짓
답변
핸들러는 외부에서 호출 할 때마다 추가됩니다. 작업을 마친 후 처리기를 제거해보십시오.
self.logger.removeHandler(ch)
답변
나는 파이썬 초보자이지만 이것은 나를 위해 일하는 것처럼 보였습니다 (Python 2.7)
while logger.handlers:
logger.handlers.pop()
답변
제 경우에는 logger.propagate = False
이중 인쇄를 방지 하도록 설정하고 싶습니다 .
아래 코드에서 제거 logger.propagate = False
하면 이중 인쇄가 표시됩니다.
import logging
from typing import Optional
_logger: Optional[logging.Logger] = None
def get_logger() -> logging.Logger:
global _logger
if _logger is None:
raise RuntimeError('get_logger call made before logger was setup!')
return _logger
def set_logger(name:str, level=logging.DEBUG) -> None:
global _logger
if _logger is not None:
raise RuntimeError('_logger is already setup!')
_logger = logging.getLogger(name)
_logger.handlers.clear()
_logger.setLevel(level)
ch = logging.StreamHandler()
ch.setLevel(level)
# warnings.filterwarnings("ignore", "(Possibly )?corrupt EXIF data", UserWarning)
ch.setFormatter(_get_formatter())
_logger.addHandler(ch)
_logger.propagate = False # otherwise root logger prints things again
def _get_formatter() -> logging.Formatter:
return logging.Formatter(
'[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s')
답변
설치된 루트 핸들러가없는 경우 호출에 대한 logging.debug()
호출 logging.basicConfig()
. 그것은 테스트 케이스가 실행되는 순서를 제어 할 수없는 테스트 프레임 워크에서 저에게 일어났습니다. 내 초기화 코드는 두 번째 코드를 설치했습니다. 기본값은 내가 원하지 않는 logging.BASIC_FORMAT을 사용합니다.
답변
실수로 로거에 무언가를 출력하고 구성하면 너무 늦은 것 같습니다. 예를 들어, 내 코드에서
logging.warning("look out)"
...
ch = logging.StreamHandler(sys.stdout)
root = logging.getLogger()
root.addHandler(ch)
root.info("hello")
나는 (형식 옵션 무시)와 같은 것을 얻을 것입니다.
look out
hello
hello
모든 것이 stdout에 두 번 기록되었습니다. 첫 번째 호출이 logging.warning
자동으로 새 처리기 를 만든 다음 명시 적으로 다른 처리기를 추가 했기 때문이라고 생각 합니다. 우연한 첫 번째 logging.warning
전화를 제거했을 때 문제가 사라졌습니다 .