Jawaban:
Gunakan logging.exception
dari dalam except:
pawang / blok untuk mencatat pengecualian saat ini bersama dengan informasi jejak, yang diawali dengan pesan.
import logging
LOG_FILENAME = '/tmp/logging_example.out'
logging.basicConfig(filename=LOG_FILENAME, level=logging.DEBUG)
logging.debug('This message should go to the log file')
try:
run_my_stuff()
except:
logging.exception('Got exception on main handler')
raise
Sekarang melihat file log, /tmp/logging_example.out
:
DEBUG:root:This message should go to the log file
ERROR:root:Got exception on main handler
Traceback (most recent call last):
File "/tmp/teste.py", line 9, in <module>
run_my_stuff()
NameError: name 'run_my_stuff' is not defined
logger = logging.getLogger('yourlogger')
Anda harus menulis logger.exception('...')
agar ini berfungsi ...
Gunakan exc_info
opsi mungkin lebih baik, tetap judul peringatan atau kesalahan:
try:
# coode in here
except Exception as e:
logging.error(e, exc_info=True)
exc_info=
disebut kwarg; Terima kasih!
logging.exception
Pekerjaan saya baru-baru ini menugasi saya untuk mencatat semua traceback / pengecualian dari aplikasi kami. Saya mencoba berbagai teknik yang telah diposting orang lain secara online seperti yang di atas tetapi memilih pendekatan yang berbeda. Mengesampingkan traceback.print_exception
.
Saya punya tulisan di http://www.bbarrows.com/ Itu akan jauh lebih mudah dibaca tetapi saya akan menempelkannya di sini juga.
Ketika ditugaskan untuk mencatat semua pengecualian yang mungkin ditemui oleh perangkat lunak kami di alam liar, saya mencoba sejumlah teknik berbeda untuk mencatat traceback python pengecualian kami. Pada awalnya saya berpikir bahwa sistem hook python pengecualian, sys.excepthook akan menjadi tempat yang sempurna untuk memasukkan kode logging. Saya mencoba sesuatu yang mirip dengan:
import traceback
import StringIO
import logging
import os, sys
def my_excepthook(excType, excValue, traceback, logger=logger):
logger.error("Logging an uncaught exception",
exc_info=(excType, excValue, traceback))
sys.excepthook = my_excepthook
Ini berfungsi untuk utas utama tetapi saya segera menemukan bahwa sys.excepthook saya tidak akan ada di utas baru pun memulai proses saya. Ini adalah masalah besar karena kebanyakan semuanya terjadi di utas dalam proyek ini.
Setelah googling dan membaca banyak dokumentasi, informasi paling bermanfaat yang saya temukan adalah dari pelacak Isu Python.
Posting pertama di utas menunjukkan contoh kerja dari sys.excepthook
TIDAK yang bertahan di utas (seperti yang ditunjukkan di bawah). Ternyata ini perilaku yang diharapkan.
import sys, threading
def log_exception(*args):
print 'got exception %s' % (args,)
sys.excepthook = log_exception
def foo():
a = 1 / 0
threading.Thread(target=foo).start()
Pesan pada utas Python Issue ini benar-benar menghasilkan 2 peretasan yang disarankan. Entah subkelas Thread
dan bungkus metode jalankan dalam percobaan kami sendiri kecuali blok untuk menangkap dan mencatat pengecualian atau patch monyet threading.Thread.run
untuk berjalan dalam percobaan Anda sendiri kecuali memblokir dan mencatat pengecualian.
Metode pertama dari subclassing Thread
bagi saya tampaknya kurang elegan dalam kode Anda karena Anda harus mengimpor dan menggunakan Thread
kelas kustom di mana pun Anda ingin memiliki thread logging. Ini akhirnya menjadi masalah karena saya harus mencari seluruh basis kode kami dan mengganti semua normal Threads
dengan kebiasaan ini Thread
. Namun, jelas apa yang Thread
sedang dilakukan dan akan lebih mudah bagi seseorang untuk mendiagnosis dan men-debug jika ada yang salah dengan kode logging kustom. Thread custome logging mungkin terlihat seperti ini:
class TracebackLoggingThread(threading.Thread):
def run(self):
try:
super(TracebackLoggingThread, self).run()
except (KeyboardInterrupt, SystemExit):
raise
except Exception, e:
logger = logging.getLogger('')
logger.exception("Logging an uncaught exception")
Metode kedua dari patch monyet threading.Thread.run
bagus karena saya bisa menjalankannya sekali saja dan memasukkan __main__
kode logging saya di semua pengecualian. Menambal monyet bisa mengganggu untuk debug meskipun karena mengubah fungsionalitas yang diharapkan dari sesuatu. Tambalan yang disarankan dari pelacak Isu Python adalah:
def installThreadExcepthook():
"""
Workaround for sys.excepthook thread bug
From
http://spyced.blogspot.com/2007/06/workaround-for-sysexcepthook-bug.html
(https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1230540&group_id=5470).
Call once from __main__ before creating any threads.
If using psyco, call psyco.cannotcompile(threading.Thread.run)
since this replaces a new-style class method.
"""
init_old = threading.Thread.__init__
def init(self, *args, **kwargs):
init_old(self, *args, **kwargs)
run_old = self.run
def run_with_except_hook(*args, **kw):
try:
run_old(*args, **kw)
except (KeyboardInterrupt, SystemExit):
raise
except:
sys.excepthook(*sys.exc_info())
self.run = run_with_except_hook
threading.Thread.__init__ = init
Tidak sampai saya mulai menguji pengecualian logging saya, saya menyadari bahwa saya salah melakukan semuanya.
Untuk menguji saya telah menempatkan a
raise Exception("Test")
di suatu tempat dalam kode saya. Namun, membungkus metode yang disebut metode ini adalah percobaan kecuali blok yang mencetak traceback dan menelan pengecualian. Ini sangat menyebalkan karena saya melihat traceback membawa cetakan ke STDOUT tetapi tidak dicatat. Saya kemudian memutuskan bahwa metode yang jauh lebih mudah untuk mencatat tracebacks adalah dengan menambal metode yang semua kode python gunakan untuk mencetak tracebacks sendiri, traceback.print_exception. Saya berakhir dengan sesuatu yang mirip dengan yang berikut:
def add_custom_print_exception():
old_print_exception = traceback.print_exception
def custom_print_exception(etype, value, tb, limit=None, file=None):
tb_output = StringIO.StringIO()
traceback.print_tb(tb, limit, tb_output)
logger = logging.getLogger('customLogger')
logger.error(tb_output.getvalue())
tb_output.close()
old_print_exception(etype, value, tb, limit=None, file=None)
traceback.print_exception = custom_print_exception
Kode ini menulis traceback ke String Buffer dan mencatatnya untuk mencatat ERROR. Saya memiliki penangan logging kustom mengatur logger 'customLogger' yang mengambil log tingkat ERROR dan mengirim mereka pulang untuk analisis.
add_custom_print_exception
tampaknya tidak ada di situs yang Anda tautkan, dan alih-alih ada beberapa kode akhir yang sangat berbeda di sana. Mana yang akan Anda katakan lebih baik / lebih final dan mengapa? Terima kasih!
logger.error(traceback.format_tb())
(atau format_exc () jika Anda menginginkan info pengecualian juga).
Anda dapat mencatat semua pengecualian yang tidak tertangkap pada utas utama dengan menetapkan penangan sys.excepthook
, mungkin menggunakan exc_info
parameter fungsi logging Python :
import sys
import logging
logging.basicConfig(filename='/tmp/foobar.log')
def exception_hook(exc_type, exc_value, exc_traceback):
logging.error(
"Uncaught exception",
exc_info=(exc_type, exc_value, exc_traceback)
)
sys.excepthook = exception_hook
raise Exception('Boom')
Namun, jika program Anda menggunakan utas, maka perhatikan bahwa utas yang dibuat menggunakan tidakthreading.Thread
akan memicu ketika pengecualian tanpa tertangkap terjadi di dalamnya, seperti yang dicatat dalam Masalah 1230540 pada pelacak masalah Python. Beberapa peretasan telah disarankan di sana untuk mengatasi keterbatasan ini, seperti penambalan monyet untuk menimpa dengan metode alternatif yang membungkus sumber asli dalam sebuah blok dan panggilan dari dalam blok. Atau, Anda bisa hanya secara manual membungkus entry point untuk setiap benang Anda di / diri sendiri.sys.excepthook
Thread.__init__
self.run
run
try
sys.excepthook
except
try
except
Pesan pengecualian yang tidak tertangkap masuk ke STDERR, jadi alih-alih menerapkan logging dengan Python sendiri, Anda bisa mengirim STDERR ke file menggunakan shell apa pun yang Anda gunakan untuk menjalankan skrip Python. Dalam skrip Bash, Anda bisa melakukan ini dengan pengalihan output, seperti yang dijelaskan dalam panduan BASH .
Tambahkan kesalahan ke file, output lain ke terminal:
./test.py 2>> mylog.log
Timpa file dengan output STDOUT dan STDERR yang disisipkan:
./test.py &> mylog.log
Apa yang saya cari:
import sys
import traceback
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback_in_var = traceback.format_tb(exc_traceback)
Lihat:
Anda bisa mendapatkan traceback menggunakan logger, di tingkat mana pun (DEBUG, INFO, ...). Perhatikan bahwa menggunakan logging.exception
, levelnya ERROR.
# test_app.py
import sys
import logging
logging.basicConfig(level="DEBUG")
def do_something():
raise ValueError(":(")
try:
do_something()
except Exception:
logging.debug("Something went wrong", exc_info=sys.exc_info())
DEBUG:root:Something went wrong
Traceback (most recent call last):
File "test_app.py", line 10, in <module>
do_something()
File "test_app.py", line 7, in do_something
raise ValueError(":(")
ValueError: :(
EDIT:
Ini juga berfungsi (menggunakan python 3.6)
logging.debug("Something went wrong", exc_info=True)
Ini adalah versi yang menggunakan sys.excepthook
import traceback
import sys
logger = logging.getLogger()
def handle_excepthook(type, message, stack):
logger.error(f'An unhandled exception occured: {message}. Traceback: {traceback.format_tb(stack)}')
sys.excepthook = handle_excepthook
{traceback.format_exc()}
bukan {traceback.format_tb(stack)}
?
mungkin tidak bergaya, tetapi lebih mudah:
#!/bin/bash
log="/var/log/yourlog"
/path/to/your/script.py 2>&1 | (while read; do echo "$REPLY" >> $log; done)
Inilah contoh sederhana yang diambil dari dokumentasi python 2.6 :
import logging
LOG_FILENAME = '/tmp/logging_example.out'
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,)
logging.debug('This message should go to the log file')