Python'da konsol günlüğü nasıl devre dışı bırakılır ve yeniden etkinleştirilir?


154

Python'un günlük modülünü kullanıyorum ve konsol günlüğünü bir süreliğine devre dışı bırakmak istiyorum ancak çalışmıyor.

#!/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")

Yukarıdaki kod bla blastdout'ta görüntülenir ve konsol işleyicisini nasıl güvenli bir şekilde devre dışı bırakabileceğimi bilmiyorum. Başka bir konsolu değil geçici olarak StreamHandler konsolunu kaldırdığımdan nasıl emin olabilirim?


Neden herkesin günlüğe kaydetmeyi devre dışı bırakmak istediğini merak edenler için: Parolalar veya API anahtarları gibi özel verileri kaydetmek istemezsiniz.
Stevoisiak

4
@StevenVascellaro. Neden ilk etapta bir kaydediciye gönderiliyorlar? Kulağa doğru gelmiyor ...
Mad Physicist

1
@MadPhysicist Harici bir API'ye XML istekleri gönderen bir uygulamam var. Varsayılan olarak, bu istekler bir dosyaya kaydedilir. Ancak, ilk giriş günlüğe kaydedilmesini istemediğim bir kullanıcı adı ve şifre ile kimlik doğrulaması gerektirir.
Stevoisiak

@StevenVascellaro. Anlıyorum. Açıklama için teşekkürler.
Mad Physicist

İşleyicilerinizi nasıl / nereye eklediğinizi göstermezsiniz. Kök kaydediciye eklendiyse, bu, günlüğün docs.python.org/3/library/logging.html#logging.basicConfig adresinde açıklandığı gibi varsayılan StreamHandler eklemesini engeller. Ayrıca, varsayılan açıklama başına yalnızca ilk StreamHandler eklenir yazdırdığınızda logger.handlersboş ( günlü logger.debug()aramadan önce ) boş olmalıdır . Söz konusu kod yalnızca görüntülenir [](işleyicilerin boş listesi). Python 2.7.15 ve Python 3.6.6 ile doğrulanmıştır.
Piotr Dobrogost

Yanıtlar:


197

Bunun için bir çözüm buldum:

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

Bu, günlüğün konsol günlüğünü içeren üst günlüğe gönderilmesini engelleyecektir.


8
Bunun iyi bir çözüm olduğunu düşünmüyorum. Daha yüksek kaydedicilere yayılmamanın başka istenmeyen sonuçları olabilir.
lfk

2
Yalnızca belirli bir günlük seviyesinin altındaki iletiyi filtrelemek istiyorsanız (örneğin, tüm INFOiletiler), ikinci satırı aşağıdaki gibi değiştirebilirsinizlogger.setLevel(logging.WARNING)
Hartley Brody

2
Daha sonra günlüğü nasıl yeniden etkinleştirirsiniz?
Stevoisiak

4
Yayılım engelleme etkin bir şekilde kök günlükçüsü tüm işleyicileri devre dışı bırakır ve soru açıkça belirtir (…) ama orada tutmak istediğim başka işleyicileri olabilir, bu da niyetinin yalnızca kök kaydedicinin varsayılan StreamHandler'ı devre dışı bırakmak olduğunu düşündürüyor .
Piotr Dobrogost

İleti yayılımını durdurmak yeterli değildir. Python 3.2'den beri , logging.lastResortişleyici yine de diğer işleyicilerin yokluğunda ciddiyet logging.WARNINGve daha büyük iletileri kaydedecektir sys.stderr. Cevabımı gör .
Maggyero

106

Kullanırım:

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

9
Bu da çalışan loggingdevre dışı tomrukçulukla modül düzeyinde tamamen örneğin: import logging; logging.disable(logging.CRITICAL);: docs.python.org/2/library/logging.html#logging.disable
LSH

1
Bu, yayılmayı devre dışı bırakmaktan çok daha iyidir.
Mátray Márk

6
Yanıt değil - soru yalnızca varsayılan StreamHandler öğesinin nasıl devre dışı bırakılacağını sorar .
Piotr Dobrogost

1
disabledNitelik ortak API parçası değildir. Bkz. Bugs.python.org/issue36318 .
Maggyero

69

Kullanabilirsiniz:

logging.basicConfig(level=your_level)

burada seviyeniz bunlardan biridir:

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

Belirlediğiniz Yani, your_level için logging.CRITICAL , sen tarafından gönderilen yalnızca kritik mesajlar alacak:

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

Ayar your_level için logging.DEBUG günlük bütün seviyelerini gösterecektir.

Daha fazla ayrıntı için lütfen günlüğe kaydetme örneklerine göz atın .

Her Handler için seviyeyi değiştirmek için aynı şekilde Handler.setLevel () fonksiyonunu kullanın .

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
Bu genellikle yararlı bir bilgidir, ancak soru, ek bir işleyicinin nasıl ekleneceğini değil, konsol günlüğünün nasıl devre dışı bırakılacağını sordu. my_logger.handlers'ı yukarıdaki kod orijinal örneğe uygulanmış olarak inceleyecekseniz, iki işleyici görürsünüz - yeni dosya işleyiciniz ve orijinal akış işleyiciniz.
Joe

