Python Günlüğü - İçe aktarılan modüllerden günlük kaydını devre dışı bırak


100

Python günlük modülünü kullanıyorum ve içe aktardığım üçüncü taraf modüller tarafından yazdırılan günlük mesajlarını devre dışı bırakmak istiyorum. Örneğin, aşağıdaki gibi bir şey kullanıyorum:

logger = logging.getLogger()
logger.setLevel(level=logging.DEBUG)
fh = logging.StreamHandler()
fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
fh.setFormatter(fh_formatter)
logger.addHandler(fh)

Bu, bir logger.debug ("mesajım!") Yaptığımda hata ayıklama mesajlarını yazdırır, ancak aynı zamanda içe aktardığım herhangi bir modülden (istekler ve bir dizi başka şey gibi) hata ayıklama mesajlarını da yazdırır.

Yalnızca ilgilendiğim modüllerin günlük mesajlarını görmek istiyorum. Günlük modülünün bunu yapmasını sağlamak mümkün mü?

İdeal olarak, kaydediciye "ModuleX, ModuleY" den gelen mesajları yazdırmasını ve diğerlerini yok saymasını söyleyebilmek istiyorum.

Aşağıdakilere baktım, ancak içe aktarılan bir işleve yapılan her çağrıdan önce günlüğe kaydetmeyi devre dışı bırakmak / etkinleştirmek istemiyorum: günlük kaydı - içe aktarılan modül günlükleri nasıl yok sayılır?

Yanıtlar:


70

Sorun, getLoggerargümansız çağrı yapmanın kök kaydediciyi döndürmesidir, bu nedenle seviyeyi size ayarladığınızda, logging.DEBUGbu günlükçüyü kullanan diğer modüller için de seviyeyi ayarlarsınız .

Sadece bu çözebilir değil kök logger kullanarak. Bunu yapmak için, bağımsız değişken olarak bir ad iletin, örneğin modülünüzün adı:

logger = logging.getLogger('my_module_name')
# as before

bu yeni bir kaydedici oluşturacak ve böylece yanlışlıkla diğer modüller için kayıt seviyesini değiştirmeyecektir.


Açıkçası logger.debugbunun yerine kullanmanız gerekir , logging.debugçünkü ikincisi, debugkök kaydedicinin yöntemini çağıran kullanışlı bir işlevdir .

Bu, Gelişmiş Günlük Kaydı Eğitiminde belirtilmiştir . Ayrıca, günlük mesajını hangi modülün tetiklediğini basit bir şekilde bilmenizi sağlar.


37
__name__R ile bir kaydedici oluşturuyorum ancak yine de içe aktarılan modüllerden günlükleri görüyorum. Bir ini yapılandırma dosyası ile günlük kaydını yapılandırmaya çalışıyorum bunun için ne yapmalıyım?
Durga Swaroop

8
İle bir logger oluşturmak __name__da benim için işe yaramadı. Belki bir "modül" değil de bağımsız bir komut dosyası kullandığım için? Benim için işe yarayan şey, içe aktarılan modüller için ( matpplotlibbenim durumumda) logging.getLogger("matplotlib").setLevel(logging.WARNING)komut dosyam aracılığıyla ve aracılığıyla günlük kaydını yapılandırmaktı logging.basicConfig.
bli

1
Sadece "Açıkçası logger.debugbunun yerine kullanmak zorundasın logging.debug. Kaydedici yerine günlük kaydını kullanmak kolay bir hatadır, ancak kurmak istediğiniz tüm akıllı yapılandırmayı gasp eder. Son birkaç saati bunu yaşayarak geçirdim!
timdadev

@bli Bir kitaplık geliştirirken günlüğe kaydetme ile bir yürütülebilir dosya geliştirirken arasında büyük bir fark vardır. Temelde: Eğer gerektiği ithal çıkartılacaktır bir modül / paket yazıyorsanız değil yapılandırmak şey. Modül, yalnızca logger = logging.getLogger('package.my_module')ve sizin aramalarınızı içermelidir, logger.debug/warningkayıt seviyeleri veya işleyicileri yapılandırılmamalıdır. Eğer ikili bir uygulama yazarken orada çeşitli kütükler ve işleyicileri için seviyesini karar vermelidir. Günlük yapılandırması içeren kitaplıklar her zaman bir sorun olacaktır.
Bakuriu

