Saya sedang menulis program yang mem-parsing 10 situs web, mencari file data, menyimpan file, dan kemudian mem-parsingnya untuk membuat data yang dapat dengan mudah digunakan di perpustakaan NumPy. Ada banyak kesalahan yang ditemui file ini melalui tautan buruk, XML yang dibentuk dengan buruk, entri yang hilang, dan hal-hal lain yang belum saya kategorikan. Saya awalnya membuat program ini untuk menangani kesalahan seperti ini:
try:
do_stuff()
except:
pass
Tapi sekarang saya ingin mencatat kesalahan:
try:
do_stuff()
except Exception, err:
print Exception, err
Perhatikan ini dicetak ke file log untuk ditinjau nanti. Ini biasanya mencetak data yang sangat tidak berguna. Apa yang saya inginkan adalah mencetak baris yang sama persis yang dicetak ketika kesalahan muncul tanpa coba-kecuali mencegat pengecualian, tapi saya tidak ingin itu menghentikan program saya karena itu bersarang dalam serangkaian loop yang saya ingin lihat sampai selesai.
sumber
print(sys.exc_info()[0]
cetakan<class 'Exception'>
.Jika Anda sedang debug dan hanya ingin melihat jejak stack saat ini, Anda dapat memanggil:
traceback.print_stack()
Tidak perlu mengajukan pengecualian secara manual hanya untuk menangkapnya lagi.
sumber
Ketika Anda tidak ingin menghentikan program Anda karena kesalahan, Anda perlu menangani kesalahan itu dengan mencoba / kecuali:
Untuk mengekstrak traceback penuh, kami akan menggunakan
traceback
modul dari pustaka standar:Dan untuk membuat stacktrace yang cukup rumit untuk menunjukkan bahwa kita mendapatkan stacktrace lengkap:
Pencetakan
Untuk mencetak traceback penuh, gunakan
traceback.print_exc
metode ini:Yang mencetak:
Lebih baik daripada mencetak, masuk:
Namun, praktik terbaik adalah membuat logger diatur untuk modul Anda. Ia akan mengetahui nama modul dan dapat mengubah level (di antara atribut lainnya, seperti penangan)
Dalam hal ini, Anda akan menginginkan
logger.exception
fungsinya sebagai gantinya:Log mana:
Atau mungkin Anda hanya menginginkan string, dalam hal ini, Anda akan menginginkan
traceback.format_exc
fungsinya sebagai gantinya:Log mana:
Kesimpulan
Dan untuk ketiga opsi ini, kami melihat kami mendapatkan output yang sama seperti ketika kami memiliki kesalahan:
sumber
traceback.print_exc()
hanya mengembalikan panggilan terakhir: bagaimana Anda berhasil mengembalikan beberapa tingkat tumpukan (dan mungkin semua level?)raise
chaining telanjang atau pengecualian, atau apakah Anda menyembunyikan traceback aslinya? lihat stackoverflow.com/questions/2052390/...Pertama, jangan gunakan
print
karena penebangan, ada astabil, terbukti dan dipikirkan modul stdlib untuk melakukannya:logging
. Anda tentu harus menggunakannya sebagai gantinya.Kedua, jangan tergoda untuk melakukan kekacauan dengan alat yang tidak terkait ketika ada pendekatan asli dan sederhana. Ini dia:
Itu dia. Anda selesai sekarang.
Penjelasan untuk siapa saja yang tertarik dengan cara kerja sesuatu di bawah tenda
Apa
log.exception
yang sebenarnya dilakukan hanyalah panggilan kelog.error
(yaitu, log event dengan levelERROR
) dan cetak traceback kemudian.Mengapa ini lebih baik?
Nah, berikut beberapa pertimbangannya:
Mengapa tidak ada yang menggunakan
traceback
atau memanggil logger denganexc_info=True
atau membuat tangan mereka kotorsys.exc_info
?Ya, hanya karena! Mereka semua ada untuk tujuan yang berbeda. Sebagai contoh,
traceback.print_exc
output sedikit berbeda dari traceback yang diproduksi oleh interpreter itu sendiri. Jika Anda menggunakannya, Anda akan membingungkan siapa pun yang membaca log Anda, mereka akan membenturkan kepalanya ke mereka.Melewati
exc_info=True
untuk mencatat panggilan tidak tepat. Tapi , ini berguna ketika menangkap kesalahan yang dapat dipulihkan dan Anda ingin mencatatnya (menggunakan, misalnyaINFO
level) dengan traceback juga, karenalog.exception
menghasilkan log hanya satu level -ERROR
.Dan Anda harus menghindari bermain-main
sys.exc_info
sebanyak mungkin. Ini bukan antarmuka publik, ini antarmuka internal - Anda dapat menggunakannya jika Anda benar-benar tahu apa yang Anda lakukan. Ini tidak dimaksudkan hanya untuk mencetak pengecualian.sumber
logging.exception()
. Tidak perlu membuat instance log kecuali Anda memiliki persyaratan khusus.Selain jawaban @Aaron Hall, jika Anda masuk, tetapi tidak ingin menggunakan
logging.exception()
(karena log di tingkat ERROR), Anda dapat menggunakan tingkat yang lebih rendah dan lulusexc_info=True
. misalnyasumber
Untuk mendapatkan jejak stack yang tepat , sebagai string, yang akan dinaikkan jika tidak ada coba / kecuali ada di sana untuk melangkahi, cukup letakkan ini di blok kecuali yang menangkap pengecualian yang menyinggung.
Berikut cara menggunakannya (dengan asumsi
flaky_func
didefinisikan, danlog
memanggil sistem logging favorit Anda):Ini ide yang bagus untuk menangkap dan menaikkan kembali
KeyboardInterrupt
, sehingga Anda masih bisa mematikan program menggunakan Ctrl-C. Logging berada di luar ruang lingkup pertanyaan, tetapi pilihan yang bagus adalah mencatat . Dokumentasi untuk sistem dan modul traceback .sumber
desired_trace = traceback.format_exc()
. Melewatisys.exc_info()
sebagai argumen tidak pernah merupakan hal yang benar untuk dilakukan, tetapi diabaikan dengan diam-diam dalam Python 2 — tetapi tidak dalam Python 3 (bagaimanapun, 3.6.4).KeyboardInterrupt
tidak berasal (langsung atau tidak langsung) dariException
. (Keduanya berasal dariBaseException
.) Ini berartiexcept Exception:
tidak akan pernah menangkapKeyboardInterrupt
, dan dengan demikianexcept KeyboardInterrupt: raise
sama sekali tidak perlu.traceback.format_exc(sys.exc_info())
tidak bekerja untuk saya dengan python 3.6.10Anda harus meletakkan try / kecuali di bagian paling dalam di mana kesalahan dapat terjadi, yaitu
... dan seterusnya
Dengan kata lain, Anda perlu membungkus pernyataan yang mungkin gagal dalam coba / kecuali sespesifik mungkin, dalam loop-dalam yang paling mungkin.
sumber
Sebuah komentar tentang komentar jawaban ini :
print(traceback.format_exc())
melakukan pekerjaan yang lebih baik untuk saya daripadatraceback.print_exc()
. Dengan yang terakhir,hello
kadang-kadang anehnya "dicampur" dengan teks traceback, seperti jika keduanya ingin menulis ke stdout atau stderr pada saat yang sama, menghasilkan output yang aneh (setidaknya ketika membangun dari dalam editor teks dan melihat output di Panel "Bangun hasil").Jadi saya menggunakan:
sumber
Saya tidak melihat ini disebutkan dalam jawaban lain. Jika Anda melewati objek Pengecualian untuk alasan apa pun ...
Di Python 3.5+ Anda bisa mendapatkan jejak dari objek Exception menggunakan traceback.TracebackException.from_exception () . Sebagai contoh:
Namun, kode di atas menghasilkan:
Ini hanya dua tingkat tumpukan, yang bertentangan dengan apa yang akan dicetak di layar seandainya pengecualian dimunculkan
stack_lvl_2()
dan tidak disadap (hapus komentar# raise
baris).Seperti yang saya pahami, itu karena pengecualian hanya mencatat level stack saat ini ketika dinaikkan,
stack_lvl_3()
dalam kasus ini. Ketika itu diteruskan kembali melalui tumpukan, lebih banyak level yang ditambahkan ke dalamnya__traceback__
. Tapi kami mencegatnyastack_lvl_2()
, artinya yang harus dicatat hanyalah level 3 dan 2. Untuk mendapatkan jejak lengkap seperti yang dicetak di stdout, kami harus menangkapnya di level tertinggi (terendah?):Yang mengakibatkan:
Perhatikan bahwa cetakan tumpukan berbeda, baris pertama dan terakhir tidak ada. Karena itu berbeda
format()
.Mencegah pengecualian sejauh mungkin dari titik dimunculkannya kode yang lebih sederhana sembari memberikan lebih banyak informasi.
sumber
Dapatkan traceback penuh sebagai string dari objek pengecualian
traceback.format_exception
Jika Anda hanya memiliki objek pengecualian, Anda bisa mendapatkan traceback sebagai string dari setiap titik kode di Python 3 dengan:
Contoh lengkap:
Keluaran:
Dokumentasi: https://docs.python.org/3.7/library/traceback.html#traceback.format_exception
Lihat juga: Ekstrak info traceback dari objek pengecualian
Diuji dalam Python 3.7.3.
sumber
Anda ingin modul traceback . Ini akan membiarkan Anda mencetak tumpukan dump seperti yang biasa dilakukan Python. Secara khusus, fungsi print_last akan mencetak pengecualian terakhir dan jejak stack.
sumber
Jika Anda sudah memiliki objek Galat, dan Anda ingin mencetak semuanya, Anda perlu melakukan panggilan yang sedikit canggung ini:
Itu benar,
print_exception
butuh tiga argumen posisi: Jenis pengecualian, objek pengecualian aktual, dan properti traceback internal pengecualian itu sendiri.Dalam python 3.5 atau yang lebih baru,
type(err)
ini opsional ... tapi itu adalah argumen posisi, jadi Anda masih harus secara eksplisit melewatkan None di tempatnya.Saya tidak tahu mengapa semua ini tidak adil
traceback.print_exception(err)
. Mengapa Anda ingin mencetak kesalahan, bersama dengan traceback selain dari kesalahan itu, ada di luar jangkauan saya.sumber