Câu trả lời:
Sử dụng logging.exception
từ bên trong except:
trình xử lý / khối để ghi lại ngoại lệ hiện tại cùng với thông tin theo dõi, được gửi kèm theo một thông báo.
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
Bây giờ nhìn vào tệp nhật ký , /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')
bạn phải viết logger.exception('...')
để hoạt động này ...
exc_info
Tùy chọn sử dụng có thể tốt hơn, vẫn là cảnh báo hoặc tiêu đề lỗi:
try:
# coode in here
except Exception as e:
logging.error(e, exc_info=True)
exc_info=
kwarg được gọi là; cảm ơn!
logging.exception
Công việc của tôi gần đây đã giao nhiệm vụ cho tôi đăng nhập tất cả các dấu vết / ngoại lệ từ ứng dụng của chúng tôi. Tôi đã thử rất nhiều kỹ thuật mà những người khác đã đăng lên mạng như cách trên nhưng đã giải quyết theo một cách tiếp cận khác. Ghi đè traceback.print_exception
.
Tôi có một bài viết tại http://www.bbarrows.com/ Điều đó sẽ dễ đọc hơn nhiều nhưng Ill cũng dán nó vào đây.
Khi được giao nhiệm vụ ghi nhật ký tất cả các ngoại lệ mà phần mềm của chúng tôi có thể gặp phải trong tự nhiên, tôi đã thử một số kỹ thuật khác nhau để ghi nhật ký truy xuất ngoại lệ python của chúng tôi. Lúc đầu, tôi nghĩ rằng hook ngoại lệ của hệ thống python, sys.ex805thook sẽ là nơi hoàn hảo để chèn mã đăng nhập. Tôi đã thử một cái gì đó tương tự như:
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
Điều này làm việc cho chủ đề chính nhưng tôi sớm nhận thấy rằng sys.ex805thook của tôi sẽ không tồn tại trên bất kỳ chủ đề mới nào mà quá trình của tôi bắt đầu. Đây là một vấn đề lớn bởi vì hầu hết mọi thứ xảy ra trong các chủ đề trong dự án này.
Sau khi googling và đọc nhiều tài liệu, thông tin hữu ích nhất tôi tìm thấy là từ trình theo dõi vấn đề Python.
Bài đăng đầu tiên trên chuỗi cho thấy một ví dụ hoạt động của sys.excepthook
KHÔNG tồn tại trên các luồng (như được hiển thị bên dưới). Rõ ràng đây là hành vi dự kiến.
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()
Các thông báo trên luồng Vấn đề Python này thực sự dẫn đến 2 vụ hack được đề xuất. Hoặc là lớp con Thread
và bọc phương thức chạy trong thử riêng của chúng tôi ngoại trừ khối để bắt và ghi nhật ký ngoại lệ hoặc bản vá khỉ threading.Thread.run
để chạy trong thử của riêng bạn ngoại trừ chặn và ghi nhật ký ngoại lệ.
Phương pháp phân lớp đầu tiên Thread
đối với tôi có vẻ kém thanh lịch trong mã của bạn vì bạn sẽ phải nhập và sử dụng Thread
lớp tùy chỉnh của mình MỌI NƠI bạn muốn có một luồng đăng nhập. Điều này cuối cùng là một rắc rối vì tôi phải tìm kiếm toàn bộ cơ sở mã của chúng tôi và thay thế tất cả bình thường Threads
với tùy chỉnh này Thread
. Tuy nhiên, rõ ràng điều này Thread
đang làm và sẽ dễ dàng hơn cho ai đó chẩn đoán và gỡ lỗi nếu có lỗi xảy ra với mã đăng nhập tùy chỉnh. Một chủ đề đăng nhập theo yêu cầu có thể trông như thế này:
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")
Phương pháp vá khỉ thứ hai threading.Thread.run
rất hay vì tôi chỉ có thể chạy nó một lần ngay sau đó __main__
và sử dụng mã đăng nhập của mình trong tất cả các trường hợp ngoại lệ. Khỉ vá có thể gây khó chịu khi gỡ lỗi mặc dù nó thay đổi chức năng dự kiến của một cái gì đó. Bản vá được đề xuất từ trình theo dõi Vấn đề Python là:
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
Mãi đến khi tôi bắt đầu thử nghiệm ghi nhật ký ngoại lệ của mình, tôi mới nhận ra rằng mình đã sai.
Để kiểm tra tôi đã đặt một
raise Exception("Test")
ở đâu đó trong mã của tôi. Tuy nhiên, gói phương thức aa được gọi là phương pháp này là một thử ngoại trừ khối đã in ra dấu vết và nuốt ngoại lệ. Điều này đã rất bực bội vì tôi đã thấy bản in mang đến STDOUT nhưng không được ghi lại. Sau đó, tôi đã quyết định rằng một phương pháp ghi nhật ký các tracebacks dễ dàng hơn nhiều chỉ là để con khỉ vá phương thức mà tất cả mã trăn sử dụng để tự in tracebacks, tracBack.print_exception. Tôi đã kết thúc với một cái gì đó tương tự như sau:
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
Mã này ghi truy nguyên vào Bộ đệm chuỗi và ghi nhật ký để ghi nhật ký LRI. Tôi có một trình xử lý ghi nhật ký tùy chỉnh thiết lập trình ghi nhật ký 'customLogger', lấy nhật ký mức ERROR và gửi chúng về nhà để phân tích.
add_custom_print_exception
dường như không có trên trang web mà bạn liên kết đến, và thay vào đó có một số mã cuối cùng khá khác nhau ở đó. Cái nào bạn muốn nói là tốt hơn / cuối cùng và tại sao? Cảm ơn!
logger.error(traceback.format_tb())
(hoặc format_exc () nếu bạn cũng muốn thông tin ngoại lệ).
Bạn có thể ghi nhật ký tất cả các trường hợp ngoại lệ chưa xử lý vào luồng chính bằng cách gán một trình xử lý sys.excepthook
, có thể sử dụng exc_info
tham số của các hàm ghi nhật ký của 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')
Tuy nhiên, nếu chương trình của bạn sử dụng các luồng, thì lưu ý rằng các luồng được tạo bằng cách sử dụng threading.Thread
sẽ không kích hoạt sys.excepthook
khi xảy ra ngoại lệ chưa được xử lý bên trong chúng, như đã lưu ý trong Vấn đề 1230540 về trình theo dõi vấn đề của Python. Một số hack đã được đề xuất ở đó để khắc phục giới hạn này, như vá khỉ Thread.__init__
để ghi đè lên self.run
bằng một run
phương pháp thay thế bao bọc bản gốc trong một try
khối và gọi sys.excepthook
từ bên trong except
khối. Ngoài ra, bạn chỉ có thể tự bọc điểm nhập cảnh cho từng chuỗi của mình trong try
/ except
chính mình.
Các thông báo ngoại lệ chưa được chuyển đến STDERR, vì vậy thay vì thực hiện đăng nhập bằng chính Python, bạn có thể gửi STDERR đến một tệp bằng bất kỳ shell nào bạn đang sử dụng để chạy tập lệnh Python của mình. Trong tập lệnh Bash, bạn có thể thực hiện việc này với chuyển hướng đầu ra, như được mô tả trong hướng dẫn BASH .
Nối các lỗi vào tập tin, đầu ra khác vào thiết bị đầu cuối:
./test.py 2>> mylog.log
Ghi đè tập tin với đầu ra STDOUT và STDERR xen kẽ:
./test.py &> mylog.log
Những gì tôi đang tìm kiếm:
import sys
import traceback
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback_in_var = traceback.format_tb(exc_traceback)
Xem:
Bạn có thể nhận được truy nguyên bằng bộ ghi, ở mọi cấp độ (DEBUG, INFO, ...). Lưu ý rằng sử dụng logging.exception
, cấp độ là LRI.
# 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: :(
BIÊN TẬP:
Điều này cũng hoạt động (sử dụng python 3.6)
logging.debug("Something went wrong", exc_info=True)
Đây là một phiên bản sử dụng sys.ex805thook
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()}
thay vì {traceback.format_tb(stack)}
?
có thể không phong cách, nhưng dễ dàng hơn:
#!/bin/bash
log="/var/log/yourlog"
/path/to/your/script.py 2>&1 | (while read; do echo "$REPLY" >> $log; done)
Đây là một ví dụ đơn giản được lấy từ tài liệu 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')