파이썬에서 콘솔 로깅을 비활성화하고 다시 활성화하는 방법은 무엇입니까?


154

Python의 로깅 모듈을 사용하고 있으며 일정 시간 동안 콘솔 로깅을 비활성화하고 싶지만 작동하지 않습니다.

#!/usr/bin/python
import logging

logger = logging.getLogger() # this gets the root logger
# ... here I add my own handlers 
#logger.removeHandler(sys.stdout)
#logger.removeHandler(sys.stderr)

print logger.handlers 
# this will print [<logging.StreamHandler instance at ...>]
# but I may have other handlers there that I want to keep

logger.debug("bla bla")

위의 코드는 bla blastdout을 표시 하며 콘솔 핸들러를 안전하게 비활성화하는 방법을 모르겠습니다. 콘솔 StreamHandler를 다른 콘솔이 아닌 일시적으로 제거하려면 어떻게해야합니까?


누구나 로깅을 비활성화하려는 이유가 궁금한 경우 : 비밀번호 또는 API 키와 같은 개인 데이터를 로깅하지 않을 것입니다.
Stevoisiak

4
@StevenVascellaro. 왜 처음에 로거에게 보내지 는가? 소리가 안 들려요.
Mad Physicist

1
@ MadPhysicist XML 요청을 외부 API로 보내는 응용 프로그램이 있습니다. 기본적으로 이러한 요청은 파일에 기록됩니다. 그러나 초기 로그인에는 로그인하고 싶지 않은 사용자 이름과 비밀번호로 인증해야합니다.
Stevoisiak

@StevenVascellaro. 내가 참조. 설명 주셔서 감사합니다.
미친 물리학 자

핸들러를 추가하는 방법 / 위치는 표시하지 않습니다. 루트 로거에 추가 된 경우 docs.python.org/3/library/logging.html#logging.basicConfig에 설명 된대로 로깅에서 기본 StreamHandler를 추가 할 수 없습니다. 또한 링크 된 설명에 따라 기본 StreamHandler는 처음에만 추가됩니다. 호출 방출 로그 메시지이므로 인쇄 logger.handlers할 때 비어 있어야합니다 ( logger.debug()통화 보다 우선 ). 문제의 코드 만 표시됩니다 [](빈 핸들러 목록). Python 2.7.15 및 Python 3.6.6에서 확인되었습니다.
Piotr Dobrogost

답변:


197

나는 이것에 대한 해결책을 찾았다.

logger = logging.getLogger('my-logger')
logger.propagate = False
# now if you use logger it will not log to console.

이렇게하면 콘솔 로깅이 포함 된 상위 로거로 로깅이 전송되지 않습니다.


8
나는 이것이 좋은 해결책이라고 생각하지 않습니다. 상위 로거로 전파하지 않으면 다른 바람직하지 않은 결과가 발생할 수 있습니다.
lfk

2
당신이 특정 로그 수준 (모든 말 아래에만 필터 메시지를 원한다면 INFO메시지), 당신은 같은 것으로 두 번째 줄을 바꿀 수logger.setLevel(logging.WARNING)
하틀리 브로디

2
나중에 로그를 어떻게 다시 사용 하시겠습니까?
Stevoisiak

4
아니 대답 전파를 차단하는 등 효과적으로 명확 루트 로거의 모든 핸들러와 질문 상태를 비활성화 (...)하지만 난 계속 할 것인지가 다른 처리기가있을 수 있습니다 의도가 루트 로거의 비활성화 기본의 StreamHandler에 어떤 제안 .
Piotr Dobrogost

메시지 전파를 중지하는 것만으로는 충분하지 않습니다. 파이썬 3.2 이후logging.lastResort핸들러는 여전히 심각도의 메시지를 기록합니다 logging.WARNING과 이상을 sys.stderr다른 핸들러의 부재. 내 답변을 참조하십시오 .
Maggyero

106

나는 사용한다:

logger = logging.getLogger()
logger.disabled = True
... whatever you want ...
logger.disabled = False

9
이도에서 작동 logging하지 않도록 로깅 모듈 수준 완전히 예를 들어, : import logging; logging.disable(logging.CRITICAL);: docs.python.org/2/library/logging.html#logging.disable
LSH

1
전파를 비활성화하는 것보다 훨씬 낫습니다.
Mátray Márk