Aradığım kelime KRİTİK idi. Teşekkürler.
Nishant

Bir hata ayıklama düzeyi OFF görmek isterim. Açık ve basittir.
Makine değil

46

(uzun ölü soru, ancak gelecekteki araştırmacılar için)

Orijinal posterin koduna / amacına daha yakın, bu benim için python 2.6 altında çalışıyor

#!/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")

Çalışmak zorunda kaldım, yeni bir tane ekledikten sonra stdout işleyicisini çıkarmaktı ; hiçbir işleyici yoksa, günlükçü kodu stdout'u otomatik olarak yeniden ekler.


2
logger = logging.getLogger(); lhStdout = logger.handlers[0]Kök kaydedicide başlangıçta işleyici bulunmadığından dizi yanlıştır python -c "import logging; assert not logging.getLogger().handlers". Python 2.7.15 ve Python 3.6.6 ile doğrulanmıştır.
Piotr Dobrogost

42

İçerik yöneticisi

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

Kullanım örneği:

with DisableLogger():
    do_something()

Bu deyimi gerçekten seviyorum, ancak belirli bir ad alanını devre dışı bırakmayı tercih ederim. Örneğin, kök kaydedicinin geçici olarak devre dışı bırakılmasını istiyorum. Bu deyimi kullanmasına rağmen, işleyicileri ve benzerlerini geçici olarak ekleyebilmemiz / kaldırabilmemiz gerekir.
Chris

1
Soru, yalnızca varsayılan StreamHandler öğesinin nasıl devre dışı bırakılacağını sorar .
Piotr Dobrogost

1
Kendi sınıfınızı atmanıza gerek yok, contextlib'den @contextmanager kullanabilir ve verimli bir işlev yazabilirsiniz
KristianR

Eğer pizza egzotik meyve içine iseniz. Elbette.
user3504575

34

Günlük kaydını tamamen devre dışı bırakmak için :

logging.disable(sys.maxint) # Python 2

logging.disable(sys.maxsize) # Python 3

Günlüğe kaydetmeyi etkinleştirmek için :

logging.disable(logging.NOTSET)

Diğer cevaplar, sorunu tam olarak çözmeyen, örneğin

logging.getLogger().disabled = True

ve n50 yaşından büyükler için,

logging.disable(n)

İlk çözümle ilgili sorun, yalnızca kök kaydedici için çalışmasıdır. Diyelim ki logging.getLogger(__name__)bu yöntemle oluşturulan diğer kaydediciler bu yöntemle devre dışı bırakılmaz.

İkinci çözüm tüm günlükleri etkiler. Ancak çıktıyı verilenin üzerinde seviyelere sınırlar, böylece biri 50'den daha yüksek bir seviyeyle günlüğe kaydederek onu geçersiz kılabilir.

Bu önlenebilir

logging.disable(sys.maxint)

( kaynak inceledikten sonra ) günlüğe kaydetmeyi tamamen devre dışı bırakmanın tek yoludur.


1
Soru olarak aşağıya oy verin, sadece
Piotr Dobrogost

27

Burada gerçekten güzel cevaplar var, ama görünüşe göre en basitleri çok fazla dikkate almıyor (sadece infinito'dan).

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

Bu, kök kaydedicisini ve böylece diğer tüm günlükleyicileri devre dışı bırakır. Gerçekten test etmedim ama aynı zamanda en hızlısı olmalı.

Python 2.7'deki günlük kodundan bunu görüyorum

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)

Bu, devre dışı bırakıldığında hiçbir işleyicinin çağrılmadığı ve örneğin çok yüksek bir değere göre filtrelemenin veya örneğin bir op-olmayan işleyicinin ayarlanmasının daha verimli olması gerektiği anlamına gelir.


1
Yanlış bir şey yapmadıkça, bu sadece kök kaydediciyi devre dışı bırakır ve herhangi bir yaratılmış gibi değillog = logging.getLogger(__name__)
starfry

2
Birden çok kaydedici veya birden çok işleyici ile uğraşıyorsanız bu sorunlu olabilir. Örneğin, yine de bir dosyaya oturum açmak istiyorsanız, ancak belirli bir durumda akış işleyicisini devre dışı bırakmak istiyorsanız.
Joe

1
Bu, kök kaydediciyi devre dışı bırakır ve böylece diğer tüm kaydediciler - kesin olarak söylemek gerekirse, kök kaydediciyi devre dışı bırakmak başka hiçbir kaydediciyi devre dışı bırakmaz. Sorunun yanı sıra, yalnızca varsayılan StreamHandler'ı devre dışı bırakma hakkında sorular sorulur .
Piotr Dobrogost

disabledNitelik ortak API parçası değildir. Bkz. Bugs.python.org/issue36318 .
Maggyero

10

Stdout'u yönlendirmeye gerek yok. İşte bunu yapmanın daha iyi bir yolu:

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

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

Daha da basit bir yol:

logging.getLogger().setLevel(100)


