개발/Python

[파이썬] logging을 비활성화하는 방법은?

MinorMan 2022. 12. 7. 20:32
반응형

<질문>

비활성화 방법loggingPython의 표준 오류 스트림에서? 이것은 작동하지 않습니다:

import logging

logger = logging.getLogger()
logger.removeHandler(sys.stderr)
logger.warning('foobar')  # emits 'foobar' on sys.stderr

<답변1>

이에 대한 해결책을 찾았습니다.

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

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


<답변2>

나는 사용한다:

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

<답변3>

당신이 사용할 수있는:

logging.basicConfig(level=your_level)

어디your_level다음 중 하나입니다.

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

따라서 설정하면your_level에게로깅.위험, 다음에서 보낸 중요 메시지만 받게 됩니다.

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

환경your_level에게로깅.디버그모든 수준의 로깅을 표시합니다.

자세한 내용은 다음을 참조하십시오.logging examples.

각 Handler 사용에 대해 동일한 방식으로 레벨을 변경합니다.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)

<답변4>

컨텍스트 관리자 사용 - [가장 단순한]

import logging 

class DisableLogger():
    def __enter__(self):
       logging.disable(logging.CRITICAL)
    def __exit__(self, exit_type, exit_value, exit_traceback):
       logging.disable(logging.NOTSET)

사용 예:

with DisableLogger():
    do_something()

필요한 경우 [더 복잡한] 볼 수 있는 세분화된 솔루션AdvancedLogger

AdvancedLogger can be used for fine grained logging temporary modifications

How it works:
Modifications will be enabled when context_manager/decorator starts working and be reverted after

Usage:
AdvancedLogger can be used
- as decorator `@AdvancedLogger()`
- as context manager `with  AdvancedLogger():`

It has three main functions/features:
- disable loggers and it's handlers by using disable_logger= argument
- enable/change loggers and it's handlers by using enable_logger= argument
- disable specific handlers for all loggers, by using  disable_handler= argument

All features they can be used together

AdvancedLogger 사용 사례

# Disable specific logger handler, for example for stripe logger disable console
AdvancedLogger(disable_logger={"stripe": "console"})
AdvancedLogger(disable_logger={"stripe": ["console", "console2"]})

# Enable/Set loggers
# Set level for "stripe" logger to 50
AdvancedLogger(enable_logger={"stripe": 50})
AdvancedLogger(enable_logger={"stripe": {"level": 50, "propagate": True}})

# Adjust already registered handlers
AdvancedLogger(enable_logger={"stripe": {"handlers": "console"}

<답변5>

(오랫동안 죽은 질문이지만 미래의 검색자를 위해)

원래 포스터의 코드/의도에 더 가깝습니다. 이것은 Python 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을 다시 추가하는 것으로 보입니다.

IndexOutOfBound 수정:lhStdout을 인스턴스화하는 동안 IndexOutOfBound 오류가 발생하면 파일 핸들러를 추가한 후 인스턴스화를 이동합니다.

...
logger.addHandler(lh)

lhStdout = logger.handlers[0]
logger.removeHandler(lhStdout)

<답변6>

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

logging.disable(sys.maxint) # Python 2

logging.disable(sys.maxsize) # Python 3

로깅을 활성화하려면:

logging.disable(logging.NOTSET)

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

logging.getLogger().disabled = True

그리고 어떤 사람들에게는n50 이상,

logging.disable(n)

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

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

에 의해 예방할 수 있습니다

logging.disable(sys.maxint)

내가 알 수 있는 한(source) 로깅을 완전히 비활성화하는 유일한 방법입니다.


<답변7>

여기에 정말 좋은 답변이 있지만 분명히 가장 간단한 답변은 너무 많이 고려되지 않습니다(infinito에서만).

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

이렇게 하면 루트 로거와 다른 모든 로거가 비활성화됩니다. 실제로 테스트하지는 않았지만 가장 빠를 것입니다.

Python 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)

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


<답변8>

로깅에는the following structure:

  • 로거점 구분 기호가 있는 네임스페이스 계층 구조에 따라 정렬됩니다.
  • 각 로거에는수준(logging.WARNING기본적으로 루트 로거 및logging.NOTSET루트가 아닌 로거의 경우 기본적으로) 및유효 수준(수준이 있는 루트가 아닌 로거에 대한 상위 로거의 유효 수준logging.NOTSET그렇지 않으면 로거의 수준);
  • 각 로거에는 다음 목록이 있습니다.필터;
  • 각 로거에는 다음 목록이 있습니다.핸들러;
  • 각 핸들러는수준(logging.NOTSET기본적으로);
  • 각 핸들러에는 다음 목록이 있습니다.필터.

로깅에는the following process(순서도로 표시됨):

Logging flow.

따라서 특정 로거를 비활성화하려면 다음 전략 중 하나를 채택할 수 있습니다.

  1. 로거의 수준을 logging.CRITICAL + 1 로 설정합니다.

    • 기본 API 사용:

       import logging logger = logging.getLogger("foo") logger.setLevel(logging.CRITICAL + 1)
    • 구성 API 사용:

       import logging.config logging.config.dictConfig({ "version": 1, "loggers": { "foo": { "level": logging.CRITICAL + 1 } } })
  2. 로거에 필터 lambda record: False 를 추가합니다.

    • 기본 API 사용:

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

       import logging.config logging.config.dictConfig({ "version": 1, "filters": { "all": { "()": lambda: (lambda record: False) } }, "loggers": { "foo": { "filters": ["all"] } } })
  3. 로거의 기존 처리기를 제거하고 로거 에 처리기 logging.NullHandler() 를 추가합니다 (현재 스트림 sys.stderr 및 수준 logging.WARNING 을 사용하는 logging.StreamHandler 인 처리기 logging.lastResort 에 의해 이벤트가 처리되지 않도록 합니다. logging.WARNING ) 로거의 속성 propagateFalse 로 설정합니다 (로거의 상위 로거 핸들러가 이벤트를 처리하지 못하도록 방지).

    • 기본 API 사용:

       import logging logger = logging.getLogger("foo") for handler in logger.handlers.copy(): try: logger.removeHandler(handler) except ValueError: # in case another thread has already removed it pass logger.addHandler(logging.NullHandler()) logger.propagate = False
    • 구성 API 사용:

       import logging.config logging.config.dictConfig({ "version": 1, "handlers": { "null": { "class": "logging.NullHandler" } }, "loggers": { "foo": { "handlers": ["null"], "propagate": False } } })

경고.— 기록된 이벤트만 방지하는 전략 1 및 2와 반대로로거에 의해로거 및 상위 로거의 핸들러에서 내보내지 않도록 전략 3은 이벤트가 기록되는 것을 방지합니다.하위 로거에 의해로거의(예:logging.getLogger("foo.bar")) 로거 및 그 조상 로거의 핸들러에서 내보낼 수 있습니다.

메모.— 속성 설정disabled로거의True공개 API의 일부가 아니므로 아직 다른 전략이 아닙니다(cf.https://bugs.python.org/issue36318):

import logging

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

<답변9>

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

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

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

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

logging.getLogger().setLevel(100)

<답변10>

이렇게 하면 여기에 설명된 대로 사용된 세 번째 라이브러리의 모든 로깅이 방지됩니다.https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library

logging.getLogger('somelogger').addHandler(logging.NullHandler())

<답변11>

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

<답변12>

자신만의 핸들러를 만들었다고 생각하면 로거에 추가하기 직전에 다음을 수행할 수 있습니다.

logger.removeHandler(logger.handlers[0])

기본 StreamHandler가 제거됩니다. 이것은 로그가 파일에만 기록되어야 할 때 stderr에 원하지 않는 로그 방출이 발생한 후 Python 3.8에서 저에게 효과적이었습니다.


<답변13>

로깅 모듈은 잘 모르지만 평소에 디버그(또는 정보) 메시지만 비활성화하고 싶은 방식으로 사용하고 있습니다. 당신이 사용할 수있는Handler.setLevel()로깅 수준을 CRITICAL 이상으로 설정합니다.

또한 sys.stderr 및 sys.stdout을 쓰기용으로 열린 파일로 바꿀 수 있습니다. 보다http://docs.python.org/library/sys.html#sys.stdout. 그러나 나는 그것을 추천하지 않을 것입니다.


<답변14>

다음과 같이 할 수도 있습니다.

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

<답변15>

"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,
    },
}

})


