Crash reporter plugin
Summary: This diff adds a static function `onRegisterDevice` which is being called whenever an device gets registered. This callback is used to add loglisterner for android. I even moved the logic of iOS from `onRegisterPlugin` to this callback. The reason for not adding android log listener in `onRegisterPlugin` was that there were cases when baseDevice was not yet registered before calling `onRegisterPlugin`. For android, I want the instance of `BaseDevice` so that I can add logListener on it. Reviewed By: danielbuechele Differential Revision: D13563282 fbshipit-source-id: b5be40f3dbc808bdaeabae28423c563cf2345a22
This commit is contained in:
committed by
Facebook Github Bot
parent
c6efea991d
commit
0048fc6e4a
@@ -11,6 +11,7 @@ import promiseRetry from 'promise-retry';
|
|||||||
import type {Store} from '../reducers/index.js';
|
import type {Store} from '../reducers/index.js';
|
||||||
import type BaseDevice from '../devices/BaseDevice';
|
import type BaseDevice from '../devices/BaseDevice';
|
||||||
import type Logger from '../fb-stubs/Logger.js';
|
import type Logger from '../fb-stubs/Logger.js';
|
||||||
|
import {registerDeviceCallbackOnPlugins} from '../utils/onRegisterDevice.js';
|
||||||
const adb = require('adbkit-fb');
|
const adb = require('adbkit-fb');
|
||||||
|
|
||||||
function createDevice(adbClient, device): Promise<AndroidDevice> {
|
function createDevice(adbClient, device): Promise<AndroidDevice> {
|
||||||
@@ -165,6 +166,13 @@ export default (store: Store, logger: Logger) => {
|
|||||||
type: 'REGISTER_DEVICE',
|
type: 'REGISTER_DEVICE',
|
||||||
payload: androidDevice,
|
payload: androidDevice,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerDeviceCallbackOnPlugins(
|
||||||
|
store,
|
||||||
|
store.getState().plugins.devicePlugins,
|
||||||
|
store.getState().plugins.clientPlugins,
|
||||||
|
androidDevice,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function unregisterDevices(deviceIds: Array<string>) {
|
async function unregisterDevices(deviceIds: Array<string>) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import IOSDevice from '../devices/IOSDevice';
|
|||||||
import iosUtil from '../fb-stubs/iOSContainerUtility';
|
import iosUtil from '../fb-stubs/iOSContainerUtility';
|
||||||
import isProduction from '../utils/isProduction.js';
|
import isProduction from '../utils/isProduction.js';
|
||||||
import GK from '../fb-stubs/GK';
|
import GK from '../fb-stubs/GK';
|
||||||
|
import {registerDeviceCallbackOnPlugins} from '../utils/onRegisterDevice.js';
|
||||||
type iOSSimulatorDevice = {|
|
type iOSSimulatorDevice = {|
|
||||||
state: 'Booted' | 'Shutdown' | 'Shutting Down',
|
state: 'Booted' | 'Shutdown' | 'Shutting Down',
|
||||||
availability?: string,
|
availability?: string,
|
||||||
@@ -70,10 +70,17 @@ function queryDevices(store: Store, logger: Logger): Promise<void> {
|
|||||||
name: name,
|
name: name,
|
||||||
serial: udid,
|
serial: udid,
|
||||||
});
|
});
|
||||||
|
const iOSDevice = new IOSDevice(udid, type, name);
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
type: 'REGISTER_DEVICE',
|
type: 'REGISTER_DEVICE',
|
||||||
payload: new IOSDevice(udid, type, name),
|
payload: iOSDevice,
|
||||||
});
|
});
|
||||||
|
registerDeviceCallbackOnPlugins(
|
||||||
|
store,
|
||||||
|
store.getState().plugins.devicePlugins,
|
||||||
|
store.getState().plugins.clientPlugins,
|
||||||
|
iOSDevice,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,26 +56,6 @@ export default (store: Store, logger: Logger) => {
|
|||||||
store.dispatch(addFailedPlugins(failedPlugins));
|
store.dispatch(addFailedPlugins(failedPlugins));
|
||||||
store.dispatch(registerPlugins(initialPlugins));
|
store.dispatch(registerPlugins(initialPlugins));
|
||||||
|
|
||||||
initialPlugins.forEach(p => {
|
|
||||||
if (p.onRegisterPlugin) {
|
|
||||||
p.onRegisterPlugin(store, (pluginKey: string, newPluginState: any) => {
|
|
||||||
const persistedState = getPersistedState(
|
|
||||||
pluginKey,
|
|
||||||
p,
|
|
||||||
store.getState().pluginStates,
|
|
||||||
);
|
|
||||||
if (newPluginState && newPluginState !== persistedState) {
|
|
||||||
store.dispatch(
|
|
||||||
setPluginState({
|
|
||||||
pluginKey: pluginKey,
|
|
||||||
state: newPluginState,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let state: ?State = null;
|
let state: ?State = null;
|
||||||
store.subscribe(() => {
|
store.subscribe(() => {
|
||||||
const newState = store.getState().plugins;
|
const newState = store.getState().plugins;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export type {Store} from './reducers/index.js';
|
|||||||
export {
|
export {
|
||||||
default as SidebarExtensions,
|
default as SidebarExtensions,
|
||||||
} from './fb-stubs/LayoutInspectorSidebarExtensions.js';
|
} from './fb-stubs/LayoutInspectorSidebarExtensions.js';
|
||||||
|
export {DeviceLogListener, DeviceLogEntry} from './devices/BaseDevice.js';
|
||||||
export {createTablePlugin} from './createTablePlugin.js';
|
export {createTablePlugin} from './createTablePlugin.js';
|
||||||
export {default as DetailSidebar} from './chrome/DetailSidebar.js';
|
export {default as DetailSidebar} from './chrome/DetailSidebar.js';
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,9 @@ export class FlipperBasePlugin<
|
|||||||
static getActiveNotifications: ?(
|
static getActiveNotifications: ?(
|
||||||
persistedState: PersistedState,
|
persistedState: PersistedState,
|
||||||
) => Array<Notification>;
|
) => Array<Notification>;
|
||||||
static onRegisterPlugin: ?(
|
static onRegisterDevice: ?(
|
||||||
store: Store,
|
store: Store,
|
||||||
|
baseDevice: BaseDevice,
|
||||||
setPersistedState: (
|
setPersistedState: (
|
||||||
pluginKey: string,
|
pluginKey: string,
|
||||||
newPluginState: ?PersistedState,
|
newPluginState: ?PersistedState,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import os from 'os';
|
|||||||
import util from 'util';
|
import util from 'util';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import type {Notification} from '../../plugin';
|
import type {Notification} from '../../plugin';
|
||||||
import type {Store} from 'flipper';
|
import type {Store, DeviceLogEntry} from 'flipper';
|
||||||
|
|
||||||
export type Crash = {|
|
export type Crash = {|
|
||||||
notificationID: string,
|
notificationID: string,
|
||||||
@@ -107,6 +107,7 @@ export function parseCrashLogAndUpdateState(
|
|||||||
!shouldShowCrashNotification(
|
!shouldShowCrashNotification(
|
||||||
store.getState().connections.selectedDevice,
|
store.getState().connections.selectedDevice,
|
||||||
content,
|
content,
|
||||||
|
store.getState().connections.selectedDevice?.os,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
@@ -140,7 +141,11 @@ export function parseCrashLogAndUpdateState(
|
|||||||
export function shouldShowCrashNotification(
|
export function shouldShowCrashNotification(
|
||||||
baseDevice: ?BaseDevice,
|
baseDevice: ?BaseDevice,
|
||||||
content: string,
|
content: string,
|
||||||
|
os: ?string,
|
||||||
): boolean {
|
): boolean {
|
||||||
|
if (os && os.includes('Android')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
const appPath = parsePath(content);
|
const appPath = parsePath(content);
|
||||||
const serial: string = baseDevice?.serial || 'unknown';
|
const serial: string = baseDevice?.serial || 'unknown';
|
||||||
if (!appPath || !appPath.includes(serial)) {
|
if (!appPath || !appPath.includes(serial)) {
|
||||||
@@ -253,19 +258,6 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin<
|
|||||||
return persistedState;
|
return persistedState;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* This function gets called whenever plugin is registered
|
|
||||||
*/
|
|
||||||
static onRegisterPlugin = (
|
|
||||||
store: Store,
|
|
||||||
setPersistedState: (
|
|
||||||
pluginKey: string,
|
|
||||||
newPluginState: ?PersistedState,
|
|
||||||
) => void,
|
|
||||||
): void => {
|
|
||||||
addFileWatcherForiOSCrashLogs(store, setPersistedState);
|
|
||||||
};
|
|
||||||
|
|
||||||
static trimCallStackIfPossible = (callstack: string): string => {
|
static trimCallStackIfPossible = (callstack: string): string => {
|
||||||
let regex = /Application Specific Information:/;
|
let regex = /Application Specific Information:/;
|
||||||
const query = regex.exec(callstack);
|
const query = regex.exec(callstack);
|
||||||
@@ -289,6 +281,45 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin<
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function gets called whenever the device is registered
|
||||||
|
*/
|
||||||
|
static onRegisterDevice = (
|
||||||
|
store: Store,
|
||||||
|
baseDevice: BaseDevice,
|
||||||
|
setPersistedState: (
|
||||||
|
pluginKey: string,
|
||||||
|
newPluginState: ?PersistedState,
|
||||||
|
) => void,
|
||||||
|
): void => {
|
||||||
|
if (baseDevice.os.includes('iOS')) {
|
||||||
|
addFileWatcherForiOSCrashLogs(store, setPersistedState);
|
||||||
|
} else {
|
||||||
|
const referenceDate = new Date();
|
||||||
|
(function(
|
||||||
|
store: Store,
|
||||||
|
date: Date,
|
||||||
|
setPersistedState: (
|
||||||
|
pluginKey: string,
|
||||||
|
newPluginState: ?PersistedState,
|
||||||
|
) => void,
|
||||||
|
) {
|
||||||
|
baseDevice.addLogListener((entry: DeviceLogEntry) => {
|
||||||
|
if (
|
||||||
|
entry.type === 'error' &&
|
||||||
|
entry.tag === 'AndroidRuntime' &&
|
||||||
|
entry.date.getTime() - date.getTime() > 0
|
||||||
|
) {
|
||||||
|
parseCrashLogAndUpdateState(
|
||||||
|
store,
|
||||||
|
entry.message,
|
||||||
|
setPersistedState,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})(store, referenceDate, setPersistedState);
|
||||||
|
}
|
||||||
|
};
|
||||||
openInLogs = (callstack: string) => {
|
openInLogs = (callstack: string) => {
|
||||||
this.props.selectPlugin('DeviceLogs', callstack);
|
this.props.selectPlugin('DeviceLogs', callstack);
|
||||||
};
|
};
|
||||||
|
|||||||
44
src/utils/onRegisterDevice.js
Normal file
44
src/utils/onRegisterDevice.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
import type {Store} from '../reducers/index.js';
|
||||||
|
import {FlipperPlugin, FlipperDevicePlugin} from '../plugin.js';
|
||||||
|
import type BaseDevice from '../devices/BaseDevice.js';
|
||||||
|
import {setPluginState} from '../reducers/pluginStates.js';
|
||||||
|
import {getPersistedState} from '../utils/pluginUtils.js';
|
||||||
|
|
||||||
|
export function registerDeviceCallbackOnPlugins(
|
||||||
|
store: Store,
|
||||||
|
devicePlugins: Map<string, Class<FlipperDevicePlugin<>>>,
|
||||||
|
clientPlugins: Map<string, Class<FlipperPlugin<>>>,
|
||||||
|
device: BaseDevice,
|
||||||
|
) {
|
||||||
|
const callRegisterDeviceHook = plugin => {
|
||||||
|
if (plugin.onRegisterDevice) {
|
||||||
|
plugin.onRegisterDevice(
|
||||||
|
store,
|
||||||
|
device,
|
||||||
|
(pluginKey: string, newPluginState: any) => {
|
||||||
|
const persistedState = getPersistedState(
|
||||||
|
pluginKey,
|
||||||
|
plugin,
|
||||||
|
store.getState().pluginStates,
|
||||||
|
);
|
||||||
|
if (newPluginState && newPluginState !== persistedState) {
|
||||||
|
store.dispatch(
|
||||||
|
setPluginState({
|
||||||
|
pluginKey,
|
||||||
|
state: newPluginState,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
devicePlugins.forEach(callRegisterDeviceHook);
|
||||||
|
clientPlugins.forEach(callRegisterDeviceHook);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user