6
답이 아닙니다 . 질문은 기본 StreamHandler 비활성화하는 방법을 묻습니다 .
Piotr Dobrogost

1
disabled속성은 공개 API의 일부가 아닙니다. bugs.python.org/issue36318을 참조하십시오 .
Maggyero

69

당신이 사용할 수있는:

logging.basicConfig(level=your_level)

여기서 your_level 은 다음 중 하나입니다.

      'debug': logging.DEBUG,
      'info': logging.INFO,
      'warning': logging.WARNING,
      'error': logging.ERROR,
      'critical': logging.CRITICAL

따라서 your_levellogging.CRITICAL로 설정 하면 다음을 통해 중요한 메시지 만 전송됩니다.

logging.critical('This is a critical error message')

your_levellogging.DEBUG로 설정하면 모든 로깅 수준이 표시됩니다.

자세한 내용은 로깅 예제 를 참조하십시오 .

각 핸들러의 레벨을 변경하는 것과 동일한 방식으로 Handler.setLevel () 함수를 사용하십시오.

import logging
import logging.handlers

LOG_FILENAME = '/tmp/logging_rotatingfile_example.out'

# Set up a specific logger with our desired output level
my_logger = logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)

# Add the log message handler to the logger
handler = logging.handlers.RotatingFileHandler(
          LOG_FILENAME, maxBytes=20, backupCount=5)

handler.setLevel(logging.CRITICAL)

my_logger.addHandler(handler)

6
이것은 일반적으로 유용한 정보이지만 추가 핸들러를 추가하는 방법이 아니라 콘솔 로깅을 비활성화하는 방법에 대한 질문이었습니다. 위의 코드가 원래 예제에 적용된 my_logger.handlers를 살펴보면 새 파일 핸들러와 원래 스트림 핸들러라는 두 개의 핸들러가 표시됩니다.
Joe

CRITICAL 은 내가 찾고 있던 단어였습니다. 감사.
Nishant

디버그 수준이 OFF 인 것을보고 싶습니다. 모호하지 않고 간단합니다.
기계가 아님

46

(긴 죽은 질문이지만 미래의 검색 자에게)

원래 포스터의 코드 / 의도에 더 가깝게 파이썬 2.6에서 작동합니다.

#!/usr/bin/python
import logging

logger = logging.getLogger() # this gets the root logger

lhStdout = logger.handlers[0]  # stdout is the only handler initially

# ... here I add my own handlers 
f = open("/tmp/debug","w")          # example handler
lh = logging.StreamHandler(f)
logger.addHandler(lh)

logger.removeHandler(lhStdout)

logger.debug("bla bla")

내가 해결해야 할 문제 는 새 처리기 추가 한 stdout 처리기를 제거하는 것이 었습니다 . 처리기가없는 경우 로거 코드는 stdout을 자동으로 다시 추가하는 것으로 보입니다.


2
logger = logging.getLogger(); lhStdout = logger.handlers[0]루트 로거에는 초기에 핸들러가 없으므로 순서 가 잘못되었습니다 python -c "import logging; assert not logging.getLogger().handlers". Python 2.7.15 및 Python 3.6.6에서 확인되었습니다.
Piotr Dobrogost

42

컨텍스트 관리자

import logging 
class DisableLogger():
    def __enter__(self):
       logging.disable(logging.CRITICAL)
    def __exit__(self, a, b, c):
       logging.disable(logging.NOTSET)

사용 예 :

with DisableLogger():
    do_something()

나는이 관용구를 정말로 좋아하지만 오히려 특정 네임 스페이스를 비활성화 할 수 있습니다. 예를 들어 루트 로거를 일시적으로 비활성화하고 싶습니다. 이 관용구를 사용하지만 처리기 등을 일시적으로 추가 / 제거 할 수 있어야합니다.
Chris

1
이 질문은 기본 StreamHandler 비활성화하는 방법을 묻습니다 .
Piotr Dobrogost

1
당신은 당신 자신의 클래스를 굴릴 필요가 없습니다, 당신은 contextlib에서 @contextmanager를 사용하고 양보 함수를 작성할 수 있습니다
KristianR

피자에서 이국적인 과일에 빠져 있다면. 확실한.
user3504575

34

로깅을 완전히 비활성화하려면 :

logging.disable(sys.maxint) # Python 2