1
Bunun çalışmasının nedeni (varsayılan StreamHandler'ı devre dışı bırakır) logging.basicConfig()işlevin açıklamasını okurken görülebilir (benimki vurgu): Varsayılan Biçimlendiriciye sahip bir StreamHandler oluşturarak ve kök kaydediciye ekleyerek günlük sistemi için temel yapılandırma yapar. Hata günlüğü (), info (), uyarı (), hata () ve kritik () işlevleri , kök günlüğü için hiçbir işleyici tanımlanmamışsa otomatik olarak basicConfig () öğesini çağırır . - docs.python.org/3/library/logging.html#logging.basicConfig
Piotr Dobrogost

2

Günlük modülünü çok iyi bilmiyorum, ancak genellikle yalnızca hata ayıklama (veya bilgi) iletilerini devre dışı bırakmak istediğim şekilde kullanıyorum. Handler.setLevel()Günlük kaydı düzeyini CRITICAL veya daha yüksek bir değere ayarlamak için kullanabilirsiniz .

Ayrıca, sys.stderr ve sys.stdout dosyalarını yazmak için açık bir dosya ile değiştirebilirsiniz. Bkz. Http://docs.python.org/library/sys.html#sys. stdout . Ama bunu tavsiye etmem.


Logger.handlers şu anda bir şey içeriyorsa bu işe yarayabilir [].
sorin

2

Ayrıca yapabilirdin:

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

Neden app.loggersoruda ( logging.getLogger()) ve çoğu yanıtta açıkça belirtilen kök kaydedici yerine belirtmediğinizi bile kullanıyorsunuz ? handlersArama Logger.addHandleryöntemi yerine özelliği güvenli bir şekilde değiştirebileceğinizi nereden biliyorsunuz ?
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')

Konsol çıkışı:

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 dosya içeriği:

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
Kod hakkında bir açıklama ekleyin. Çok daha iyi yardımcı olur
Mathews Güneşli

2

"Logging.config.dictConfig" içindeki bir düzeyi değiştirerek, tüm günlük kaydı düzeyini yeni bir düzeye taşıyabilirsiniz.

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

Dekoratörler kullanarak aşağıdaki sorunu ele alan zarif bir çözüm buldum : ya birkaç işlevi olan bir modül yazıyorsanız, her biri birkaç hata ayıklama mesajı olan ve şu anda odaklanmakta olduğunuz tüm işlevlerde günlüğe kaydetmeyi devre dışı bırakmak istiyorsanız ne olacak?

Dekoratörleri kullanarak yapabilirsiniz:

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

Sonra şunları yapabilirsiniz:

@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")
    ...

Aradığınızda bile function_already_debuggediçinden function_being_focusedgelen ayıklama mesajları function_already_debuggedirade değil gösterdi edilebilir. Bu, yalnızca odaklandığınız işlevdeki hata ayıklama iletilerini görmenizi sağlar.

Umarım yardımcı olur!


0

Belirli bir kaydediciyi geçici olarak devre dışı bırakmak istiyorsanız, işte burada ne var.

Örnek Günlük

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

kod

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

0

Günlük Python kitaplığında, aşağıdakilerden birini yaparak belirli bir günlükçünün günlük kaydını ( tüm düzeyler için) tamamen devre dışı bırakabilirsiniz :

  1. Bir kaydedici ekleme logging.NullHandler()işleyici (önlemek için logging.lastResortşiddeti olaylarını açmasını işleyicisi logging.WARNINGiçin ve daha fazla sys.stderrve) ayarı propagateiçin bu kaydedicisi niteliğiniFalse (kendi soy kaydedicilerinin işleyicileri olayları geçmesini kayıt cihazı önlemek için).

    • Ana API'yı kullanma:

      import logging
      
      logging.getLogger("foo").addHandler(logging.NullHandler())
      logging.getLogger("foo").propagate = False
    • Yapılandırma API'sını kullanma:

      import logging.config
      
      logging.config.dictConfig({
          "version": 1,
          "handlers": {
              "null": {
                  "class": "logging.NullHandler"
              }
          },
          "loggers": {
              "foo": {
                  "handlers": ["null"],
                  "propagate": False
              }
          }
      })
  2. Kaydediciye bir lambda record: Falsefiltre ekleme .

    • Ana API'yı kullanma:

      import logging
      
      logging.getLogger("foo").addFilter(lambda record: False)
    • Yapılandırma API'sını kullanma:

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

Uyarı. - 1. çözümün aksine, 2. çözüm alt günlüklerden (örneğin logging.getLogger("foo.bar")) günlüğe kaydetmeyi devre dışı bırakmaz , bu nedenle yalnızca tek bir günlükçü için günlüğe kaydetmeyi devre dışı bırakmak için kullanılmalıdır.

Not. - Günlük API'sının bir parçası olmadığı için günlükçünün disabledniteliğini ayarlamak True3. bir çözüm değildir. Bkz. Https://bugs.python.org/issue36318 :

import logging

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

-1

geçici olarak devre dışı bırakmak istediğiniz işleyiciyi alt sınıflara ayırın:

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)

işleyiciyi adıyla bulmak oldukça kolaydır:

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

bir kez bulundu:

_handler.disable()
doStuff()
_handler.enable()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.