Python Logging - Nonaktifkan logging dari modul yang diimpor


100

Saya menggunakan modul logging Python, dan ingin menonaktifkan pesan log yang dicetak oleh modul pihak ketiga yang saya impor. Misalnya, saya menggunakan sesuatu seperti berikut:

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)

Ini mencetak pesan debug saya ketika saya melakukan logger.debug ("pesan saya!"), Tetapi juga mencetak pesan debug dari modul apa pun yang saya impor (seperti permintaan, dan sejumlah hal lainnya).

Saya hanya ingin melihat pesan log dari modul yang saya minati. Apakah mungkin membuat modul logging melakukan ini?

Idealnya, saya ingin memberi tahu logger untuk mencetak pesan dari "ModuleX, ModuleY" dan mengabaikan yang lainnya.

Saya melihat yang berikut, tetapi saya tidak ingin menonaktifkan / mengaktifkan logging sebelum setiap panggilan ke fungsi yang diimpor: logging - bagaimana cara mengabaikan log modul yang diimpor?

Jawaban:


70

Masalahnya adalah bahwa memanggil getLoggertanpa argumen mengembalikan logger root jadi saat Anda menyetel level ke logging.DEBUGAnda juga menyetel level untuk modul lain yang menggunakan logger itu.

Anda dapat mengatasi ini hanya dengan tidak menggunakan logger root. Untuk melakukan ini, cukup berikan nama sebagai argumen, misalnya nama modul Anda:

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

ini akan membuat logger baru dan karenanya tidak akan secara tidak sengaja mengubah level logging untuk modul lain.


Jelas Anda harus menggunakan logger.debugdaripada logging.debugkarena yang terakhir adalah fungsi praktis yang memanggil debugmetode logger root.

Ini disebutkan dalam Tutorial Logging Lanjutan . Ini juga memungkinkan Anda untuk mengetahui modul mana yang memicu pesan log dengan cara yang sederhana.


37
Saya membuat logger dengan __name__r tetapi saya masih melihat log dari modul yang diimpor. Saya mencoba mengkonfigurasi logging dengan file konfigurasi ini. Apa yang harus saya lakukan untuk itu?
Durga Swaroop

8
Membuat logger dengan __name__juga tidak berhasil untuk saya. Mungkin karena saya menggunakan skrip mandiri dan bukan "modul"? Apa yang berhasil bagi saya adalah mengonfigurasi logging untuk modul yang diimpor ( matpplotlib, dalam kasus saya) melalui logging.getLogger("matplotlib").setLevel(logging.WARNING)dan untuk skrip saya via logging.basicConfig.
bli

1
Saya hanya ingin menyoroti nilai baris Anda "Jelas Anda harus menggunakan, logger.debugbukan logging.debug". Ini adalah kesalahan yang mudah untuk membuat menggunakan logging daripada logger tetapi itu merebut semua konfigurasi pintar yang ingin Anda atur. Saya telah menghabiskan beberapa jam terakhir menjalani ini!
timdadev

@bli Ada perbedaan besar antara logging saat mengembangkan pustaka vs saat mengembangkan executable. Pada dasarnya: jika Anda menulis modul / paket yang dimaksudkan untuk diimpor, Anda tidak boleh mengkonfigurasi apa pun. Modul hanya boleh berisi logger = logging.getLogger('package.my_module')panggilan and your could logger.debug/warning, tidak perlu mengonfigurasi penangan atau level logging. Saat Anda menulis aplikasi biner di sana, Anda harus memutuskan level untuk berbagai log dan penangannya. Pustaka yang berisi konfigurasi logging akan selalu menjadi masalah.
Bakuriu

1
@IanS Tidak, itu sebabnya perpustakaan tidak boleh menggunakan logger root. Silakan buka laporan bug ke perpustakaan itu dan beri tahu mereka untuk menggunakannya logging.getLogger(__name__).
Bakuriu

45

Jika Anda akan menggunakan loggingpaket python , itu adalah konvensi umum untuk mendefinisikan logger di setiap modul yang menggunakannya.

logger = logging.getLogger(__name__)

Banyak paket python populer melakukan ini, termasuk requests. Jika sebuah paket menggunakan konvensi ini, mudah untuk mengaktifkan / menonaktifkan pencatatan untuk itu, karena nama pencatat akan menjadi nama yang sama dengan paket (atau akan menjadi anak dari pencatat itu). Anda bahkan dapat memasukkannya ke file yang sama dengan logger Anda yang lain.

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
Sadarilah, bahwa ketika Anda mencoba mengkonfigurasi logger Anda seperti di tutorial dasar resmi dengan logging.basicConfig(...)semua logger sekarang akan menampilkan logging.lastResort(dimulai dengan Python 3.2, yang merupakan stderr) jika tidak ada penangan yang diberikan atau ke penangan yang Anda tetapkan. Jadi jangan menggunakannya atau Anda akan terus mendapatkan semua pesan log.
pengguna136036

44

Tidak yakin apakah ini pantas untuk diposkan, tetapi saya terhenti untuk waktu yang lama & ingin membantu siapa pun dengan masalah yang sama, karena saya tidak menemukannya di tempat lain!