logging.disable(sys.maxsize) # Python 3

로깅을 사용하려면 :

logging.disable(logging.NOTSET)

다른 답변은 문제를 완전히 해결하지 못하는 해결 방법을 제공합니다.

logging.getLogger().disabled = True

그리고, 일부 n(50)보다 큰,

logging.disable(n)

첫 번째 해결책의 문제점은 루트 로거에서만 작동한다는 것입니다. 예를 들어 생성 된 다른 로거 logging.getLogger(__name__)는이 방법으로 비활성화되지 않습니다.

두 번째 솔루션은 모든 로그에 영향을줍니다. 그러나 출력을 주어진 수준보다 높은 수준으로 제한하므로 50보다 큰 수준으로 로깅하여 출력을 무시할 수 있습니다.

그것은 예방할 수 있습니다

logging.disable(sys.maxint)

( 소스를 검토 한 후) 알 수있는 한 로깅을 완전히 비활성화하는 유일한 방법입니다.


1
질문에 따라 표준 StreamHandler
Piotr Dobrogost

27

여기에 정말 좋은 답변이 있지만, 가장 간단한 것은 너무 많이 고려되지 않습니다 (인피니 토에서만).

root_logger = logging.getLogger()
root_logger.disabled = True

루트 로거와 다른 모든 로거를 비활성화합니다. 나는 실제로 테스트하지는 않았지만 가장 빠릅니다.

파이썬 2.7의 로깅 코드에서 나는 이것을 본다.

def handle(self, record):
    """
    Call the handlers for the specified record.

    This method is used for unpickled records received from a socket, as
    well as those created locally. Logger-level filtering is applied.
    """
    if (not self.disabled) and self.filter(record):
        self.callHandlers(record)

즉, 비활성화되면 핸들러가 호출되지 않으며 매우 높은 값으로 필터링하거나 no-op 핸들러를 설정하는 것이 더 효율적이어야합니다.


1
내가 뭔가 잘못하고 있지 않는 한, 이것은 루트 로거를 비활성화하고 다음과 같은 것을 만들지 않습니다log = logging.getLogger(__name__)
starfry

2
여러 로거 또는 여러 처리기를 처리하는 경우 문제가 될 수 있습니다. 예를 들어, 여전히 파일에 로그하고 싶지만 특정 경우에 스트림 핸들러를 사용하지 않으려는 경우.
Joe

1
루트 로거와 다른 모든 로거를 비활성화합니다. 루트 로거를 엄격히 비활성화해도 다른 로거는 비활성화되지 않습니다. 질문 외에도 기본 StreamHandler 비활성화하는 것에 대해 묻습니다 .
Piotr Dobrogost

disabled속성은 공개 API의 일부가 아닙니다. bugs.python.org/issue36318을 참조하십시오 .
Maggyero

10

표준 출력을 전환 할 필요가 없습니다. 더 좋은 방법은 다음과 같습니다.

import logging
class MyLogHandler(logging.Handler):
    def emit(self, record):
        pass

logging.getLogger().addHandler(MyLogHandler())

더 간단한 방법은 다음과 같습니다.

logging.getLogger().setLevel(100)

4
Python 2.7 이상에서는 NullHandler ()
Pierre

1
이것이 작동하는 이유 (기본 StreamHandler 비활성화)는 logging.basicConfig()기능 설명을 읽을 때 볼 수 있습니다 (강조 광산) : 기본 포맷터를 사용하여 StreamHandler를 작성하고 루트 로거에 추가하여 로깅 시스템의 기본 구성을 수행합니다. 디버그 (), info (), warning (), error () 및 critical () 함수는 루트 로거에 대해 핸들러가 정의되지 않은 경우 자동으로 basicConfig ()를 호출 합니다. docs.python.org/3/library/logging.html#logging.basicConfig
Piotr Dobrogost

2

로깅 모듈을 잘 모르지만 일반적으로 디버그 (또는 정보) 메시지 만 비활성화하려는 방식으로 로깅 모듈을 사용하고 있습니다. Handler.setLevel()로깅 레벨을 위험 또는 그 이상으로 설정하는 데 사용할 수 있습니다 .

또한 sys.stderr 및 sys.stdout을 쓰기 위해 열린 파일로 바꿀 수 있습니다. http://docs.python.org/library/sys.html#sys를 참조 하십시오. stdout . 그러나 나는 그것을 권장하지 않습니다.