<답변16>

다음을 사용하여 우아한 솔루션을 찾았습니다.데코레이터, 다음 문제를 해결합니다. 각각 여러 디버깅 메시지가 있는 여러 기능이 있는 모듈을 작성하고 현재 집중하고 있는 기능을 제외한 모든 기능에서 로그인을 비활성화하려면 어떻게 해야 합니까?

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

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_debugged안으로부터function_being_focused, 디버그 메시지function_already_debugged표시되지 않습니다. 이렇게 하면 집중하고 있는 기능의 디버그 메시지만 볼 수 있습니다.

도움이 되길 바랍니다!


<답변17>

완전히 비활성화하는 대신 특정 처리기에 대한 디버그 모드 수준을 변경할 수 있습니다.

따라서 사례가 있는 경우 콘솔에 대해서만 디버그 모드를 중지하고 싶지만 오류와 같은 다른 수준은 유지해야 합니다. 다음과 같이 할 수 있습니다

# create logger
logger = logging.getLogger(__name__)

def enableConsoleDebug (debug = False):
    #Set level to logging.DEBUG to see CRITICAL, ERROR, WARNING, INFO and DEBUG statements
    #Set level to logging.ERROR to see the CRITICAL & ERROR statements only
    logger.setLevel(logging.DEBUG)

    debugLevel = logging.ERROR
    if debug:
        debugLevel = logging.DEBUG

    for handler in logger.handlers:
        if type(handler) is logging.StreamHandler:
            handler.setLevel (debugLevel)


<답변18>

100% 해결책은 아니지만 여기에 있는 답변 중 어느 것도 내 문제를 해결하지 못했습니다. 심각도에 따라 컬러 텍스트를 출력하는 사용자 지정 로깅 모듈이 있습니다. 내 로그를 복제하고 있었기 때문에 stdout 출력을 비활성화해야 했습니다. 콘솔을 거의 사용하지 않기 때문에 중요한 로그가 콘솔에 출력되어도 괜찮습니다. 내 로깅에서 사용하지 않기 때문에 stderr에 대해 테스트하지 않았지만 stdout과 동일한 방식으로 작동해야 합니다. stdout(요청된 경우 stderr)에 대해서만 CRITICAL을 최소 심각도로 설정합니다.

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# disable terminal output - it is handled by this module
stdout_handler = logging.StreamHandler(sys.stdout)

# set terminal output to critical only - won't output lower levels
stdout_handler.setLevel(logging.CRITICAL)

# add adjusted stream handler
logger.addHandler(stdout_handler)

<답변19>

일시적으로 비활성화할 수 있게 하려는 핸들러를 하위 클래스로 분류합니다.

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()
반응형