Saya mendapatkan log debug dari matplotlib meskipun mengikuti dokumentasi yang cukup mudah di tutorial lanjutan logging dan pemecahan masalah . Saya memulai logger saya di main()satu file dan mengimpor fungsi untuk membuat plot dari file lain (tempat saya mengimpor matplotlib).

Apa yang berhasil untuk saya adalah mengatur level matplotlib sebelum mengimpornya, daripada setelahnya seperti yang saya lakukan untuk modul lain di file utama saya. Ini tampak berlawanan dengan intuisi bagi saya, jadi jika ada yang memiliki wawasan tentang bagaimana Anda dapat mengatur konfigurasi untuk logger yang belum diimpor, saya akan penasaran untuk mencari tahu cara kerjanya. Terima kasih!

Di file utama saya:

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

def main():
  ...

Di plot.pyfile saya :

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

def generatePlot():
  ...

Saya mendapat kesalahan: Objek 'Logger' tidak memiliki atribut 'DEBUG'. logger.DEBUGharuslogging.DEBUG
foxiris

Terima kasih! Ini sangat membantu! Saya mengatur tingkat logging matplotlib setelah konfigurasi logging utama saya dan sebelum perintah yang akan mengimpor matplotlib. Terpecahkan!
gph

Saya telah menyetel logging matplotlibmenjadi WARNING setelah saya mengimpor modul, karena menambahkannya sebelum mengimpor akan memberikan kesalahan lint. Itu masih berhasil untuk saya. Saya menggunakan matplotlib==3.3.2Python 3.7 jika itu membantu.
Akhir-2-Akhir

9

@Bakuriu menjelaskan fungsinya dengan cukup elegan. Sebaliknya, Anda dapat menggunakan getLogger()metode ini untuk mengambil dan mengkonfigurasi ulang / menonaktifkan logger yang tidak diinginkan.

Saya juga ingin menambahkan logging.fileConfig()metode menerima parameter yang disebut disable_existing_loggersyang akan menonaktifkan setiap penebang yang ditentukan sebelumnya (yaitu, dalam modul yang diimpor).


9

Ini menonaktifkan semua logger yang ada, seperti yang dibuat oleh modul yang diimpor, saat masih menggunakan logger root (dan tanpa harus memuat file eksternal).

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

Perhatikan bahwa Anda perlu mengimpor semua modul yang tidak ingin Anda masuki terlebih dahulu! Jika tidak, mereka tidak akan dianggap sebagai "penebang yang ada". Ini kemudian akan menonaktifkan semua penebang dari modul tersebut. Ini mungkin membuat Anda juga melewatkan kesalahan penting!

Untuk contoh yang lebih mendetail menggunakan opsi terkait untuk konfigurasi, lihat https://gist.github.com/st4lk/6287746 , dan berikut adalah contoh (sebagian berfungsi) menggunakan YAML untuk konfigurasi dengan coloredlogpustaka.


Apa pertanyaanmu?
pengguna1767754

1
Ini berfungsi requestmisalnya, tetapi tidak akan berfungsi saat modul yang diimpor membuat loggernya di dalam kelas yang akan Anda panggil nanti, seperti yang APSchedulerdilakukan saat Anda memanggil BackgroundScheduler.BackgroundScheduler(). Lihat di sini untuk solusinya: stackoverflow.com/a/48891485/2441026
user136036

Ini berfungsi untuk kasus saya dengan file konfigurasi yaml
user4015990

4

Anda bisa menggunakan sesuatu seperti:

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

Ini akan menyetel tingkat log modul saya sendiri ke DEBUG, sekaligus mencegah modul yang diimpor menggunakan tingkat yang sama.

Catatan: "imported_module"bisa diganti dengan imported_module.__name__(tanpa tanda kutip), dan "my_own_logger_name"bisa diganti __name__jika itu cara yang Anda inginkan.


1

Saya memiliki masalah yang sama. Saya memiliki file logging_config.py yang saya impor di semua file py lainnya. Di file logging_config.py saya mengatur tingkat logging root logger ke ERROR (secara default peringatannya):

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

Di modul lain saya mengimpor logging_config.py dan mendeklarasikan logger baru dan mengatur levelnya ke debug:

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

Dengan cara ini semua yang saya masuk ke file py saya dicatat, tetapi hal-hal yang dicatat di debug dan tingkat info oleh modul yang diimpor seperti urllib, request, boto3 dll tidak dicatat. Jika ada beberapa kesalahan dalam modul impor tersebut, maka itu dicatat, karena saya menyetel tingkat logger root ke ERROR.


0

Hal lain yang perlu dipertimbangkan adalah properti propagasi kelas Logger.

Misalnya, pustaka py-suds untuk menangani panggilan sabun, bahkan dimasukkan ke 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)

log log tentang modul bernama sxbasics.py creationg sejumlah besar log

masukkan deskripsi gambar di sini

bahwa karena penyebaran log adalah True secara default, menyetel ke False, sebaliknya, saya memulihkan 514MB log.

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)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.