logger.handlers에 현재 무언가가 포함되어 있으면 작동 할 수 있습니다 [].
sorin

2

당신은 또한 할 수 있습니다 :

handlers = app.logger.handlers
# detach console handler
app.logger.handlers = []
# attach
app.logger.handlers = handlers

app.logger질문 ( logging.getLogger())과 대부분의 답변 에서 명시 적으로 언급 한 루트 로거 대신 지정하지 않은 것을 사용 하는 이유는 무엇 입니까? 메서드 handlers를 호출 Logger.addHandler하는 대신 속성을 안전하게 수정할 수 있다는 것을 어떻게 알 수 있습니까?
Piotr Dobrogost

2
import logging

log_file = 'test.log'
info_format = '%(asctime)s - %(levelname)s - %(message)s'
logging.config.dictConfig({
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'info_format': {
            'format': info_format
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'info_format'
        },
        'info_log_file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'level': 'INFO',
            'filename': log_file,
            'formatter': 'info_format'
        }
    },
    'loggers': {
        '': {
            'handlers': [
                'console',
                'info_log_file'
            ],
            'level': 'INFO'
        }
    }
})


class A:

    def __init__(self):
        logging.info('object created of class A')

        self.logger = logging.getLogger()
        self.console_handler = None

    def say(self, word):
        logging.info('A object says: {}'.format(word))

    def disable_console_log(self):
        if self.console_handler is not None:
            # Console log has already been disabled
            return

        for handler in self.logger.handlers:
            if type(handler) is logging.StreamHandler:
                self.console_handler = handler
                self.logger.removeHandler(handler)

    def enable_console_log(self):
        if self.console_handler is None:
            # Console log has already been enabled
            return

        self.logger.addHandler(self.console_handler)
        self.console_handler = None


if __name__ == '__main__':
    a = A()
    a.say('111')
    a.disable_console_log()
    a.say('222')
    a.enable_console_log()
    a.say('333')

콘솔 출력 :

2018-09-15 15:22:23,354 - INFO - object created of class A
2018-09-15 15:22:23,356 - INFO - A object says: 111
2018-09-15 15:22:23,358 - INFO - A object says: 333

test.log 파일 내용 :

2018-09-15 15:22:23,354 - INFO - object created of class A
2018-09-15 15:22:23,356 - INFO - A object says: 111
2018-09-15 15:22:23,357 - INFO - A object says: 222
2018-09-15 15:22:23,358 - INFO - A object says: 333

2
코드에 대한 설명을 추가하십시오. 훨씬 더 도움이 될 것입니다
Mathews Sunny

2

"logging.config.dictConfig"에서 한 수준을 변경하면 전체 로깅 수준을 새로운 수준으로 만들 수 있습니다.

logging.config.dictConfig({
'version': 1,
'disable_existing_loggers': False,
'formatters': {
    'console': {
        'format': '%(name)-12s %(levelname)-8s %(message)s'
    },
    'file': {
        'format': '%(asctime)s %(name)-12s %(levelname)-8s %(message)s'
    }
},
'handlers': {
    'console': {
        'class': 'logging.StreamHandler',
        'formatter': 'console'
    },
#CHANGE below level from DEBUG to THE_LEVEL_YOU_WANT_TO_SWITCH_FOR
#if we jump from DEBUG to INFO
# we won't be able to see the DEBUG logs in our logging.log file
    'file': {
        'level': 'DEBUG',
        'class': 'logging.FileHandler',
        'formatter': 'file',
        'filename': 'logging.log'
    },
},
'loggers': {
    '': {
        'level': 'DEBUG',
        'handlers': ['console', 'file'],
        'propagate': False,
    },
}

})


1

데코레이터를 사용 하여 다음과 같은 문제를 해결 하는 우아한 솔루션을 찾았 습니다. 여러 함수가있는 모듈을 작성하고 각 모듈에 여러 디버깅 메시지가있는 경우 현재 초점을 맞추고있는 기능을 제외한 모든 기능에서 로깅을 사용하지 않으려면 어떻게해야합니까?

데코레이터를 사용하여 수행 할 수 있습니다.

import logging, sys
logger = logging.getLogger()
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)


