summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2022-11-07 14:46:07 +0100
committerOskar Nyberg <oskar@mullvad.net>2022-11-07 14:46:07 +0100
commit2e74d77a4f6ace207a29ff366d0132685a965523 (patch)
tree7921c63578a79de74aaaa4a708cb752cff548f49
parent735601ed34ab83fa4443424aa2ddf9068b27f6bd (diff)
parentc48585f44062138a1abc42f8a3d9dafa4172e923 (diff)
downloadmullvadvpn-2e74d77a4f6ace207a29ff366d0132685a965523.tar.xz
mullvadvpn-2e74d77a4f6ace207a29ff366d0132685a965523.zip
Merge branch 'improve-renderer-log-forwarder'
-rw-r--r--gui/src/main/index.ts12
-rw-r--r--gui/src/main/logging.ts25
-rw-r--r--gui/src/main/user-interface.ts7
-rw-r--r--gui/src/renderer/components/AppRouter.tsx2
-rw-r--r--gui/src/renderer/components/Debug.tsx90
-rw-r--r--gui/src/renderer/components/Settings.tsx17
-rw-r--r--gui/src/renderer/lib/routes.ts1
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',
}