Merge pull request #836 from feross/dc/fixes

Telemetry: log version in errors
This commit is contained in:
Feross Aboukhadijeh
2016-08-25 15:34:21 +02:00
committed by GitHub
3 changed files with 48 additions and 15 deletions

View File

@@ -78,8 +78,8 @@ function init () {
// Report uncaught exceptions // Report uncaught exceptions
process.on('uncaughtException', (err) => { process.on('uncaughtException', (err) => {
console.error(err) console.error(err)
var errJSON = {message: err.message, stack: err.stack} var error = {message: err.message, stack: err.stack}
windows.main.dispatch('uncaughtError', 'main', errJSON) windows.main.dispatch('uncaughtError', 'main', error)
}) })
}) })

View File

@@ -33,7 +33,7 @@ function init (state) {
if (config.IS_PRODUCTION) { if (config.IS_PRODUCTION) {
postToServer() postToServer()
// If the user keeps WebTorrent running for a long time, post every 24h // If the user keeps WebTorrent running for a long time, post every 12h
setInterval(postToServer, 12 * 3600 * 1000) setInterval(postToServer, 12 * 3600 * 1000)
} else { } else {
// Development: telemetry used only for local debugging // Development: telemetry used only for local debugging
@@ -45,6 +45,7 @@ function init (state) {
function reset () { function reset () {
telemetry.uncaughtErrors = [] telemetry.uncaughtErrors = []
telemetry.playAttempts = { telemetry.playAttempts = {
minVersion: config.APP_VERSION,
total: 0, total: 0,
success: 0, success: 0,
timeout: 0, timeout: 0,
@@ -118,29 +119,60 @@ function getApproxNumTorrents (state) {
} }
// An uncaught error happened in the main process or in one of the windows // 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. // Not initialized yet? Ignore.
// Hopefully uncaught errors immediately on startup are fixed in dev // Hopefully uncaught errors immediately on startup are fixed in dev
if (!telemetry) return if (!telemetry) return
var message, stack var message
if (err instanceof Error) { var stack = ''
message = err.message if (e.message) {
// Remove the first part of each file path in the stack trace. // err is either an Error or a plain object {message, stack}
// - Privacy: remove personal info like C:\Users\<full name> message = e.message
// - Aggregation: this lets us find which stacktraces occur often stack = e.stack
stack = err.stack.replace(/\(.*app.asar/g, '(...') } 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 { } else {
message = String(err) // Resource errors (captured element.onerror), err is an Event
stack = '' 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\<full name>
// - 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 // We need to POST the telemetry object, make sure it stays < 100kb
if (telemetry.uncaughtErrors.length > 20) return if (telemetry.uncaughtErrors.length > 20) return
if (message.length > 1000) message = message.substring(0, 1000) if (message.length > 1000) message = message.substring(0, 1000)
if (stack.length > 1000) stack = stack.substring(0, 1000) if (stack.length > 1000) stack = stack.substring(0, 1000)
telemetry.uncaughtErrors.push({process: procName, message, stack}) // Log the app version *at the time of the error*
var version = config.APP_VERSION
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 // The user pressed play. It either worked, timed out, or showed the

View File

@@ -116,7 +116,8 @@ function onState (err, _state) {
// Log uncaught JS errors // Log uncaught JS errors
window.addEventListener('error', 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 // Done! Ideally we want to get here < 500ms after the user clicks the app
sound.play('STARTUP') sound.play('STARTUP')