Introduced first class console to help users debugging issues (#1479)
Summary: Handling issues typically start with: did you look at the Electron logs? Since Flipper is such an extensible tool, running in varying environments I think the console should be support as first class concept. Many errors are currently not shown to the user. This PR is a first attempt to fix that. The implementation is based on https://github.com/samdenty/console-feed, which is used by quite some web based IDE like tools (like codesandbox), and offers a lot of goodies out of the box, like collapsing errors, objects, etc. Edit: also added a counter keeping track of the amount of errors N.B. no need to immediately review this diff, I'll import it to phabricator as soon as I can :) ## Changelog changelog: Introduce 'Debug Logs' section to help users to troubleshoot issues or to provide more accurate reports. Pull Request resolved: https://github.com/facebook/flipper/pull/1479 Test Plan:  Reviewed By: jknoxville Differential Revision: D23198103 Pulled By: passy fbshipit-source-id: a2505f9fa59e10676a44ffa33312efe83c7be55d
This commit is contained in:
committed by
Facebook GitHub Bot
parent
baa29d0b49
commit
dd15cffa64
@@ -23,6 +23,7 @@
|
||||
"archiver": "^5.0.0",
|
||||
"async-mutex": "^0.1.3",
|
||||
"axios": "^0.19.2",
|
||||
"console-feed": "^3.0.1",
|
||||
"deep-equal": "^2.0.1",
|
||||
"emotion": "^10.0.23",
|
||||
"expand-tilde": "^2.0.2",
|
||||
|
||||
93
desktop/app/src/chrome/ConsoleLogs.tsx
Normal file
93
desktop/app/src/chrome/ConsoleLogs.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {useMemo} from 'react';
|
||||
import {Button, Toolbar, ButtonGroup, Layout} from '../ui';
|
||||
import React from 'react';
|
||||
import {Console, Hook} from 'console-feed';
|
||||
import type {Methods} from 'console-feed/lib/definitions/Methods';
|
||||
import {createState, useValue} from 'flipper-plugin';
|
||||
import {useLocalStorage} from '../utils/useLocalStorage';
|
||||
|
||||
const logsAtom = createState<any[]>([]);
|
||||
export const errorCounterAtom = createState(0);
|
||||
|
||||
export function enableConsoleHook() {
|
||||
console.log('enabling hooks');
|
||||
Hook(
|
||||
window.console,
|
||||
(log) => {
|
||||
logsAtom.set([...logsAtom.get(), log]);
|
||||
if (log.method === 'error' || log.method === 'assert') {
|
||||
errorCounterAtom.set(errorCounterAtom.get() + 1);
|
||||
}
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
function clearLogs() {
|
||||
logsAtom.set([]);
|
||||
errorCounterAtom.set(0);
|
||||
}
|
||||
|
||||
const allLogLevels: Methods[] = [
|
||||
'log',
|
||||
'debug',
|
||||
'info',
|
||||
'warn',
|
||||
'error',
|
||||
'table',
|
||||
'clear',
|
||||
'time',
|
||||
'timeEnd',
|
||||
'count',
|
||||
'assert',
|
||||
];
|
||||
|
||||
const defaultLogLevels: Methods[] = ['warn', 'error', 'table', 'assert'];
|
||||
|
||||
export function ConsoleLogs() {
|
||||
const logs = useValue(logsAtom);
|
||||
const [logLevels, setLogLevels] = useLocalStorage<Methods[]>(
|
||||
'console-logs-loglevels',
|
||||
defaultLogLevels,
|
||||
);
|
||||
|
||||
const dropdown = useMemo(() => {
|
||||
return allLogLevels.map(
|
||||
(l): Electron.MenuItemConstructorOptions => ({
|
||||
label: l,
|
||||
checked: logLevels.includes(l),
|
||||
type: 'checkbox',
|
||||
click() {
|
||||
setLogLevels((state) =>
|
||||
state.includes(l)
|
||||
? state.filter((level) => level !== l)
|
||||
: [l, ...state],
|
||||
);
|
||||
},
|
||||
}),
|
||||
);
|
||||
}, [logLevels, setLogLevels]);
|
||||
|
||||
return (
|
||||
<Layout.Top scrollable>
|
||||
<Toolbar>
|
||||
<ButtonGroup>
|
||||
<Button onClick={clearLogs} icon="trash">
|
||||
Clear Logs
|
||||
</Button>
|
||||
<Button dropdown={dropdown}>Log Levels</Button>
|
||||
</ButtonGroup>
|
||||
</Toolbar>
|
||||
<Console logs={logs} filter={logLevels} variant="light" />
|
||||
</Layout.Top>
|
||||
);
|
||||
}
|
||||
@@ -29,6 +29,8 @@ import {
|
||||
} from './sidebarUtils';
|
||||
import {Group} from '../../reducers/supportForm';
|
||||
import {getInstance} from '../../fb-stubs/Logger';
|
||||
import {ConsoleLogs, errorCounterAtom} from '../ConsoleLogs';
|
||||
import {useValue} from 'flipper-plugin';
|
||||
|
||||
type OwnProps = {};
|
||||
|
||||
@@ -103,6 +105,7 @@ function MainSidebarUtilsSection({
|
||||
/>
|
||||
Manage Plugins
|
||||
</ListItem>
|
||||
<DebugLogsEntry staticView={staticView} setStaticView={setStaticView} />
|
||||
{config.showLogin && <UserAccount />}
|
||||
</div>
|
||||
);
|
||||
@@ -171,3 +174,26 @@ const RenderNotificationsEntry = connect<
|
||||
</ListItem>
|
||||
);
|
||||
});
|
||||
|
||||
function DebugLogsEntry({
|
||||
staticView,
|
||||
setStaticView,
|
||||
}: {
|
||||
staticView: StaticView;
|
||||
setStaticView: (payload: StaticView) => void;
|
||||
}) {
|
||||
const active = isStaticViewActive(staticView, ConsoleLogs);
|
||||
const errorCount = useValue(errorCounterAtom);
|
||||
return (
|
||||
<ListItem onClick={() => setStaticView(ConsoleLogs)} active={active}>
|
||||
<PluginIcon
|
||||
name="caution-octagon"
|
||||
color={colors.light50}
|
||||
isActive={active}
|
||||
/>
|
||||
<PluginName count={errorCount} isActive={active}>
|
||||
Debug Logs
|
||||
</PluginName>
|
||||
</ListItem>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ const PluginShape = styled(FlexBox)<{
|
||||
|
||||
export const PluginName = styled(Text)<{isActive?: boolean; count?: number}>(
|
||||
(props) => ({
|
||||
cursor: 'default',
|
||||
minWidth: 0,
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
|
||||
@@ -38,6 +38,7 @@ import os from 'os';
|
||||
import QuickPerformanceLogger, {FLIPPER_QPL_EVENTS} from './fb-stubs/QPL';
|
||||
import {PopoverProvider} from './ui/components/PopoverProvider';
|
||||
import {initializeFlipperLibImplementation} from './utils/flipperLibImplementation';
|
||||
import {enableConsoleHook} from './chrome/ConsoleLogs';
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && os.platform() === 'darwin') {
|
||||
// By default Node.JS has its internal certificate storage and doesn't use
|
||||
@@ -119,6 +120,7 @@ function init() {
|
||||
const sessionId = store.getState().application.sessionId;
|
||||
initCrashReporter(sessionId || '');
|
||||
registerRecordingHooks(store);
|
||||
enableConsoleHook();
|
||||
window.flipperGlobalStoreDispatch = store.dispatch;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,13 +27,15 @@ import {getPluginKey, isDevicePluginDefinition} from '../utils/pluginUtils';
|
||||
import {deconstructClientId} from '../utils/clientUtils';
|
||||
import {PluginDefinition} from '../plugin';
|
||||
import {RegisterPluginAction} from './plugins';
|
||||
import {ConsoleLogs} from '../chrome/ConsoleLogs';
|
||||
|
||||
export type StaticView =
|
||||
| null
|
||||
| typeof WelcomeScreen
|
||||
| typeof NotificationScreen
|
||||
| typeof SupportRequestFormV2
|
||||
| typeof SupportRequestDetails;
|
||||
| typeof SupportRequestDetails
|
||||
| typeof ConsoleLogs;
|
||||
|
||||
export type FlipperError = {
|
||||
occurrences?: number;
|
||||
|
||||
Reference in New Issue
Block a user