From ffbcb4ecb5bd53dabe8ac15d23e72ae49b5654bb Mon Sep 17 00:00:00 2001 From: Scott Nonnenberg Date: Wed, 4 Oct 2017 14:40:35 -0700 Subject: [PATCH] Load debug log dialog immediately, then populate log data (#1540) An immediate response to the user request to see the log, and then we show the real data as soon as we've loaded it from disk. Changes: - the IPC exchange to get the log data is now async - the API to fetch the log on the client side now returns a Promise - in the main process, the only disk access done synchronoously is reading the contents of the log directory. The JSON parsing of the resultant log data is now split up into three chunks. - We only send three keys from each log item to the renderer process: msg, time, level. Previously we sent the entire log entry with extra keys: hostname, pid, name. FREEBIE --- app/logging.js | 45 ++++++++++++++++++++++++++------------ js/logging.js | 9 +++++++- js/views/debug_log_view.js | 6 ++++- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/app/logging.js b/app/logging.js index b4fb40581..a7966d257 100644 --- a/app/logging.js +++ b/app/logging.js @@ -51,7 +51,11 @@ function initialize() { }); ipc.on('fetch-log', function(event) { - event.returnValue = fetch(logPath); + fetch(logPath).then(function(data) { + event.sender.send('fetched-log', data); + }, function(error) { + logger.error('Problem loading log from disk: ' + error.stack); + }); }); } @@ -63,23 +67,36 @@ function getLogger() { return logger; } -function fetch(logPath) { - const files = fs.readdirSync(logPath); - let contents = ''; +function fetchLog(logFile) { + return new Promise(function(resolve, reject) { + fs.readFile(logFile, { encoding: 'utf8' }, function(err, text) { + if (err) { + return reject(err); + } + + const lines = _.compact(text.split('\n')); + const data = _.compact(lines.map(function(line) { + try { + return _.pick(JSON.parse(line), ['level', 'time', 'msg']); + } + catch (e) {} + })); - files.forEach(function(file) { - contents += fs.readFileSync(path.join(logPath, file), { encoding: 'utf8' }); + return resolve(data); + }); }); +} - const lines = _.compact(contents.split('\n')); - const data = _.compact(lines.map(function(line) { - try { - return JSON.parse(line); - } - catch (e) {} - })); +function fetch(logPath) { + const files = fs.readdirSync(logPath); + const paths = files.map(function(file) { + return path.join(logPath, file) + }); - return _.sortBy(data, 'time'); + return Promise.all(paths.map(fetchLog)).then(function(results) { + const data = _.flatten(results); + return _.sortBy(data, 'time'); + }); } diff --git a/js/logging.js b/js/logging.js index 2253e532c..f7a687fe0 100644 --- a/js/logging.js +++ b/js/logging.js @@ -90,7 +90,14 @@ function format(entries) { } function fetch() { - return getHeader() + '\n' + format(ipc.sendSync('fetch-log')); + return new Promise(function(resolve) { + ipc.send('fetch-log'); + + ipc.on('fetched-log', function(event, text) { + var result = getHeader() + '\n' + format(text); + resolve(result); + }); + }); } function publish(log) { diff --git a/js/views/debug_log_view.js b/js/views/debug_log_view.js index 628ddc96c..357e2bf5e 100644 --- a/js/views/debug_log_view.js +++ b/js/views/debug_log_view.js @@ -22,7 +22,11 @@ className: 'debug-log modal', initialize: function() { this.render(); - this.$('textarea').val(log.fetch()); + this.$('textarea').val(i18n('loading')); + + window.log.fetch().then(function(text) { + this.$('textarea').val(text); + }.bind(this)); }, events: { 'click .submit': 'submit',