diff --git a/app/main/appium.js b/app/main/appium.js index 70d71856e..ecc77794b 100644 --- a/app/main/appium.js +++ b/app/main/appium.js @@ -5,6 +5,7 @@ import { main as appiumServer } from 'appium'; import { getDefaultArgs, getParser } from 'appium/build/lib/parser'; import path from 'path'; import wd from 'wd'; +import { fs, tempDir } from 'appium-support'; import settings from '../settings'; import autoUpdaterController from './auto-updater'; import AppiumMethodHandler from './appium-method-handler'; @@ -20,10 +21,19 @@ var batchedLogs = []; let sessionDrivers = {}; let appiumHandlers = {}; +let logFile; // Delete saved server args, don't start until a server has been started settings.deleteSync('SERVER_ARGS'); +async function deleteLogfile () { + if (logFile) { + try { + await fs.rimraf(logFile); + } catch (ign) { } + } +} + /** * Kill session associated with session browser window */ @@ -46,6 +56,14 @@ async function killSession (sessionWinID) { function connectStartServer (win) { ipcMain.on('start-server', async (event, args) => { + // log the server logs to a file + try { + const dir = await tempDir.openDir(); + logFile = path.resolve(dir, 'appium-server-logs.txt'); + win.webContents.send('path-to-logs', logFile); + win.on('close', deleteLogfile); + } catch (ign) { } + // clean up args object for appium log purposes (so it doesn't show in // non-default args list if (args.defaultCapabilities && @@ -60,9 +78,16 @@ function connectStartServer (win) { args.throwInsteadOfExit = true; // set up our log watcher - logWatcher = setInterval(() => { + logWatcher = setInterval(async () => { if (batchedLogs.length) { - win.webContents.send('appium-log-line', batchedLogs); + try { + await fs.writeFile( + logFile, + batchedLogs.map((log) => `[${log.level}] ${log.msg}`).join('\n'), + {flag: 'a'} + ); + win.webContents.send('appium-log-line', batchedLogs); + } catch (ign) { } batchedLogs = []; } }, LOG_SEND_INTERVAL_MS); @@ -90,6 +115,7 @@ function connectStopServer (win) { } catch (e) { win.webContents.send('appium-stop-error', e.message); } + clearInterval(logWatcher); await settings.delete('SERVER_ARGS'); }); diff --git a/app/renderer/actions/ServerMonitor.js b/app/renderer/actions/ServerMonitor.js index 82cd545b0..e2c326be6 100644 --- a/app/renderer/actions/ServerMonitor.js +++ b/app/renderer/actions/ServerMonitor.js @@ -1,4 +1,4 @@ -import { ipcRenderer } from 'electron'; +import { ipcRenderer, shell } from 'electron'; import { push } from 'react-router-redux'; export const SERVER_STOP_REQ = 'SERVER_STOP_REQ'; @@ -86,4 +86,15 @@ export function startSession () { dispatch({type: START_SESSION_REQUEST}); ipcRenderer.send('create-new-session-window'); }; +} + +export function getRawLogs () { + return (dispatch, getState) => { + const logfilePath = getState().startServer.logfilePath; + if (logfilePath) { + shell.openExternal(`file://${logfilePath}`); + } else { + alert('An error has occurred: Logs not available'); + } + }; } \ No newline at end of file diff --git a/app/renderer/actions/StartServer.js b/app/renderer/actions/StartServer.js index 66280289e..63dec9341 100644 --- a/app/renderer/actions/StartServer.js +++ b/app/renderer/actions/StartServer.js @@ -14,6 +14,7 @@ export const PRESET_SAVE_OK = 'PRESET_SAVE_OK'; export const GET_PRESETS = 'GET_PRESETS'; export const PRESET_DELETE_REQ = 'PRESET_DELETE_REQ'; export const PRESET_DELETE_OK = 'PRESET_DELETE_OK'; +export const SET_LOGFILE_PATH = 'SET_LOGFILE_PATH'; export const PRESETS = 'presets'; @@ -47,6 +48,7 @@ export function startServer (evt) { }); dispatch(clearLogs()); + ipcRenderer.once('path-to-logs', (event, logfilePath) => dispatch({type: SET_LOGFILE_PATH, logfilePath})); ipcRenderer.send('start-server', serverArgs); }; } @@ -104,4 +106,4 @@ export function deletePreset (name) { } dispatch({type: PRESET_DELETE_OK, presets}); }; -} +} \ No newline at end of file diff --git a/app/renderer/components/ServerMonitor/ServerMonitor.css b/app/renderer/components/ServerMonitor/ServerMonitor.css index 77168c582..fb88f2a6f 100644 --- a/app/renderer/components/ServerMonitor/ServerMonitor.css +++ b/app/renderer/components/ServerMonitor/ServerMonitor.css @@ -57,13 +57,20 @@ margin-right: 10px; } -.stopButton { + +.serverButton { color: #a0a0a0 !important; background-image: none !important; background-color: #252525 !important; border-color: #a0a0a0 !important; } +.getRawLogsButton { + position: absolute; + right: 0; + margin: 0 1em 0 0; +} + .term { white-space: pre-wrap; width: 100%; diff --git a/app/renderer/components/ServerMonitor/ServerMonitor.js b/app/renderer/components/ServerMonitor/ServerMonitor.js index 49eecb127..e8e56aee1 100644 --- a/app/renderer/components/ServerMonitor/ServerMonitor.js +++ b/app/renderer/components/ServerMonitor/ServerMonitor.js @@ -31,15 +31,15 @@ class StopButton extends Component { render () { const {serverStatus, stopServer, closeMonitor} = this.props; - let btn = ; if (serverStatus === STATUS_STOPPED) { - btn = ; } else if (serverStatus === STATUS_STOPPING) { btn = ; + className={styles.serverButton} type="disabled">Stopping...; } return btn; } @@ -54,7 +54,7 @@ class StartSessionButton extends Component { render () { const {serverStatus, startSession} = this.props; if (serverStatus !== STATUS_STOPPED && serverStatus !== STATUS_STOPPING) { - return ; } else { @@ -63,6 +63,14 @@ class StartSessionButton extends Component { } } +class GetRawLogsButton extends Component { + render () { + return ; + } +} + export default class ServerMonitor extends Component { static propTypes = { @@ -149,6 +157,7 @@ export default class ServerMonitor extends Component {