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 truy 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ư phương pháp ở 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 //www.bbarrows.com/ sẽ dễ đọc hơn nhiều nhưng cũng sẽ 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 lại các dấu vết ngoại lệ Python của chúng tôi. Lúc đầu, tôi nghĩ rằng móc ngoại lệ hệ thống Python, Sys.ExceptHook sẽ là nơi hoàn hảo để chèn mã ghi nhật ký. 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 đã hoạt động cho chủ đề chính nhưng tôi sớm thấy rằng hệ thống của tôi.ExceptHook 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 luồng 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 mong đợi.
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 tin nhắn trên chủ đề vấn đề Python này thực sự dẫn đến 2 bản hack được đề xuất. Một lớp con Thread
và bọc phương thức chạy trong thử của chúng tôi ngoại trừ khối để bắt và ghi nhật ký các 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ừ khối và ghi lại các ngoại lệ.
Phương pháp đầu tiên để phân lớp Thread
dường như ít thanh lịch hơn trong mã của bạn vì bạn sẽ phải nhập và sử dụng lớp Thread
tùy chỉnh của bạn ở mọi nơi bạn muốn có một luồng đăng nhập. Điều này cuối cùng đã trở thành 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ả
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[]
2 bình thường bằng cách tùy chỉnh này. Tuy nhiên, rõ ràng Thread
này đang làm gì và sẽ dễ dàng hơn cho ai đó chẩn đoán và gỡ lỗi nếu có sự cố với mã ghi nhật ký tùy chỉnh. Một chủ đề ghi nhật ký 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 thứ hai của việc vá khỉ threading.Thread.run
là tốt vì tôi chỉ có thể chạy nó một lần ngay sau
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[]
6 và thiết bị mã ghi nhật ký của tôi trong tất cả các ngoại lệ. Việc vá khỉ 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
//spyced.blogspot.com/2007/06/workaround-for-sysexcepthook-bug.html
[//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 cho đến khi tôi bắt đầu kiểm tra đăng nhập ngoại lệ của mình, tôi mới nhận ra rằng tôi sẽ sai về nó.
Để kiểm tra tôi đã đặt một
raise Exception["Test"]
ở đâu đó trong mã của tôi. Tuy nhiên, gói một phương pháp 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 Traceback mang in cho Stdout nhưng không được ghi lại. Sau đó, tôi đã quyết định rằng một phương pháp dễ tính hơn nhiều để ghi lại các dấu vết chỉ là để vá phương pháp mà tất cả các mã Python sử dụng để in các dấu vết, traceback.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 TraceBack vào bộ đệm chuỗi và ghi nhật ký vào lỗi ghi nhật ký. Tôi có một trình xử lý đăng nhập tùy chỉnh đã thiết lập bộ ghi 'CustomLogger' lấy nhật ký mức lỗi và gửi cho họ về nhà để phân tích.