Python 로깅 모듈을 사용할 때 로그 출력이 중복됨
저는 파이썬 로거를 사용하고 있습니다.내 코드는 다음과 같습니다.
import os
import time
import datetime
import logging
class Logger :
def myLogger(self):
logger = logging.getLogger('ProvisioningPython')
logger.setLevel(logging.DEBUG)
now = datetime.datetime.now()
handler=logging.FileHandler('/root/credentials/Logs/ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
있는 의 로그 입니다.logger.info어떻게 해결해야 하나요?
그logging.getLogger()는 지정된 이름에 대해 동일한 인스턴스를 반환합니다. (문서)
문제는 당신이 전화할 때마다myLogger()인스턴스에 다른 처리기를 추가하여 로그가 중복됩니다.
아마도 이것과 비슷한 것?
import os
import time
import datetime
import logging
loggers = {}
def myLogger(name):
global loggers
if loggers.get(name):
return loggers.get(name)
else:
logger = logging.getLogger(name)
logger.setLevel(logging.DEBUG)
now = datetime.datetime.now()
handler = logging.FileHandler(
'/root/credentials/Logs/ProvisioningPython'
+ now.strftime("%Y-%m-%d")
+ '.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
loggers[name] = logger
return logger
Python 3.2에서는 핸들러가 이미 있는지 확인하고, 있다면 새 핸들러를 추가하기 전에 해당 핸들러를 지웁니다.이것은 디버깅할 때 매우 편리하며 코드에는 로거 초기화가 포함되어 있습니다.
if (logger.hasHandlers()):
logger.handlers.clear()
logger.addHandler(handler)
이사용습다니했미▁the를 사용했습니다.logger독신자로서.if not len(logger.handlers)하지만 여전히 중복되는 것이 있습니다.형식이 지정된 출력과 형식이 지정되지 않은 출력입니다.
내 경우의 해결책:logger.propagate = False
import datetime
import logging
class Logger :
def myLogger(self):
logger=logging.getLogger('ProvisioningPython')
if not len(logger.handlers):
logger.setLevel(logging.DEBUG)
now = datetime.datetime.now()
handler=logging.FileHandler('/root/credentials/Logs/ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
나를 위해 속임수를 썼습니다.
python 2.7 사용
전화를 걸겠습니다.Logger.myLogger()두 번 이상반환되는 로거 인스턴스를 어딘가에 저장하고 재사용합니다.
핸들러가인 " " " " " " " " 을 합니다.StreamHandler(sys.stderr)생성됩니다.
이것은 @rm957377의 답변에 추가된 것이지만 왜 이런 일이 발생하는지에 대한 설명이 포함되어 있습니다.AWS에서 람다 함수를 실행하면 여러 호출 동안 활성 상태를 유지하는 래핑 인스턴스 내에서 함수를 호출합니다.그러니까, 전화를 하면,addHandler()함수의 코드 내에서 함수가 실행될 때마다 중복 핸들러를 로깅 싱글톤에 계속 추가합니다.로깅 싱글톤은 람다 함수의 여러 호출을 통해 지속됩니다.
이 문제를 해결하려면 다음을 통해 핸들러를 설정하기 전에 핸들러를 지울 수 있습니다.
logging.getLogger().handlers.clear()
logging.getLogger().addHandler(...)
로거 구현은 이미 싱글톤입니다.
logging.getLogger('someLogger')에 대한 여러 호출이 동일한 로거 개체에 대한 참조를 반환합니다.이는 동일한 모듈 내에서뿐만 아니라 동일한 Python 인터프리터 프로세스에 있는 한 모듈 전체에서도 마찬가지입니다.동일한 개체에 대한 참조의 경우에도 마찬가지입니다. 또한 응용 프로그램 코드는 한 모듈에서 상위 로거를 정의 및 구성하고 별도 모듈에서 하위 로거를 생성(구성하지 않음)할 수 있으며, 하위 로거 호출은 모두 상위 로거로 전달됩니다.여기에 메인 모듈이 있습니다.
그래서 당신이 이걸 활용해야 하는 방법입니다.
메인 모듈에서 'main_logger'라는 로거를 만들고 구성했다고 가정해 보겠습니다(로거를 구성하기만 하면 아무것도 반환하지 않습니다).
# get the logger instance
logger = logging.getLogger("main_logger")
# configuration follows
...
이제 하위 모듈에서 명명 계층 'main_logger.sub_module_logger'에 이어 하위 로거를 생성하면 하위 모듈에서 이를 구성할 필요가 없습니다.이름 지정 계층에 따라 로거를 만드는 것만으로도 충분합니다.
# get the logger instance
logger = logging.getLogger("main_logger.sub_module_logger")
# no configuration needed
# it inherits the configuration from the parent logger
...
또한 중복 핸들러를 추가하지 않습니다.
자세한 답변은 이 질문을 참조하십시오.
문제는 숫자 처리기입니다. 처리기가 여러 개인 경우 로그가 여러 개이므로 다음을 추가하기 전에 확인해야 합니다.
if not logger.handlers:
logger.addHandler(handler)
로거는 싱글톤으로 작동해야 합니다.두 번 이상 생성하면 안 됩니다.다음은 보기의 예입니다.
import os
import time
import datetime
import logging
class Logger :
logger = None
def myLogger(self):
if None == self.logger:
self.logger=logging.getLogger('ProvisioningPython')
self.logger.setLevel(logging.DEBUG)
now = datetime.datetime.now()
handler=logging.FileHandler('ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
self.logger.addHandler(handler)
return self.logger
s = Logger()
m = s.myLogger()
m2 = s.myLogger()
m.info("Info1")
m2.info("info2")
인수 없이 getLogger()를 사용하면 RootLogger가 반환됩니다.
따라서 여러 위치에서 getLogger()를 호출하고 로그 핸들러를 추가하면 로그 핸들러가 RootLogger에 추가됩니다(로그 핸들러를 명시적으로 추가하지 않으면 StreamHandler가 자동으로 추가됩니다).따라서 메시지를 기록하려고 하면 RootLogger에 추가된 모든 핸들러를 사용하여 메시지를 기록합니다.이것이 중복 로그의 원인입니다.
getLogger()를 호출할 때 다른 로거 이름을 제공하면 이 문제를 피할 수 있습니다.비슷한 것
logger1 = logging.getLogger("loggera")
logger2 = logging.getLogger("loggerb")
이것은 저에게 효과가 있었던 것입니다.
한 가지 간단한 해결 방법은 다음과 같습니다.
logger.handlers[:] = [handler]
이렇게 하면 새 처리기가 기본 목록 "처리기"에 추가되지 않습니다.
더블 또는 ) 은 를 통해 도 발생할 수 .importlib.reload(승인된 답변에서 설명한 것과 동일한 이유로).제 출력이 중복(트리플)된 이유를 파악하는 데 시간이 좀 걸렸기 때문에 나중에 참고하기 위해 이 답변을 추가합니다.
이 경우 대부분의 경우 모듈당 logger.getLogger()를 한 번만 호출하면 됩니다.만약 당신이 저처럼 수업이 여러 개 있다면, 저는 그렇게 부를 수 있습니다.
LOGGER = logger.getLogger(__name__)
class MyClass1:
log = LOGGER
def __init__(self):
self.log.debug('class 1 initialized')
class MyClass2:
log = LOGGER
def __init__(self):
self.log.debug('class 2 initialized')
그러면 둘 다 로그에 기록된 자신의 전체 패키지 이름과 방법을 갖게 됩니다.
특정 로거에 대한 모든 처리기 목록을 가져올 수 있으므로 다음과 같은 작업을 수행할 수 있습니다.
logger = logging.getLogger(logger_name)
handler_installed = False
for handler in logger:
# Here your condition to check for handler presence
if isinstance(handler, logging.FileHandler) and handler.baseFilename == log_filename:
handler_installed = True
break
if not handler_installed:
logger.addHandler(your_handler)
위의 예에서는 지정된 파일의 처리기가 이미 로거에 연결되어 있는지 확인하지만 모든 처리기 목록에 액세스하면 다른 처리기를 추가할지 여부를 결정할 수 있습니다.
오늘 이 문제가 있었습니다.제 기능이 @static method였기 때문에 위의 제안은 랜덤()으로 해결되었습니다.
보기에는 다음과 같습니다.
import random
logger = logging.getLogger('ProvisioningPython.{}'.format(random.random()))
로거 하나에 핸들러가 3개 있습니다.
StreamHandler setLevel(args.logging_level)
logging.FileHandler(logging.ERROR)
RotatingFileHandler(args.logging_level)
logger.setLevel(args.logging_level)
코드를 사용했습니다.
logger = logging.getLogger('same_name_everywhere')
결과적으로 중복된 행 및 중복된 처리기, 스트림 처리기 2개, 회전 파일 처리기 3개, 스트림 처리기 1개 + 회전 파일 처리기 2개(errlog의 경우 1개, 일반 로그의 경우 1개)이 작업은 다음 사용자가 수행합니다.
logger.warn(logger.handlers)
cli_normalize_string: WARNING [<StreamHandler <stderr> (DEBUG)>, <RotatingFileHandler /tmp/cli.normalize_string.py.2020-11-02.user.errlog (ERROR)>, <StreamHandler <stderr> (DEBUG)>, <RotatingFileHandler /tmp/cli.normalize_string.py.2020-11-02.user.log (DEBUG)>, <RotatingFileHandler /tmp/cli.normalize_string.py.2020-11-02.user.errlog (ERROR)>]
로 바꾼 후에
# The name is now become change.cli_normalize_string or change.normalize_string
logger = logger.getLogger(__name__)
모든 모듈에서 문제 해결, 중복 라인 없음, StreamHeader 1개, 오류 로깅용 FileHandler 1개, 일반 로깅용 RotatingFileHandler 1개
2020-11-02 21:26:05,856 cli_normalize_string INFO [<StreamHandler <stderr> (DEBUG)>, <FileHandler /tmp/cli.normalize_string.py.2020-11-02.user.errlog (ERROR)>, <RotatingFileHandler /tmp/cli.normalize_string.py.2020-11-02.user.log (DEBUG)>]
자세한 내용은 이 문서 https://docs.python.org/3/library/logging.html 에 나와 있습니다.
Logger는 직접 인스턴스화되지 않아야 하며 항상 모듈 수준 함수 logging.getLogger(이름)를 통해 인스턴스화되어야 합니다.같은 이름의 getLogger()를 여러 번 호출하면 항상 동일한 Logger 개체에 대한 참조가 반환됩니다."
이름은 잠재적으로 foo.bar .baz와 같이 마침표로 구분된 계층 값입니다(예를 들어 일반 foo일 수도 있음).계층 목록에서 더 아래에 있는 로거는 목록에서 더 위에 있는 로거의 자식입니다.예를 들어, foo라는 이름의 로거가 주어지면,
의 이름을 가진 벌목꾼들
foo.bar
foo.bar.baz
foo.bam
모두 foo의 후손들입니다.로거 이름 계층 구조는 Python 패키지 계층 구조와 유사하며 구성할 경우 동일합니다.
권장 구성을 사용하여 로그 단위로 기록합니다.
logging.getLogger(__name__).
그건 모듈 안에서
__name__
는 Python 패키지 네임스페이스에 있는 모듈의 이름입니다.
from logging.handlers import RotatingFileHandler
import logging
import datetime
# stores all the existing loggers
loggers = {}
def get_logger(name):
# if a logger exists, return that logger, else create a new one
global loggers
if name in loggers.keys():
return loggers[name]
else:
logger = logging.getLogger(name)
logger.setLevel(logging.DEBUG)
now = datetime.datetime.now()
handler = logging.FileHandler(
'path_of_your_log_file'
+ now.strftime("%Y-%m-%d")
+ '.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
loggers.update(dict(name=logger))
return logger
언급URL : https://stackoverflow.com/questions/7173033/duplicate-log-output-when-using-python-logging-module
'programing' 카테고리의 다른 글
| 루비에서 require_relative와 require의 차이점은 무엇입니까? (0) | 2023.06.17 |
|---|---|
| Vuejs mixin의 비동기 방법 (0) | 2023.06.17 |
| 파이썬 3에서 사용자 정의 비교 기능을 사용하는 방법은 무엇입니까? (0) | 2023.06.17 |
| 제네릭 타입의 기능적인 리액트 구성 요소를 만드는 방법은 무엇입니까? (0) | 2023.06.17 |
| Android 앱이 Firebase에 연결되지 않음 (0) | 2023.06.17 |