15

Để thực hiện gỡ lỗi dễ dàng hơn, tôi đang chụp tất cả nhật ký bảng điều khiển trong Chrome để người dùng gửi mục phản hồi cũng sẽ gửi tất cả nhật ký đến máy chủ của chúng tôi. Khi ai đó gặp phải vấn đề trong sản xuất, trước hết tôi có thể đưa họ trở lại làm việc để tôi có thể ngồi xuống và xem kỹ tất cả nhật ký để xác định nguyên nhân gốc rễ của bất kỳ vấn đề nào người dùng gặp phải trong sản xuất.Tôi làm cách nào để ghi đè/mở rộng tham chiếu trong JavaScript của Chrome?

Kỹ thuật tôi sử dụng để ghi nhật ký liên quan đến việc ghi đè console.log sao cho tất cả văn bản được nhập trong đối số đầu tiên được lưu trữ trong một mảng trong khi đồng thời gọi hàm cũ để tôi vẫn có thể xem nhật ký trong bảng điều khiển.

Vấn đề là khi có ngoại lệ không thường xuyên bị bắt buộc. Chúng không được bao gồm trong nhật ký được tải lên, do đó, không phải lúc nào cũng rõ ràng nguyên nhân gây ra sự cố. Vì vậy, tôi đã cố gắng ghi đè tham chiếu bằng cách viết hàm JavaScript lấy hàm làm đối số, sau đó trả về hàm mới thực hiện công cụ, như lưu trữ dữ liệu trong biến và sau đó gọi hàm cũ là bước cuối cùng:

function overrideException(legacyFn) { 

    /** arguments for original fn **/ 
    return function() { 

     var args = []; 

     args[0] = arguments[0]; 

     // pass in as arguments to original function and store result to 
      // prove we overrode the ReferenceError 
     output = ">> " + legacyFn.apply(this, args).stack; 

     return legacyFn.apply(this, arguments); 
    }   

} 

Để kiểm tra chức năng overrideException, tôi chạy đoạn mã sau vào giao diện điều khiển:

ReferenceError = overrideException(ReferenceError); 

sau đó, tôi đã thử nghiệm chức năng trả lời, ReferenceError mới, bằng cách thủ công ném một ReferenceError:

throw new ReferenceError("YES!! IT WORKS! HAHAHA!"); 

Kết quả là sản lượng trên giao diện điều khiển là:

ReferenceError: YES!! IT WORKS! HAHAHA!

Và kiểm tra các biến toàn cầu output từ chức năng overrideException cho thấy rằng nó đã thực sự chạy:

output 
    ">> ReferenceError: YES!! IT WORKS! HAHAHA! 
    at ReferenceError (<anonymous>) 
    at new <anonymous> (<anonymous>:18:35) 
    at <anonymous>:2:7 
    at Object.InjectedScript._evaluateOn (<anonymous>:562:39) 
    at Object.InjectedScript._evaluateAndWrap (<anonymous>:521:52) 
    at Object.InjectedScript.evaluate (<anonymous>:440:21)" 

Bây giờ, đây là nơi mọi thứ bắt đầu rơi ngoài. Trong mã của chúng tôi, chúng tôi sẽ không biết khi nào uncaught một ngoại lệ xảy ra, vì vậy tôi đã thử nghiệm nó bằng cách cố gắng để chạy một chức năng mà không tồn tại:

ttt(); 

mà kết quả trong:

ReferenceError: ttt is not defined

Tuy nhiên, không giống như trường hợp chúng tôi ném một lỗi rõ ràng, trong trường hợp này, hàm không kích hoạt và chúng tôi chỉ còn lại chức năng cũ. Nội dung của biến số output giống như trong bài kiểm tra đầu tiên. Vì vậy, câu hỏi có vẻ như thế này: Làm thế nào để chúng ta ghi đè lên chức năng ReferenceError mà công cụ JavaScript sử dụng để ném lỗi sao cho nó giống với một lỗi mà chúng ta sử dụng khi chúng ta ném một tham chiếu tới lỗi?

Hãy nhớ rằng sự cố của tôi chỉ giới hạn ở Chrome vào thời điểm này; Tôi đang xây dựng một ứng dụng Chrome Packaged.

+0

Đoán bạn không muốn quấn mã của mình trong 'try/catch' và xử lý đối tượng lỗi sau đó ném lại ở đó? –

+0