1
Kütüphaneler neden var @IanS Hayır, değil kök kayıt kullanımı. Lütfen bu kitaplığa bir hata raporu açın ve logging.getLogger(__name__)onun yerine kullanmalarını söyleyin .
Bakuriu

45

Python loggingpaketini kullanacaksanız , onu kullanan her modülde bir günlükçü tanımlamak yaygın bir kuraldır.

logger = logging.getLogger(__name__)

Birçok popüler python paketi bunu yapar requests. Bir paket bu kuralı kullanıyorsa, günlük kaydını etkinleştirmek / devre dışı bırakmak kolaydır, çünkü günlükçü adı paketle aynı ad olacaktır (veya bu kaydedicinin alt öğesi olacaktır). Hatta diğer kaydedicilerinizle aynı dosyaya kaydedebilirsiniz.

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

requests_logger = logging.getLogger('requests')
requests_logger.setLevel(logging.DEBUG)

handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
logger.addHandler(handler)
requests_logger.addHandler(handler)

15
Kaydedicilerinizi resmi temel öğreticide olduğu gibi logging.basicConfig(...)tüm kaydedicilerle yapılandırmaya çalıştığınızda artık logging.lastResorthiçbir işleyici verilmemişse (Python 3.2'den başlayarak, stderr) veya ayarladığınız işleyiciye çıktı vereceğini unutmayın. Bu yüzden kullanmayın, yoksa yine de tüm günlük mesajlarını almaya devam edeceksiniz.
user136036

44

Bunun yayınlamak için uygun olup olmadığından emin değilim, ancak uzun süredir takılı kaldım ve başka hiçbir yerde bulamadığım için aynı sorunu yaşayan herkese yardım etmek istedim!

Günlüğe kaydetme gelişmiş öğreticisi ve sorun giderme bölümündeki oldukça basit belgeleri izlememe rağmen matplotlib'den hata ayıklama günlükleri alıyordum . Logger'ımı main()bir dosyadan başlatıyordum ve başka bir dosyadan bir çizim oluşturmak için bir işlevi içe aktarıyordum (matplotlib'i içe aktarmıştım).

Benim için işe yarayan şey, matplotlib seviyesini, ana dosyamdaki diğer modüller için olduğu gibi içe aktarmadan önce ayarlamaktı . Bu bana mantığa aykırı göründü, bu yüzden herhangi biri henüz içe aktarılmamış bir kaydedici için yapılandırmayı nasıl ayarlayabileceğiniz konusunda bir fikir sahibi olursa, bunun nasıl çalıştığını merak ederdim. Teşekkürler!

Ana dosyamda:

import logging
import requests
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logging.getLogger('requests').setLevel(logging.DEBUG)

def main():
  ...

Benim içinde plot.pydosyaya:

import logging
logging.getLogger('matplotlib').setLevel(logging.WARNING)
import matplotlib.pyplot as plt

def generatePlot():
  ...

Hata aldım: 'Logger' nesnesinin 'DEBUG' özniteliği yok. logger.DEBUGolmalıdırlogging.DEBUG
foxiris

Teşekkürler! Gerçekten yardımcı oluyor! Ana loglama konfigürasyonumdan sonra ve matplotlib'i içe aktaracak komuttan önce matplotlib loglama seviyesini ayarlıyorum. Çözüldü!
gph

Ben günlüğü kurdum matplotlibiçin WARNING sonra ben bir tiftik hatası verecekti aktarmadan önce eklemeden beri modülü ithal ettik. Hala benim için çalıştı. matplotlib==3.3.2Yardımcı olursa Python 3.7'de kullanıyorum .
sonu

9

@Bakuriu işlevi oldukça zarif bir şekilde açıklıyor. Tersine, getLogger()istenmeyen günlükleri almak ve yeniden yapılandırmak / devre dışı bırakmak için yöntemi kullanabilirsiniz .

Ayrıca logging.fileConfig()yöntemin disable_existing_loggersönceden tanımlanmış (yani içe aktarılan modüllerde) herhangi bir günlükçüyü devre dışı bırakacak bir parametreyi kabul ettiğini eklemek istedim .


9

Bu, kök kaydediciyi kullanırken (ve harici bir dosya yüklemeye gerek kalmadan) içe aktarılan modüller tarafından oluşturulanlar gibi mevcut tüm kaydedicileri devre dışı bırakır.

logging.config.dictConfig({
    'version': 1,
    'disable_existing_loggers': True,
})

Öncelikle günlüğe kaydedilmesini istemediğiniz tüm modülleri içe aktarmanız gerektiğini unutmayın! Aksi takdirde bunlar "mevcut kaydediciler" olarak kabul edilmeyecektir. Daha sonra bu modüllerdeki tüm kaydedicileri devre dışı bırakacaktır. Bu, önemli hataları da gözden kaçırmanıza neden olabilir!

Yapılandırma için ilgili seçenekleri kullanan daha ayrıntılı örnekler için bkz. Https://gist.github.com/st4lk/6287746 ve iştecoloredlog kitaplıkla yapılandırma için YAML kullanan (kısmen çalışan) bir örnek .


Sorunuz nedir?
user1767754

1
Bu request, örneğin işe yarar, ancak aktarılan modüller, aradığınızda olduğu gibi, daha sonra arayacağınız kendi sınıflarında kendi kayıt cihazlarını oluşturduğunda APSchedulerçalışmaz BackgroundScheduler.BackgroundScheduler(). Çözüm için buraya bakın: stackoverflow.com/a/48891485/2441026
user136036

Bu, yaml yapılandırma dosyası
user4015990

4

Şunun gibi bir şey kullanabilirsiniz:

logging.getLogger("imported_module").setLevel(logging.WARNING)
logging.getLogger("my_own_logger_name").setLevel(logging.DEBUG)

Bu, içe aktarılan modülün aynı seviyeyi kullanmasını önlerken kendi modülümün günlük seviyesini DEBUG olarak ayarlayacak.

Not: "imported_module"ile değiştirilebilir imported_module.__name__(tırnaklar olmadan) ve "my_own_logger_name"ile değiştirilebilir __name__buna öyle yapmayı tercih yolu buysa.


1

Ben de aynı sorunu yaşadım. Diğer tüm py dosyalarında içe aktardığım bir logging_config.py dosyam var. Logging_config.py dosyasında, root logger günlük kaydı seviyesini ERROR olarak ayarladım (varsayılan olarak bu uyarı):

logging.basicConfig(
    handlers=[
        RotatingFileHandler('logs.log',maxBytes=1000, backupCount=2),
        logging.StreamHandler(), #print to console
    ],
    level=logging.ERROR
)

Diğer modüllerde logging_config.py dosyasını içe aktarıyorum ve yeni bir günlükçü bildiriyorum ve seviyesini hata ayıklamak için ayarlıyorum:

log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)

Bu şekilde py dosyalarımda oturum açtığım her şey günlüğe kaydedilir, ancak urllib, istek, boto3 vb. Gibi içe aktarılan modüller tarafından hata ayıklama ve bilgi düzeyinde günlüğe kaydedilen şeyler günlüğe kaydedilmez. Bu içe aktarma modülünde bir hata varsa, kök kaydedici seviyesini ERROR olarak ayarladığım için günlüğe kaydedilir.


0

Dikkate alınması gereken bir diğer husus , Logger sınıfının yayılma özelliğidir.

Örneğin, sabun çağrılarını işlemek için py-suds kitaplığı, hatta ERROR

logging.getLogger('suds.client').setLevel(logging.ERROR)
logging.getLogger('suds.transport').setLevel(logging.ERROR)
logging.getLogger('suds.xsdschema').setLevel(logging.ERROR)
logging.getLogger('suds.wsdl').setLevel(logging.ERROR)

sxbasics.py adlı bir modül hakkında günlükler, çok büyük miktarda günlük oluşturma

görüntü açıklamasını buraya girin

çünkü günlüklerin yayılımı varsayılan olarak True olduğundan, False olarak ayarlandığında, bunun yerine 514MB günlükleri kurtardım.

import logging
logging.getLogger("suds").propagate = False
logging.getLogger('suds.client').setLevel(logging.ERROR)
logging.getLogger('suds.transport').setLevel(logging.ERROR)
logging.getLogger('suds.xsdschema').setLevel(logging.ERROR)
logging.getLogger('suds.wsdl').setLevel(logging.ERROR)
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.