Pythonでコンソールログを無効にして再度有効にする方法は?


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 blaon stdoutを表示しますが、コンソールハンドラーを安全に無効にする方法を知りません。コンソールStreamHandlerを一時的に削除し、別のStreamHandlerを削除しないようにするにはどうすればよいですか?


なぜ誰もがログを無効にしたいと思う人のために:パスワードやAPIキーなどのプライベートデータをログに記録したくないでしょう。
Stevoisiak

4
@StevenVascellaro。では、そもそもなぜそれらがロガーに送られるのでしょうか?それは正しく聞こえません...
マッド物理学者

1
@MadPhysicist XMLリクエストを外部APIに送信するアプリケーションがあります。デフォルトでは、これらのリクエストはファイルに記録されます。ただし、最初のログインでは、ユーザー名とパスワードによる認証が必要です。これはログに記録したくありません。
Stevoisiak 2018

@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 2017

2
特定のログレベルより下のメッセージ(たとえば、すべてのINFOメッセージ)のみをフィルター処理する場合は、2行目を次のように変更できますlogger.setLevel(logging.WARNING)
Hartley Brody

2
その後、どのようにしてログを再度有効にしますか?
Stevoisiak

4
伝播をブロックするとルートロガーのすべてのハンドラーが事実上無効になり、質問には明確に(…)が示されるため、回答でありませんが、ルートロガーのデフォルトのStreamHandler のみを無効にする意図があることを示唆する他のハンドラーを保持たい場合があります。
Piotr Dobrogost

メッセージの伝達を停止するだけでは不十分です。Python 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átrayMárk2018

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を調べると、2つのハンドラー(新しいファイルハンドラーと元のストリームハンドラー)が表示されます。
Joe

CRITICALは私が探していた言葉でした。ありがとう。
Nishant

デバッグレベルをOFFにしたいと思います。それは明確でシンプルです。
マシンではない

46

(長い死んだ質問ですが、将来の検索者向けです)

元の投稿者のコード/インテントに近い、これは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を自動的に再追加するように見えます。


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

私はこのイディオムが本当に好きですが、特定の名前空間を無効にすることができます。たとえば、ルートロガーを一時的に無効にしたいだけです。このイディオムを使用しますが、ハンドラーなどを一時的に追加/削除できるだけです。
クリス

1
この質問では、デフォルトのStreamHandler のみを無効にする方法を尋ねています。
Piotr Dobrogost

1
独自のクラスをロールする必要はありません。contextlibから@contextmanagerを使用して、yielting関数を作成できます
KristianR

あなたがあなたのピザのエキゾチックな果物になっているなら。承知しました。
user3504575

34

ロギングを完全に無効にするには

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__)この方法で作成された他のロガーは、この方法では無効になりません。

2番目のソリューションはすべてのログに影響します。ただし、出力を指定されたレベルよりも上に制限するため、50を超えるレベルでログを記録することで、出力を上書きできます。

それは

logging.disable(sys.maxint)

ソースを確認した後)私が知る限り、ロギングを完全に無効にする唯一の方法です。


1
質問は標準のStreamHandler のみ
Piotr Dobrogost '21

27

ここには本当に良い答えがいくつかありますが、明らかに最も単純なものはあまり考慮されていません(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)

つまり、無効になっている場合、ハンドラーは呼び出されません。たとえば、非常に高い値にフィルタリングしたり、no-opハンドラーを設定したりする方が効率的です。


1
私が何か間違ったことをしているのでない限り、これはルートロガーを無効にするだけで、作成されたものは無効にしませんlog = logging.getLogger(__name__)
starfry

2
複数のロガーまたは複数のハンドラーを処理している場合、これは問題になる可能性があります。たとえば、ファイルにログを記録したいが、特定のケースでストリームハンドラを無効にしたい場合。
Joe

1
これにより、ルートロガーが無効になり、他のすべてのロガーも無効になります。厳密に言えば、ルートロガーを無効にしても、他のロガーは無効になりません。質問の他に、デフォルトのStreamHandler のみを無効にすることについて尋ねます。
Piotr Dobrogost

disabled属性には、パブリックAPIの一部ではありません。bugs.python.org/issue36318を参照してください。
Maggyero

10

stdoutを迂回させる必要はありません。ここにそれを行うためのより良い方法があります:

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を作成し、ルートロガーに追加することにより、ロギングシステムの基本的な構成を行います。ルートロガーにハンドラーが定義されていない場合、関数debug()、info()、warning()、error()、critical()はbasicConfig()を自動的に呼び出しますdocs.python.org/3/library/logging.html#logging.basicConfig
Piotr Dobrogost

2

ロギングモジュールはよくわかりませんが、通常はデバッグ(または情報)メッセージのみを無効にしたい方法で使用しています。を使用Handler.setLevel()して、ロギングレベルをCRITICAL以上に設定できます。

また、sys.stderrとsys.stdoutを書き込み用に開いたファイルに置き換えることもできます。http://docs.python.org/library/sys.html#sysを参照してくださいstdout。しかし、私はそれをお勧めしません。


これは、logger.handlersに何かが含まれている場合に機能します[]。現在はです。
ソリン

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」の1つのレベルを変更することで、ログレベル全体を新しいレベルに変更できます。

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_debugged内から呼び出しても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

Logging 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"]
              }
          }
      })

警告。— 1番目のソリューションとは異なり、2番目のソリューションは子ロガー(たとえばlogging.getLogger("foo.bar"))からのロギングを無効にしないため、単一のロガーのロギングを無効にする場合にのみ使用する必要があります。

注意。—ロガーのdisabled属性をに設定するTrueことは、パブリックAPIの一部ではないため、3番目のソリューションではありません。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.