@CrazyTrain - Tôi có thể làm điều đó, và có lẽ tôi sẽ làm vậy. Tuy nhiên, nó tẻ nhạt và cũng có thể bỏ lỡ một cái gì đó. Tôi thích các giải pháp chống giả và bao gồm tất cả vì chúng thường "Tôi quá bận rộn" :) Kế hoạch của tôi tất nhiên là sử dụng nhiều thử/nắm bắt hơn, nhưng điều này có vẻ như một giải pháp tuyệt vời như vậy Tôi bắt đầu đào sâu vào nó. – jmort253

+0

Tôi có nghĩa là một "thử/catch" nguyên khối kết thúc tốt đẹp tất cả các mã của bạn. Vì dường như mục tiêu không phải là quá nhiều để giải quyết các lỗi tại chỗ, mà là định dạng lại chúng bằng cách nào đó, sau đó gói tất cả mã trong một 'try/catch' duy nhất có vẻ hơi khác so với phương pháp thay thế constructor hiện tại của bạn. Bạn sẽ chỉ cần chắc chắn rằng bạn ném lại bất kỳ lỗi nào bạn nhận được. –

Trả lời

12

Tôi đã thực hiện khá nhiều nghiên cứu vì lý do tương tự: Tôi muốn ghi lại các lỗi và báo cáo chúng.

"Ghi đè" loại gốc (cho dù ReferenceError, String hoặc Array) là không thể.

Chrome liên kết các mã này trước khi bất kỳ Javascript nào được chạy, do đó việc xác định lại window.ReferenceError sẽ không có hiệu lực.

Bạn có thể mở rộng ReferenceError bằng thứ gì đó như ReferenceError.prototype.extension = function() { return 0; } hoặc thậm chí ghi đè toString (để nhất quán, hãy thử trên trang chứ không phải Công cụ tìm kiếm).

Điều đó không giúp bạn nhiều.

Nhưng không phải lo lắng ....

(1) Sử dụng window.onerror để có được tên tập tin, số dòng 1-lập chỉ mục, và vị trí 0-lập chỉ mục các lỗi còn tự do, cũng như các lỗi chính nó.

var errorData = []; 
onerror = function(message, file, line, position, error) { 
    errorData.push({message:message, file:file, line:line, position:position, error:error}); 
}; 

Xem ví dụ fiddle để biết ví dụ. Vì OP dành riêng cho Chrome nên tính năng này chỉ được thử nghiệm để hoạt động trong Chrome.

(2) Do cải tiến (1), điều này không còn cần thiết, nhưng tôi để kỹ thuật thứ hai này ở đây để hoàn thành và kể từ onerrornot guaranteed to work for all errors on all browsers. Bạn cũng có đôi khi sẽ thấy như sau:

var errors = []; 
function protectedFunction(f) { 
    return function() { 
     try { 
      f.apply(this, arguments); 
     } catch(e) { 
      errors.push(e); 
      throw e; 
     } 
    }; 
} 
setTimeout = protectedFunction(setTimeout); 
setInterval = protectedFunction(setInterval); 
etc... 

FYI, tất cả điều này rất giống với những gì đã được thực hiện trong thư viện Google Closure Compiler, trong goog.debug, tạo ra quá trình phát triển với mục đích làm chính xác này Gmail. Sở thích cụ thể là goog.debug.ErrorHandlergoog.debug.ErrorReporter.

+1

Bạn thưa bạn, là một thiên tài! Tôi đã thử nó và thực sự đã có một ngoại lệ không thực sự trong mã của tôi tôi không biết về, và nó đã đăng nhập vào khung đăng nhập của tôi! Tôi sẽ cần phải chơi xung quanh với điều này nhiều hơn một chút, như tôi nhận thấy nó đã không làm việc bên trong một số callbacks. Tôi hy vọng phương pháp setTimeout/setInterval của bạn sẽ làm việc cho những trường hợp đó. +1 – jmort253

+0

Cảm ơn. (1) nên làm việc cho tất cả các trường hợp ngoại lệ không bắt buộc (cho dù từ đánh giá kịch bản, người nghe sự kiện, vv). Hãy để nó được biết nếu bạn tìm thấy trường hợp nó không hoạt động. –

+0

Tôi sẽ phải chơi xung quanh với nó nhiều hơn vào ngày mai, và tôi có thể vừa mắc lỗi, nhưng tôi nhớ lại một số trình xử lý sự kiện khác ném các lỗi được tạo ra bên trong chrome.app.window.create, thay vì window.onerror xử lý chúng. Tôi đang thử điều này bên trong một chức năng gọi lại phương thức 'create' của ứng dụng được đóng gói Chrome. – jmort253

Các vấn đề liên quan