diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2022-11-07 14:46:07 +0100 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2022-11-07 14:46:07 +0100 |
| commit | 2e74d77a4f6ace207a29ff366d0132685a965523 (patch) | |
| tree | 7921c63578a79de74aaaa4a708cb752cff548f49 | |
| parent | 735601ed34ab83fa4443424aa2ddf9068b27f6bd (diff) | |
| parent | c48585f44062138a1abc42f8a3d9dafa4172e923 (diff) | |
| download | mullvadvpn-2e74d77a4f6ace207a29ff366d0132685a965523.tar.xz mullvadvpn-2e74d77a4f6ace207a29ff366d0132685a965523.zip | |
Merge branch 'improve-renderer-log-forwarder'
| -rw-r--r-- | gui/src/main/index.ts | 12 | ||||
| -rw-r--r-- | gui/src/main/logging.ts | 25 | ||||
| -rw-r--r-- | gui/src/main/user-interface.ts | 7 | ||||
| -rw-r--r-- | gui/src/renderer/components/AppRouter.tsx | 2 | ||||
| -rw-r--r-- | gui/src/renderer/components/Debug.tsx | 90 | ||||
| -rw-r--r-- | gui/src/renderer/components/Settings.tsx | 17 | ||||
| -rw-r--r-- | gui/src/renderer/lib/routes.ts | 1 |
7 files changed, 142 insertions, 12 deletions
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts index 4649cac8a7..bc971b24f9 100644 --- a/gui/src/main/index.ts +++ b/gui/src/main/index.ts @@ -18,11 +18,7 @@ import { SystemNotification } from '../shared/notifications/notification'; import Account, { AccountDelegate, LocaleProvider } from './account'; import { getOpenAtLogin } from './autostart'; import { readChangelog } from './changelog'; -import { - SHOULD_DISABLE_RESET_NAVIGATION, - SHOULD_FORWARD_RENDERER_LOG, - SHOULD_SHOW_CHANGES, -} from './command-line-options'; +import { SHOULD_DISABLE_RESET_NAVIGATION, SHOULD_SHOW_CHANGES } from './command-line-options'; import { ConnectionObserver, DaemonRpc, SubscriptionListener } from './daemon-rpc'; import Expectation from './expectation'; import { IpcMainEventChannel } from './ipc-event-channel'; @@ -250,11 +246,7 @@ class ApplicationMain const mainLogPath = getMainLogPath(); const rendererLogPath = getRendererLogPath(); - if (process.env.NODE_ENV === 'development') { - if (SHOULD_FORWARD_RENDERER_LOG) { - log.addInput(new IpcInput()); - } - } else { + if (process.env.NODE_ENV === 'production') { this.rendererLog = new Logger(); this.rendererLog.addInput(new IpcInput()); diff --git a/gui/src/main/logging.ts b/gui/src/main/logging.ts index 0e488914ce..8798b52066 100644 --- a/gui/src/main/logging.ts +++ b/gui/src/main/logging.ts @@ -1,4 +1,4 @@ -import { app } from 'electron'; +import { app, WebContents } from 'electron'; import fs from 'fs'; import path from 'path'; @@ -37,6 +37,29 @@ export class IpcInput implements ILogInput { } } +export class WebContentsConsoleInput implements ILogInput { + public constructor(private webContents: WebContents) {} + + public on(handler: (level: LogLevel, message: string) => void) { + const levelMap = [LogLevel.verbose, LogLevel.info, LogLevel.warning, LogLevel.error]; + + this.webContents.on('console-message', (_event, consoleLevel, message) => { + const level = levelMap[consoleLevel]; + handler(level, WebContentsConsoleInput.formatMessage(level, message)); + }); + + this.webContents.on('preload-error', (_event, _path, error) => + handler(LogLevel.error, WebContentsConsoleInput.formatMessage(LogLevel.error, error.message)), + ); + } + + private static formatMessage(level: LogLevel, message: string) { + // Prefix all messages from renderer with [Renderer] in blue or red depending on level. + const color = level === LogLevel.error ? '\x1b[31m' : '\x1b[34m'; + return `${color}[Renderer]\x1b[0m ${message}`; + } +} + export function getMainLogPath() { return path.join(getLogDirectoryDir(), 'frontend-main.log'); } diff --git a/gui/src/main/user-interface.ts b/gui/src/main/user-interface.ts index ae9e9c8592..624347a9d3 100644 --- a/gui/src/main/user-interface.ts +++ b/gui/src/main/user-interface.ts @@ -8,9 +8,10 @@ import { IAccountData, ILocation, TunnelState } from '../shared/daemon-rpc-types import { messages, relayLocations } from '../shared/gettext'; import log from '../shared/logging'; import { Scheduler } from '../shared/scheduler'; -import { SHOULD_DISABLE_DEVTOOLS_OPEN } from './command-line-options'; +import { SHOULD_DISABLE_DEVTOOLS_OPEN, SHOULD_FORWARD_RENDERER_LOG } from './command-line-options'; import { DaemonRpc } from './daemon-rpc'; import { changeIpcWebContents, IpcMainEventChannel } from './ipc-event-channel'; +import { WebContentsConsoleInput } from './logging'; import { isMacOs11OrNewer } from './platform-version'; import TrayIconController, { TrayIconType } from './tray-icon-controller'; import WindowController, { WindowControllerDelegate } from './window-controller'; @@ -96,6 +97,10 @@ export default class UserInterface implements WindowControllerDelegate { // The devtools doesn't open on Windows if openDevTools is called without a delay here. window.once('ready-to-show', () => window.webContents.openDevTools({ mode: 'detach' })); } + + if (SHOULD_FORWARD_RENDERER_LOG) { + log.addInput(new WebContentsConsoleInput(window.webContents)); + } } switch (process.platform) { diff --git a/gui/src/renderer/components/AppRouter.tsx b/gui/src/renderer/components/AppRouter.tsx index 4dad09a773..cab40d9db9 100644 --- a/gui/src/renderer/components/AppRouter.tsx +++ b/gui/src/renderer/components/AppRouter.tsx @@ -7,6 +7,7 @@ import { useAppContext } from '../context'; import { ITransitionSpecification, transitions, useHistory } from '../lib/history'; import { RoutePath } from '../lib/routes'; import Account from './Account'; +import Debug from './Debug'; import { DeviceRevokedView } from './DeviceRevokedView'; import { SetupFinished, @@ -79,6 +80,7 @@ export default function AppRouter() { <Route exact path={RoutePath.splitTunneling} component={SplitTunnelingSettings} /> <Route exact path={RoutePath.support} component={Support} /> <Route exact path={RoutePath.problemReport} component={ProblemReport} /> + <Route exact path={RoutePath.debug} component={Debug} /> <Route exact path={RoutePath.selectLocation} component={SelectLocationPage} /> <Route exact path={RoutePath.filter} component={Filter} /> </Switch> diff --git a/gui/src/renderer/components/Debug.tsx b/gui/src/renderer/components/Debug.tsx new file mode 100644 index 0000000000..f81fb85402 --- /dev/null +++ b/gui/src/renderer/components/Debug.tsx @@ -0,0 +1,90 @@ +import { useCallback } from 'react'; +import styled from 'styled-components'; + +import { useHistory } from '../lib/history'; +import { useBoolean } from '../lib/utilityHooks'; +import * as AppButton from './AppButton'; +import { measurements } from './common-styles'; +import { BackAction } from './KeyboardNavigation'; +import { Layout, SettingsContainer } from './Layout'; +import { + NavigationBar, + NavigationContainer, + NavigationItems, + NavigationScrollbars, + TitleBarItem, +} from './NavigationBar'; +import SettingsHeader, { HeaderTitle } from './SettingsHeader'; + +const StyledContent = styled.div({ + display: 'flex', + flexDirection: 'column', + flex: 1, + marginBottom: '2px', +}); + +const StyledButtonGroup = styled.div({ + margin: measurements.viewMargin, +}); + +export default function Debug() { + const { pop } = useHistory(); + + return ( + <BackAction action={pop}> + <Layout> + <SettingsContainer> + <NavigationContainer> + <NavigationBar> + <NavigationItems> + <TitleBarItem>Developer tools</TitleBarItem> + </NavigationItems> + </NavigationBar> + + <NavigationScrollbars> + <SettingsHeader> + <HeaderTitle>Developer tools</HeaderTitle> + </SettingsHeader> + + <StyledContent> + <StyledButtonGroup> + <AppButton.ButtonGroup> + <ThrowErrorButton /> + <UnhandledRejectionButton /> + <ErrorDuringRender /> + </AppButton.ButtonGroup> + </StyledButtonGroup> + </StyledContent> + </NavigationScrollbars> + </NavigationContainer> + </SettingsContainer> + </Layout> + </BackAction> + ); +} + +function ThrowErrorButton() { + const handleClick = useCallback(() => { + throw new Error('This is a test error'); + }, []); + + return <AppButton.RedButton onClick={handleClick}>Throw error</AppButton.RedButton>; +} + +function UnhandledRejectionButton() { + const handleClick = useCallback(() => { + return new Promise((_resolve, reject) => setTimeout(reject, 100)); + }, []); + + return <AppButton.RedButton onClick={handleClick}>Unhandled rejection</AppButton.RedButton>; +} + +function ErrorDuringRender() { + const [error, setError] = useBoolean(false); + + if (error) { + throw new Error('This is a test error during render'); + } + + return <AppButton.RedButton onClick={setError}>Error next render</AppButton.RedButton>; +} diff --git a/gui/src/renderer/components/Settings.tsx b/gui/src/renderer/components/Settings.tsx index 69d4e2b80a..fb4feec8fd 100644 --- a/gui/src/renderer/components/Settings.tsx +++ b/gui/src/renderer/components/Settings.tsx @@ -84,6 +84,12 @@ export default function Support() { <SupportButton /> <AppVersionButton /> </Cell.Group> + + {window.env.development && ( + <Cell.Group> + <DebugButton /> + </Cell.Group> + )} </StyledSettingsContent> </StyledContent> @@ -237,6 +243,17 @@ function SupportButton() { ); } +function DebugButton() { + const history = useHistory(); + const navigate = useCallback(() => history.push(RoutePath.debug), [history]); + + return ( + <Cell.CellNavigationButton onClick={navigate}> + <Cell.Label>Developer tools</Cell.Label> + </Cell.CellNavigationButton> + ); +} + function QuitButton() { const { quit } = useAppContext(); diff --git a/gui/src/renderer/lib/routes.ts b/gui/src/renderer/lib/routes.ts index 3a82175d3e..eaefb26c67 100644 --- a/gui/src/renderer/lib/routes.ts +++ b/gui/src/renderer/lib/routes.ts @@ -22,6 +22,7 @@ export enum RoutePath { splitTunneling = '/settings/split-tunneling', support = '/settings/support', problemReport = '/settings/support/problem-report', + debug = '/settings/debug', selectLocation = '/select-location', filter = '/select-location/filter', } |
