Chromium Code Reviews| Index: ui/file_manager/file_manager/common/js/importer_common.js |
| diff --git a/ui/file_manager/file_manager/common/js/importer_common.js b/ui/file_manager/file_manager/common/js/importer_common.js |
| index 6634ad3972dbea9f4da44e46565f62267855368c..4e85dd7192d272e5b54fdf3525aa7ae1d52c614b 100644 |
| --- a/ui/file_manager/file_manager/common/js/importer_common.js |
| +++ b/ui/file_manager/file_manager/common/js/importer_common.js |
| @@ -19,7 +19,8 @@ importer.ScanEvent = { |
| importer.Setting = { |
| HAS_COMPLETED_IMPORT: 'importer-has-completed-import', |
| MACHINE_ID: 'importer-machine-id', |
| - PHOTOS_APP_ENABLED: 'importer-photo-app-enabled' |
| + PHOTOS_APP_ENABLED: 'importer-photo-app-enabled', |
| + LAST_KNOWN_LOG_ID: 'importer-last-known-log-id' |
| }; |
| /** |
| @@ -223,18 +224,19 @@ importer.getMachineId = function() { |
| importer.getHistoryFilename = function() { |
| return importer.getMachineId().then( |
| function(machineId) { |
| - return 'import-history.' + machineId + '.log'; |
| + return 'import-history-' + machineId + '.log'; |
| }); |
| }; |
| /** |
| + * @param {number} logId |
| * @return {!Promise.<string>} Resolves with the filename of this |
| * machines debug log file. |
| */ |
| -importer.getDebugLogFilename = function() { |
| +importer.getDebugLogFilename = function(logId) { |
| return importer.getMachineId().then( |
| function(machineId) { |
| - return 'import-debug.' + machineId + '.log'; |
| + return 'import-debug-' + machineId + '-' + logId + '.log'; |
| }); |
| }; |
| @@ -669,8 +671,18 @@ importer.RuntimeLogger.prototype.error = function(content) { |
| /** @override */ |
| importer.RuntimeLogger.prototype.catcher = function(context) { |
| return function(error) { |
| - this.error('Caught promise error. Context: ' + context + |
| - ' Error: ' + error.message); |
| + var prefix = '(' + context + ')'; |
| + var message = prefix + ' Caught error in promise chain.'; |
| + |
| + if (error) { |
| + this.error(message + ' Error' + error.message); |
| + this.write_('STACK', prefix + ' Trace: ' + error.stack); |
| + } else { |
| + this.error(message); |
| + error = new Error(message); |
| + } |
| + |
| + throw error; |
| }.bind(this); |
| }; |
| @@ -728,14 +740,90 @@ importer.logger_ = null; |
| */ |
| importer.getLogger = function() { |
| if (!importer.logger_) { |
| + var nextLogId = importer.getNextDebugLogId_(); |
| + |
| + /** @return {!Promise} */ |
| + var rotator = function() { |
| + return importer.rotateLogs( |
| + nextLogId, |
| + importer.ChromeSyncFileEntryProvider.getFileEntry); |
| + }; |
| + |
| + // This is a sligtly odd arrangement in service of two goals. |
| + // |
| + // 1) Make a logger available synchronously. |
| + // 2) Nuke old log files before reusing their names. |
| + // |
| + // In support of these goals we push the "rotator" between |
| + // the call to load the file entry and the method that |
| + // produces the name of the file to load. That method |
| + // (getDebugLogFilename) returns promise. We exploit this. |
| importer.logger_ = new importer.RuntimeLogger( |
| importer.ChromeSyncFileEntryProvider.getFileEntry( |
| - importer.getDebugLogFilename())); |
| + /** @type {!Promise<string>} */ (rotator().then( |
| + importer.getDebugLogFilename.bind(null, nextLogId))))); |
| } |
| + |
| return importer.logger_; |
| }; |
| /** |
| + * Returns the log ID for the next debug log to use. |
| + * @private |
| + */ |
| +importer.getNextDebugLogId_ = function() { |
| + return new Date().getMonth() % 2; |
| +}; |
| + |
| +/** |
| + * Deletes the "next" log file if it has just-now become active. |
| + * |
| + * Basically we toggle back and forth writing to two log files. At the time |
| + * we flip from one to another we want to delete the oldest data we have. |
| + * In this case it will be the "next" log. |
| + * |
| + * This function must be run befor instantiating the logger. |
|
fukino
2015/02/23 03:42:26
nit: s/befor/before
Steve McKay
2015/02/23 03:50:18
Done.
|
| + * |
| + * @param {number} nextLogId |
| + * @param {function(!Promise<string>): !Promise<!FileEntry>} fileFactory |
| + * Injected primarily to facilitate testing. |
| + * @return {!Promise} Resolves when trimming is complete. |
| + */ |
| +importer.rotateLogs = function(nextLogId, fileFactory) { |
| + var storage = importer.ChromeLocalStorage.getInstance(); |
| + |
| + /** @return {!Promise} */ |
| + var rememberLogId = function() { |
| + return storage.set( |
| + importer.Setting.LAST_KNOWN_LOG_ID, |
| + nextLogId); |
| + }; |
| + |
| + return storage.get(importer.Setting.LAST_KNOWN_LOG_ID) |
| + .then( |
| + /** @param {number} lastKnownLogId */ |
| + function(lastKnownLogId) { |
| + if (nextLogId === lastKnownLogId || |
| + lastKnownLogId === undefined) { |
| + return Promise.resolve(); |
| + } |
| + |
| + return fileFactory(importer.getDebugLogFilename(nextLogId)) |
| + .then( |
| + /** |
| + * @param {!FileEntry} entry |
| + * @return {!Promise} |
| + * @suppress {checkTypes} |
| + */ |
| + function(entry) { |
| + return new Promise(entry.remove.bind(entry)); |
| + }); |
| + }) |
| + .then(rememberLogId) |
| + .catch(rememberLogId); |
| +}; |
| + |
| +/** |
| * Friendly wrapper around chrome.storage.local. |
| * |
| * NOTE: If you want to use this in a test, install MockChromeStorageAPI. |