From f488ef7597157012d058d3cbf9221e510f3995d9 Mon Sep 17 00:00:00 2001 From: DC Date: Thu, 25 Aug 2016 05:56:46 -0700 Subject: [PATCH] Telemetry: fix error logging bugs, [object Object] and [object HTMLMediaElement] --- src/main/index.js | 4 +-- src/renderer/lib/telemetry.js | 48 +++++++++++++++++++++++++++-------- src/renderer/main.js | 3 ++- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/main/index.js b/src/main/index.js index 7cbbeb15..3ed6d344 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -78,8 +78,8 @@ function init () { // Report uncaught exceptions process.on('uncaughtException', (err) => { console.error(err) - var errJSON = {message: err.message, stack: err.stack} - windows.main.dispatch('uncaughtError', 'main', errJSON) + var error = {message: err.message, stack: err.stack} + windows.main.dispatch('uncaughtError', 'main', error) }) }) diff --git a/src/renderer/lib/telemetry.js b/src/renderer/lib/telemetry.js index 4394df54..482942f2 100644 --- a/src/renderer/lib/telemetry.js +++ b/src/renderer/lib/telemetry.js @@ -119,23 +119,42 @@ function getApproxNumTorrents (state) { } // An uncaught error happened in the main process or in one of the windows -function logUncaughtError (procName, err) { +function logUncaughtError (procName, e) { // Not initialized yet? Ignore. // Hopefully uncaught errors immediately on startup are fixed in dev if (!telemetry) return - var message, stack - if (err instanceof Error) { - message = err.message - // Remove the first part of each file path in the stack trace. - // - Privacy: remove personal info like C:\Users\ - // - Aggregation: this lets us find which stacktraces occur often - stack = err.stack.replace(/\(.*app.asar/g, '(...') + var message + var stack = '' + if (e.message) { + // err is either an Error or a plain object {message, stack} + message = e.message + stack = e.stack + } else if (e.error) { + // Uncaught Javascript errors (window.onerror), err is an ErrorEvent + if (!e.error.message) { + message = 'Unexpected ErrorEvent.error: ' + Object.keys(e.error).join(' ') + } else { + message = e.error.message + stack = e.error.stack + } } else { - message = String(err) - stack = '' + // Resource errors (captured element.onerror), err is an Event + if (!e.target) { + message = 'Unexpected unknown error' + } else if (!e.target.error) { + message = 'Unexpected resource loading error: ' + getElemString(e.target) + } else { + message = 'Resource error ' + getElemString(e.target) + ': ' + e.target.error.code + } } + // Remove the first part of each file path in the stack trace. + // - Privacy: remove personal info like C:\Users\ + // - Aggregation: this lets us find which stacktraces occur often + if (stack && typeof stack === 'string') stack = stack.replace(/\(.*app.asar/g, '(...') + else if (stack) stack = 'Unexpected stack: ' + stack + // We need to POST the telemetry object, make sure it stays < 100kb if (telemetry.uncaughtErrors.length > 20) return if (message.length > 1000) message = message.substring(0, 1000) @@ -147,6 +166,15 @@ function logUncaughtError (procName, err) { telemetry.uncaughtErrors.push({process: procName, message, stack, version}) } +// Turns a DOM element into a string, eg "DIV.my-class.visible" +function getElemString (elem) { + var ret = elem.tagName + try { + ret += '.' + Array.from(elem.classList).join('.') + } catch (e) {} + return ret +} + // The user pressed play. It either worked, timed out, or showed the // 'Play in VLC' codec error function logPlayAttempt (result) { diff --git a/src/renderer/main.js b/src/renderer/main.js index a5ddfedd..e9ed6cee 100644 --- a/src/renderer/main.js +++ b/src/renderer/main.js @@ -116,7 +116,8 @@ function onState (err, _state) { // Log uncaught JS errors window.addEventListener('error', - (e) => telemetry.logUncaughtError('window', e.error || e.target), true) + (e) => telemetry.logUncaughtError('window', e), + true /* capture */) // Done! Ideally we want to get here < 500ms after the user clicks the app sound.play('STARTUP')