From 65b08f09521109550284af6aa4f21d490c500af8 Mon Sep 17 00:00:00 2001 From: Vikas Shashidhar Date: Wed, 24 May 2017 19:02:49 +0530 Subject: [PATCH] Electron-17: Crash Reporter 1. Implemented crash reporter for both main and renderer processes 2. Fetch crash log details from Symphony.config 3. Send reports to a break pad server --- config/Symphony.config | 1 + demo/index.html | 13 +++++++++++++ js/crashReporter/index.js | 34 ++++++++++++++++++++++++++++++++++ js/main.js | 21 ++++++++++++++++++++- js/preload/preloadMain.js | 11 +++++++++++ js/windowMgr.js | 34 ++++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 1 deletion(-) create mode 100755 js/crashReporter/index.js diff --git a/config/Symphony.config b/config/Symphony.config index fd18abec..c6864d5e 100644 --- a/config/Symphony.config +++ b/config/Symphony.config @@ -1,5 +1,6 @@ { "url": "https://foundation-dev.symphony.com", + "sendCrashReports": true, "minimizeOnClose" : true, "launchOnStartup" : true } \ No newline at end of file diff --git a/demo/index.html b/demo/index.html index d4d67749..5d4d67fe 100644 --- a/demo/index.html +++ b/demo/index.html @@ -36,6 +36,13 @@



+

+ Crash Process: +

+ +

+
+

Badge Count:


@@ -165,6 +172,12 @@ console.log('bounds changed for=', arg) } + // crash the renderer process + const crash = document.getElementById('crash'); + crash.addEventListener('click', function () { + ssf.crashRendererProcess(); + }); + var getSources = document.getElementById('get-sources'); getSources.addEventListener('click', function() { ssf.getMediaSources({types: ['window', 'screen']}, function(error, sources) { diff --git a/js/crashReporter/index.js b/js/crashReporter/index.js new file mode 100755 index 00000000..50cef570 --- /dev/null +++ b/js/crashReporter/index.js @@ -0,0 +1,34 @@ +'use strict'; + +const {crashReporter} = require('electron'); + +/** + * Setup the crash reporter with appropriate information + * @param sendCrashReports: An object to get crash information + * from the global config file + * @param detailObj: An object to send extra parameters + * via the crash reporter + */ +function setupCrashReporter(detailObj, sendCrashReports) { + // Will eventually have to fetch all these from the config file. + let crashReportInfo = { + companyName: "Symphony Communication Services, LLC", + submitURL: "http://crash.symphony.com", + autoSubmit: true, + uploadToServer: sendCrashReports, + extra: detailObj + } + + // App store builds cannot use crash reporter, so, return if that's the case + if (process.platform === 'darwin' && process.mas) { + return + } + + if (process.type === 'renderer' && !(process.platform === 'darwin')) { + return; + } + + crashReporter.start(crashReportInfo); +} + +exports.setupCrashReporter = setupCrashReporter; \ No newline at end of file diff --git a/js/main.js b/js/main.js index f1b2d8fd..79c14d1f 100644 --- a/js/main.js +++ b/js/main.js @@ -7,9 +7,11 @@ const squirrelStartup = require('electron-squirrel-startup'); const AutoLaunch = require('auto-launch'); const urlParser = require('url'); const { getConfigField } = require('./config.js'); -const { isDevEnv} = require('./utils/misc.js'); +const { isDevEnv } = require('./utils/misc.js'); const protocolHandler = require('./protocolHandler'); +const crashReporter = require('./crashReporter'); + // used to check if a url was opened when the app was already open let isAppAlreadyOpen = false; @@ -161,6 +163,20 @@ function createWin(urlFromConfig) { windowMgr.createMainWindow(url); } +/** + * Get crash info from global config and setup crash reporter for Main Process. + */ +function initializeCrashReporter () { + getConfigField('sendCrashReports').then( + function (data) { + crashReporter.setupCrashReporter({'window': 'main'}, data); + } + ).catch(function (err) { + let title = 'Error loading configuration'; + electron.dialog.showErrorBox(title, title + ': ' + err); + }) +} + /** * processes protocol action for windows clients * @param argv {Array} an array of command line arguments @@ -207,3 +223,6 @@ function handleProtocolAction(uri) { protocolHandler.processProtocolAction(uri); } } + +// Initialize the crash reporter +initializeCrashReporter(); \ No newline at end of file diff --git a/js/preload/preloadMain.js b/js/preload/preloadMain.js index 0f78d090..4994805a 100644 --- a/js/preload/preloadMain.js +++ b/js/preload/preloadMain.js @@ -18,6 +18,7 @@ const apiEnums = require('../enums/api.js'); const apiCmds = apiEnums.cmds; const apiName = apiEnums.apiName; const getMediaSources = require('../desktopCapturer/getSources'); +const crashReporter = require('../crashReporter'); // hold ref so doesn't get GC'ed const local = { @@ -32,6 +33,9 @@ const throttledSetBadgeCount = throttle(1000, function(count) { }); }); +// Setup the crash reporter +crashReporter.setupCrashReporter({'window': 'preloadMain'}); + createAPI(); // creates API exposed from electron. @@ -88,6 +92,13 @@ function createAPI() { */ ScreenSnippet: remote.require('./screenSnippet/ScreenSnippet.js'), + /** + * Provides API to crash the renderer process that calls this function + */ + crashRendererProcess: function () { + process.crash(); + }, + /** * Brings window forward and gives focus. * @param {String} windowName Name of window. Note: main window name is 'main' diff --git a/js/windowMgr.js b/js/windowMgr.js index 8406d421..f8584c73 100644 --- a/js/windowMgr.js +++ b/js/windowMgr.js @@ -6,6 +6,8 @@ const BrowserWindow = electron.BrowserWindow; const path = require('path'); const nodeURL = require('url'); const querystring = require('querystring'); +const {dialog} = require('electron'); +const {shell} = require('electron'); const { getTemplate, getMinimizeOnClose } = require('./menus/menuTemplate.js'); const loadErrors = require('./dialogs/showLoadError.js'); @@ -20,6 +22,8 @@ const activityDetection = require('./activityDetection/activityDetection.js'); const throttle = require('./utils/throttle.js'); const { getConfigField, updateConfigField } = require('./config.js'); +const crashReporter = require('./crashReporter'); + //context menu const contextMenu = require('./menus/contextMenu.js'); @@ -68,6 +72,18 @@ function doCreateMainWindow(initialUrl, initialBounds) { let url = initialUrl; let key = getGuid(); + /** + * Get crash info from global config and setup crash reporter. + */ + getConfigField('sendCrashReports').then( + function (data) { + crashReporter.setupCrashReporter({'window': 'main'}, data); + } + ).catch(function (err) { + let title = 'Error loading configuration'; + electron.dialog.showErrorBox(title, title + ': ' + err); + }); + let newWinOpts = { title: 'Symphony', show: true, @@ -146,6 +162,24 @@ function doCreateMainWindow(initialUrl, initialBounds) { loadErrors.showLoadFailure(mainWindow, validatedURL, errorDesc, errorCode, retry); }); + // In case a renderer process crashes, provide an + // option for the user to either reload or close the window + mainWindow.webContents.on('crashed', function () { + const options = { + type: 'error', + title: 'Renderer Process Crashed', + message: 'Uh oh! Looks like we have had a crash. Please reload or close this window.', + buttons: ['Reload', 'Close'] + }; + + dialog.showMessageBox(options, function (index) { + if (index === 0) { + mainWindow.reload(); + } + else mainWindow.close(); + }); + }); + addWindowKey(key, mainWindow); mainWindow.loadURL(url);