mirror of
https://github.com/finos/SymphonyElectron.git
synced 2024-12-29 02:11:28 -06:00
Merge branch 'master' of github.com:symphonyoss/SymphonyElectron
This commit is contained in:
commit
8ab674443c
@ -153,6 +153,7 @@ export const Menu = {
|
||||
|
||||
export const crashReporter = {
|
||||
start: jest.fn(),
|
||||
getLastCrashReport: jest.fn(),
|
||||
};
|
||||
|
||||
const getCurrentWindow = jest.fn(() => {
|
||||
|
@ -1,9 +1,16 @@
|
||||
export interface IAnalyticsData {
|
||||
element: AnalyticsElements;
|
||||
action_type: MenuActionTypes | ScreenSnippetActionTypes;
|
||||
action_type?: MenuActionTypes | ScreenSnippetActionTypes;
|
||||
action_result?: AnalyticsActions;
|
||||
}
|
||||
|
||||
export interface ICrashData extends IAnalyticsData {
|
||||
process: SDACrashProcess;
|
||||
crashCause: string;
|
||||
windowName: string;
|
||||
miniDump?: string;
|
||||
}
|
||||
|
||||
export enum MenuActionTypes {
|
||||
AUTO_LAUNCH_ON_START_UP = 'auto_launch_on_start_up',
|
||||
ALWAYS_ON_TOP = 'always_on_top',
|
||||
@ -30,6 +37,13 @@ export enum AnalyticsActions {
|
||||
export enum AnalyticsElements {
|
||||
MENU = 'Menu',
|
||||
SCREEN_CAPTURE_ANNOTATE = 'screen_capture_annotate',
|
||||
SDA_CRASH = 'sda_crash',
|
||||
}
|
||||
|
||||
export enum SDACrashProcess {
|
||||
MAIN = 'main',
|
||||
RENDERER = 'renderer',
|
||||
GPU = 'gpu',
|
||||
}
|
||||
|
||||
const MAX_EVENT_QUEUE_LENGTH = 50;
|
||||
@ -51,9 +65,12 @@ class Analytics {
|
||||
return;
|
||||
}
|
||||
if (this.analyticsEventQueue && this.analyticsEventQueue.length > 0) {
|
||||
this.analyticsEventQueue.forEach((events) => {
|
||||
this.analyticsEventQueue.forEach((eventData) => {
|
||||
if (this.preloadWindow && !this.preloadWindow.isDestroyed()) {
|
||||
this.preloadWindow.send(analyticsCallback, events);
|
||||
if (eventData.element === AnalyticsElements.SDA_CRASH) {
|
||||
eventData = eventData as ICrashData;
|
||||
}
|
||||
this.preloadWindow.send(analyticsCallback, eventData);
|
||||
}
|
||||
});
|
||||
this.resetAnalytics();
|
||||
@ -66,12 +83,15 @@ class Analytics {
|
||||
* @param eventData {IAnalyticsData}
|
||||
*/
|
||||
public track(eventData: IAnalyticsData): void {
|
||||
if (eventData.element === AnalyticsElements.SDA_CRASH) {
|
||||
eventData = eventData as ICrashData;
|
||||
}
|
||||
if (this.preloadWindow && !this.preloadWindow.isDestroyed()) {
|
||||
this.preloadWindow.send(analyticsCallback, eventData);
|
||||
return;
|
||||
}
|
||||
this.analyticsEventQueue.push(eventData);
|
||||
// don't store more than 50 msgs. keep most recent log msgs.
|
||||
// don't store more than specified limit. keep most recent events.
|
||||
if (this.analyticsEventQueue.length > MAX_EVENT_QUEUE_LENGTH) {
|
||||
this.analyticsEventQueue.shift();
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { BrowserWindow, WebContents } from 'electron';
|
||||
import { BrowserWindow, crashReporter, WebContents } from 'electron';
|
||||
|
||||
import { parse as parseQuerystring } from 'querystring';
|
||||
import { format, parse, Url } from 'url';
|
||||
@ -8,6 +8,7 @@ import { logger } from '../common/logger';
|
||||
import { getGuid } from '../common/utils';
|
||||
import { whitelistHandler } from '../common/whitelist-handler';
|
||||
import { config } from './config-handler';
|
||||
import crashHandler from './crash-handler';
|
||||
import {
|
||||
handlePermissionRequests,
|
||||
monitorWindowActions,
|
||||
@ -262,6 +263,14 @@ export const handleChildWindow = (webContents: WebContents): void => {
|
||||
removeWindowEventListener(browserWin);
|
||||
});
|
||||
|
||||
crashReporter.start({
|
||||
submitURL: '',
|
||||
uploadToServer: false,
|
||||
ignoreSystemCrashHandler: false,
|
||||
});
|
||||
|
||||
crashHandler.handleRendererCrash(browserWin);
|
||||
|
||||
if (browserWin.webContents) {
|
||||
// validate link and create a child window or open in browser
|
||||
handleChildWindow(browserWin.webContents);
|
||||
|
110
src/app/crash-handler.ts
Normal file
110
src/app/crash-handler.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import { app, crashReporter, Details, dialog } from 'electron';
|
||||
import { i18n } from '../common/i18n';
|
||||
import { logger } from '../common/logger';
|
||||
import {
|
||||
analytics,
|
||||
AnalyticsElements,
|
||||
ICrashData,
|
||||
SDACrashProcess,
|
||||
} from './analytics-handler';
|
||||
import { ICustomBrowserWindow } from './window-handler';
|
||||
import { windowExists } from './window-utils';
|
||||
|
||||
class CrashHandler {
|
||||
/**
|
||||
* Shows a message to the user to take further action
|
||||
* @param browserWindow Browser Window to show the dialog on
|
||||
* @private
|
||||
*/
|
||||
private static async showMessageToUser(browserWindow: ICustomBrowserWindow) {
|
||||
if (!browserWindow || !windowExists(browserWindow)) {
|
||||
return;
|
||||
}
|
||||
const { response } = await dialog.showMessageBox({
|
||||
type: 'error',
|
||||
title: i18n.t('Renderer Process Crashed')(),
|
||||
message: i18n.t(
|
||||
'Oops! Looks like we have had a crash. Please reload or close this window.',
|
||||
)(),
|
||||
buttons: ['Reload', 'Close'],
|
||||
});
|
||||
response === 0 ? browserWindow.reload() : browserWindow.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a GPU crash event
|
||||
* @private
|
||||
*/
|
||||
private static handleGpuCrash() {
|
||||
app.on('gpu-process-crashed', (_event: Event, _killed: boolean) => {
|
||||
logger.info(`crash-handler: GPU process crashed.`);
|
||||
const eventData: ICrashData = {
|
||||
element: AnalyticsElements.SDA_CRASH,
|
||||
process: SDACrashProcess.GPU,
|
||||
windowName: 'main',
|
||||
crashCause: _killed ? 'killed' : 'crashed',
|
||||
};
|
||||
analytics.track(eventData);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a main process crash event
|
||||
* @private
|
||||
*/
|
||||
private static handleMainProcessCrash() {
|
||||
const lastCrash = crashReporter.getLastCrashReport();
|
||||
if (!lastCrash) {
|
||||
logger.info(`crash-handler: No crashes found for main process`);
|
||||
return;
|
||||
}
|
||||
const eventData: ICrashData = {
|
||||
element: AnalyticsElements.SDA_CRASH,
|
||||
process: SDACrashProcess.MAIN,
|
||||
windowName: 'main',
|
||||
crashCause: lastCrash.id,
|
||||
};
|
||||
analytics.track(eventData);
|
||||
}
|
||||
|
||||
constructor() {
|
||||
CrashHandler.handleMainProcessCrash();
|
||||
CrashHandler.handleGpuCrash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a crash event for a browser window
|
||||
* @param browserWindow Browser Window on which the crash should be handled
|
||||
*/
|
||||
public handleRendererCrash(browserWindow: ICustomBrowserWindow) {
|
||||
browserWindow.webContents.on(
|
||||
'render-process-gone',
|
||||
async (_event: Event, details: Details) => {
|
||||
logger.info(`crash-handler: Renderer process for ${browserWindow.winName} crashed.
|
||||
Reason is ${details.reason}`);
|
||||
const eventData: ICrashData = {
|
||||
element: AnalyticsElements.SDA_CRASH,
|
||||
process: SDACrashProcess.RENDERER,
|
||||
windowName: browserWindow.winName,
|
||||
crashCause: details.reason,
|
||||
};
|
||||
switch (details.reason) {
|
||||
case 'abnormal-exit':
|
||||
case 'crashed':
|
||||
case 'integrity-failure':
|
||||
case 'launch-failed':
|
||||
case 'oom':
|
||||
await CrashHandler.showMessageToUser(browserWindow);
|
||||
analytics.track(eventData);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const crashHandler = new CrashHandler();
|
||||
|
||||
export default crashHandler;
|
@ -1,4 +1,4 @@
|
||||
import { app } from 'electron';
|
||||
import { app, crashReporter } from 'electron';
|
||||
import * as path from 'path';
|
||||
|
||||
import { isDevEnv, isNodeEnv } from '../common/env';
|
||||
@ -39,6 +39,14 @@ if (userDataPath) {
|
||||
|
||||
logger.info(`init: Fetch user data path`, app.getPath('userData'));
|
||||
|
||||
logger.info(`Crashes directory: ${app.getPath('crashDumps')}`);
|
||||
crashReporter.start({
|
||||
submitURL: '',
|
||||
uploadToServer: false,
|
||||
ignoreSystemCrashHandler: false,
|
||||
});
|
||||
logger.info(`Crash Reporter started`);
|
||||
|
||||
// Log app statistics
|
||||
appStats.logStats();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import * as archiver from 'archiver';
|
||||
import { app, BrowserWindow, crashReporter, dialog, shell } from 'electron';
|
||||
import { app, BrowserWindow, dialog, shell } from 'electron';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
@ -184,7 +184,7 @@ export const exportLogs = (): void => {
|
||||
*/
|
||||
export const exportCrashDumps = (): void => {
|
||||
const FILE_EXTENSIONS = isMac ? ['.dmp'] : ['.dmp', '.txt'];
|
||||
const crashesDirectory = (crashReporter as any).getCrashesDirectory();
|
||||
const crashesDirectory = app.getPath('crashDumps');
|
||||
const source = isMac ? crashesDirectory + '/completed' : crashesDirectory;
|
||||
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
|
||||
|
@ -40,6 +40,7 @@ import {
|
||||
IConfig,
|
||||
IGlobalConfig,
|
||||
} from './config-handler';
|
||||
import crashHandler from './crash-handler';
|
||||
import { SpellChecker } from './spell-check-handler';
|
||||
import { checkIfBuildExpired } from './ttl-handler';
|
||||
import { versionHandler } from './version-handler';
|
||||
@ -232,23 +233,6 @@ export class WindowHandler {
|
||||
app.getLocale()) as LocaleType;
|
||||
i18n.setLocale(locale);
|
||||
|
||||
try {
|
||||
const extra = {
|
||||
podUrl: this.userConfig.url
|
||||
? this.userConfig.url
|
||||
: this.globalConfig.url,
|
||||
process: 'main',
|
||||
};
|
||||
const defaultOpts = {
|
||||
uploadToServer: false,
|
||||
companyName: 'Symphony',
|
||||
submitURL: '',
|
||||
};
|
||||
crashReporter.start({ ...defaultOpts, extra });
|
||||
} catch (e) {
|
||||
throw new Error('failed to init crash report');
|
||||
}
|
||||
|
||||
this.listenForLoad();
|
||||
}
|
||||
|
||||
@ -625,6 +609,14 @@ export class WindowHandler {
|
||||
this.destroyAllWindows();
|
||||
});
|
||||
|
||||
crashReporter.start({
|
||||
submitURL: '',
|
||||
uploadToServer: false,
|
||||
ignoreSystemCrashHandler: false,
|
||||
});
|
||||
|
||||
crashHandler.handleRendererCrash(this.mainWindow);
|
||||
|
||||
// Reloads the Symphony
|
||||
ipcMain.on('reload-symphony', () => {
|
||||
this.reloadSymphony();
|
||||
|
Loading…
Reference in New Issue
Block a user