Crashreporter plugin by adding a watchman for crash log

Summary:
This diff adds a watcher on `~/Library/Logs/Diagnostics/` library and fires a notification whenever a crash log is added there. This will only work for iOS crashes. With this change, for iOS we should be able to see all kind of crash notification be it due to uncaught exception or a native crash or signal errors.

For android, it will still show notifications due to uncaught exceptions. In upcoming diffs, I will change the logic for android too by parsing Logcat logs.

This diff doesn't support physical device crash reporting. The crashes for physical devices are synced to other folder and that too they are symbolicated.

Reviewed By: danielbuechele

Differential Revision: D13404648

fbshipit-source-id: 7219855ebc73451af87f77f90cc3ed0f2ab5287c
This commit is contained in:
Pritesh Nandgaonkar
2018-12-18 13:30:50 -08:00
committed by Facebook Github Bot
parent e3fb1e1d84
commit a12768539e
3 changed files with 353 additions and 15 deletions

View File

@@ -19,13 +19,14 @@ import {
} from 'flipper';
import type {Notification} from '../../plugin';
type Crash = {|
notificationID: number,
callStack: string,
export type Crash = {|
notificationID: string,
callstack: string,
reason: string,
name: string,
|};
type PersistedState = {|
export type PersistedState = {|
crashes: Array<Crash>,
|};
@@ -70,6 +71,8 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin {
static supportsDevice(device: Device) {
return device.os === 'iOS' || device.os === 'Android';
}
static notificationID: number = 0;
/*
* Reducer to process incoming "send" messages from the mobile counterpart.
*/
@@ -79,21 +82,27 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin {
payload: Object,
): PersistedState => {
if (method === 'crash-report') {
return {
...persistedState,
CrashReporterPlugin.notificationID++;
const mergedState: PersistedState = {
crashes: persistedState.crashes.concat([
{
notificationID: Math.random(), // All notifications are unique
callStack: payload.callstack,
notificationID: CrashReporterPlugin.notificationID.toString(), // All notifications are unique
callstack: payload.callstack,
name: payload.name,
reason: payload.reason,
},
]),
};
return mergedState;
}
return persistedState;
};
static trimCallStackIfPossible = (callstack: string): string => {
let regex = /Application Specific Information:/;
const query = regex.exec(callstack);
return query ? callstack.substring(0, query.index) : callstack;
};
/*
* Callback to provide the currently active notifications.
*/
@@ -101,10 +110,10 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin {
persistedState: PersistedState,
): Array<Notification> => {
return persistedState.crashes.map((crash: Crash) => {
const id = 'crash-notification:' + crash.notificationID;
const id = crash.notificationID;
return {
id,
message: crash.callStack,
message: CrashReporterPlugin.trimCallStackIfPossible(crash.callstack),
severity: 'error',
title: 'CRASH: ' + crash.name + ' ' + crash.reason,
action: id,
@@ -124,7 +133,7 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin {
];
if (crash) {
const callStackString = crash.callStack;
const callstackString = crash.callstack;
return (
<RootColumn>
<CrashRow>
@@ -144,16 +153,16 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin {
{
label: 'copy',
click: () => {
clipboard.writeText(callStackString);
clipboard.writeText(callstackString);
},
},
]}>
<CallStack>{callStackString}</CallStack>
<CallStack>{callstackString}</CallStack>
</ContextMenu>
</CrashRow>
{this.device.os == 'Android' && (
<CrashRow>
<Button onClick={() => this.openInLogs(crash.callStack)}>
<Button onClick={() => this.openInLogs(crash.callstack)}>
Open in Logs
</Button>
</CrashRow>