def disable_debug_messages(func):
    def wrapper(*args, **kwargs):
        prev_state = logger.disabled
        logger.disabled = True
        result = func(*args, **kwargs)
        logger.disabled = prev_state
        return result
    return wrapper

그런 다음 다음을 수행 할 수 있습니다.

@disable_debug_messages
def function_already_debugged():
    ...
    logger.debug("This message won't be showed because of the decorator")
    ...

def function_being_focused():
    ...
    logger.debug("This message will be showed")
    ...

function_already_debuggedwithin function_being_focused에서 호출하더라도 디버그 메시지가 function_already_debugged표시되지 않습니다. 그러면 초점을 맞추고있는 기능의 디버그 메시지 만 표시됩니다.

그것이 도움이되기를 바랍니다!


0

특정 로거를 일시적으로 비활성화하려면 여기가 수행됩니다.

로그 예

2019-10-02 21:28:45,663 django.request PID: 8  Internal Server Error: /service_portal/get_all_sites

암호

django_request_logger = logging.getLogger('django.request')
django_request_logger.disabled = True
django_request_logger.disabled = False

0

로깅 Python 라이브러리 에서 다음 중 하나를 수행하여 특정 로거에 대한 로깅을 모든 레벨에서 완전히 비활성화 할 수 있습니다 .

  1. 상기 로거에 추가 logging.NullHandler()핸들러 (방지하려면이 logging.lastResort정도의 이벤트 로그에서 핸들러 logging.WARNING에 더 큰를 sys.stderr하고) , 설정 propagate에 그 로거의 속성을False 합니다 (조상 로거의 핸들러에 이벤트를 통과 로거를 방지하기 위해).

    • 기본 API 사용 :

      import logging
      
      logging.getLogger("foo").addHandler(logging.NullHandler())
      logging.getLogger("foo").propagate = False
    • 구성 API 사용 :

      import logging.config
      
      logging.config.dictConfig({
          "version": 1,
          "handlers": {
              "null": {
                  "class": "logging.NullHandler"
              }
          },
          "loggers": {
              "foo": {
                  "handlers": ["null"],
                  "propagate": False
              }
          }
      })
  2. 로거에 lambda record: False필터를 추가합니다 .

    • 기본 API 사용 :

      import logging
      
      logging.getLogger("foo").addFilter(lambda record: False)
    • 구성 API 사용 :

      import logging.config
      
      logging.config.dictConfig({
          "version": 1,
          "filters": {
              "all": {
                  "()": lambda: (lambda record: False)
              }
          },
          "loggers": {
              "foo": {
                  "filters": ["all"]
              }
          }
      })

경고. — 첫 번째 솔루션과 달리 두 번째 솔루션은 하위 로거 (예 logging.getLogger("foo.bar"):)에서 로깅을 비활성화하지 않으므로 단일 로거에 대한 로깅을 비활성화하는 데만 사용해야합니다.

노트. — 로거의 disabled속성을 설정하는 True것은 퍼블릭 API의 일부가 아니므로 세 번째 솔루션이 아닙니다. https://bugs.python.org/issue36318을 참조 하십시오 .

import logging

logging.getLogger("foo").disabled = True  # DO NOT DO THAT

-1

일시적으로 비활성화 할 수있는 처리기를 서브 클래스로 만듭니다.

class ToggledHandler(logging.StreamHandler):
"""A handler one can turn on and off"""

def __init__(self, args, kwargs):
    super(ToggledHandler, self).__init__(*args, **kwargs)
    self.enabled = True  # enabled by default

def enable(self):
    """enables"""
    self.enabled = True

def disable(self):
    """disables"""
    self.enabled = False

def emit(self, record):
    """emits, if enabled"""
    if self.enabled:
        # this is taken from the super's emit, implement your own
        try:
            msg = self.format(record)
            stream = self.stream
            stream.write(msg)
            stream.write(self.terminator)
            self.flush()
        except Exception:
            self.handleError(record)

이름별로 핸들러를 찾는 것은 매우 쉽습니다.

_handler = [x for x in logging.getLogger('').handlers if x.name == your_handler_name]
if len(_handler) == 1:
    _handler = _handler[0]
else:
    raise Exception('Expected one handler but found {}'.format(len(_handler))

일단 발견 :

_handler.disable()
doStuff()
_handler.enable()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.