Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(325)

Side by Side Diff: ui/file_manager/file_manager/common/js/importer_common.js

Issue 964643002: Report Promise error-context strings to GA. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2311
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Shared cloud importer namespace 5 // Shared cloud importer namespace
6 var importer = importer || {}; 6 var importer = importer || {};
7 7
8 /** @enum {string} */ 8 /** @enum {string} */
9 importer.ScanEvent = { 9 importer.ScanEvent = {
10 FINALIZED: 'finalized', 10 FINALIZED: 'finalized',
11 INVALIDATED: 'invalidated', 11 INVALIDATED: 'invalidated',
12 UPDATED: 'updated' 12 UPDATED: 'updated'
13 }; 13 };
14 14
15 /** 15 /**
16 * Storage keys for settings saved by importer. 16 * Storage keys for settings saved by importer.
17 * @enum {string} 17 * @enum {string}
18 */ 18 */
19 importer.Setting = { 19 importer.Setting = {
20 HAS_COMPLETED_IMPORT: 'importer-has-completed-import', 20 HAS_COMPLETED_IMPORT: 'importer-has-completed-import',
21 MACHINE_ID: 'importer-machine-id', 21 MACHINE_ID: 'importer-machine-id',
22 PHOTOS_APP_ENABLED: 'importer-photo-app-enabled' 22 PHOTOS_APP_ENABLED: 'importer-photo-app-enabled',
23 LAST_KNOWN_LOG_ID: 'importer-last-known-log-id'
23 }; 24 };
24 25
25 /** 26 /**
26 * @typedef {function( 27 * @typedef {function(
27 * !importer.ScanEvent, importer.ScanResult)} 28 * !importer.ScanEvent, importer.ScanResult)}
28 */ 29 */
29 importer.ScanObserver; 30 importer.ScanObserver;
30 31
31 /** 32 /**
32 * Volume types eligible for the affections of Cloud Import. 33 * Volume types eligible for the affections of Cloud Import.
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 }); 217 });
217 }; 218 };
218 219
219 /** 220 /**
220 * @return {!Promise.<string>} Resolves with the filename of this 221 * @return {!Promise.<string>} Resolves with the filename of this
221 * machines history file. 222 * machines history file.
222 */ 223 */
223 importer.getHistoryFilename = function() { 224 importer.getHistoryFilename = function() {
224 return importer.getMachineId().then( 225 return importer.getMachineId().then(
225 function(machineId) { 226 function(machineId) {
226 return 'import-history.' + machineId + '.log'; 227 return machineId + '-import-history.log';
227 }); 228 });
228 }; 229 };
229 230
230 /** 231 /**
232 * @param {number} logId
231 * @return {!Promise.<string>} Resolves with the filename of this 233 * @return {!Promise.<string>} Resolves with the filename of this
232 * machines debug log file. 234 * machines debug log file.
233 */ 235 */
234 importer.getDebugLogFilename = function() { 236 importer.getDebugLogFilename = function(logId) {
235 return importer.getMachineId().then( 237 return importer.getMachineId().then(
236 function(machineId) { 238 function(machineId) {
237 return 'import-debug.' + machineId + '.log'; 239 return machineId + '-import-debug-' + logId + '.log';
238 }); 240 });
239 }; 241 };
240 242
241 /** 243 /**
242 * @return {number} A relatively unique six digit integer that is most likely 244 * @return {number} A relatively unique six digit integer that is most likely
243 * unique to this machine among a user's machines. Used only to segregate 245 * unique to this machine among a user's machines. Used only to segregate
244 * log files on sync storage. 246 * log files on sync storage.
245 */ 247 */
246 importer.generateMachineId_ = function() { 248 importer.generateMachineId_ = function() {
247 return Math.floor(Math.random() * 899999) + 100000; 249 return Math.floor(Math.random() * 899999) + 100000;
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 638
637 /** 639 /**
638 * A {@code importer.Logger} that persists data in a {@code FileEntry}. 640 * A {@code importer.Logger} that persists data in a {@code FileEntry}.
639 * 641 *
640 * @constructor 642 * @constructor
641 * @implements {importer.Logger} 643 * @implements {importer.Logger}
642 * @struct 644 * @struct
643 * @final 645 * @final
644 * 646 *
645 * @param {!Promise.<!FileEntry>} fileEntryPromise 647 * @param {!Promise.<!FileEntry>} fileEntryPromise
648 * @param {!Promise.<!analytics.Tracker>} trackerPromise
646 */ 649 */
647 importer.RuntimeLogger = function(fileEntryPromise) { 650 importer.RuntimeLogger = function(fileEntryPromise, trackerPromise) {
648 651
649 /** @private {!Promise.<!importer.PromisingFileEntry>} */ 652 /** @private {!Promise.<!importer.PromisingFileEntry>} */
650 this.fileEntryPromise_ = fileEntryPromise.then( 653 this.fileEntryPromise_ = fileEntryPromise.then(
651 /** @param {!FileEntry} fileEntry */ 654 /** @param {!FileEntry} fileEntry */
652 function(fileEntry) { 655 function(fileEntry) {
653 return new importer.PromisingFileEntry(fileEntry); 656 return new importer.PromisingFileEntry(fileEntry);
654 }); 657 });
658
659 /** @private {!Promise.<!analytics.Tracker>} */
660 this.trackerPromise_ = trackerPromise;
661 };
662
663 /**
664 * Reports an error to analytics.
665 *
666 * @param {string} context MUST NOT contain any dynamic error content,
667 * only statically defined string will dooooo.
668 */
669 importer.RuntimeLogger.prototype.reportErrorContext_ = function(context) {
670 this.trackerPromise_.then(
671 /** @param {!analytics.Tracker} tracker */
672 function(tracker) {
673 tracker.sendException(
674 context,
675 false /* fatal */ );
676 });
655 }; 677 };
656 678
657 /** @override */ 679 /** @override */
658 importer.RuntimeLogger.prototype.info = function(content) { 680 importer.RuntimeLogger.prototype.info = function(content) {
659 this.write_('INFO', content); 681 this.write_('INFO', content);
660 console.log(content); 682 console.log(content);
661 }; 683 };
662 684
663 /** @override */ 685 /** @override */
664 importer.RuntimeLogger.prototype.error = function(content) { 686 importer.RuntimeLogger.prototype.error = function(content) {
665 this.write_('ERROR', content); 687 this.write_('ERROR', content);
666 console.error(content); 688 console.error(content);
667 }; 689 };
668 690
669 /** @override */ 691 /** @override */
670 importer.RuntimeLogger.prototype.catcher = function(context) { 692 importer.RuntimeLogger.prototype.catcher = function(context) {
693 var prefix = '(' + context + ') ';
671 return function(error) { 694 return function(error) {
672 this.error('Caught promise error. Context: ' + context + 695 this.reportErrorContext_(context);
673 ' Error: ' + error.message); 696
697 var message = prefix + 'Caught error in promise chain.';
698 if (error) {
699 // Error can be anything...maybe an Error, maybe a string.
700 var error = error.message || error;
701 this.error(message + ' Error: ' + error);
702 if (error.stack) {
703 this.write_('STACK', prefix + error.stack);
704 }
705 } else {
706 this.error(message);
707 error = new Error(message);
708 }
709
710 throw error;
674 }.bind(this); 711 }.bind(this);
675 }; 712 };
676 713
677 /** 714 /**
678 * Writes a message to the logger followed by a new line. 715 * Writes a message to the logger followed by a new line.
679 * 716 *
680 * @param {string} type 717 * @param {string} type
681 * @param {string} message 718 * @param {string} message
682 */ 719 */
683 importer.RuntimeLogger.prototype.write_ = function(type, message) { 720 importer.RuntimeLogger.prototype.write_ = function(type, message) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
721 /** @private {importer.Logger} */ 758 /** @private {importer.Logger} */
722 importer.logger_ = null; 759 importer.logger_ = null;
723 760
724 /** 761 /**
725 * Creates a new logger instance...all ready to go. 762 * Creates a new logger instance...all ready to go.
726 * 763 *
727 * @return {!importer.Logger} 764 * @return {!importer.Logger}
728 */ 765 */
729 importer.getLogger = function() { 766 importer.getLogger = function() {
730 if (!importer.logger_) { 767 if (!importer.logger_) {
768 var nextLogId = importer.getNextDebugLogId_();
769
770 /** @return {!Promise} */
771 var rotator = function() {
772 return importer.rotateLogs(
773 nextLogId,
774 importer.ChromeSyncFileEntryProvider.getFileEntry);
775 };
776
777 // This is a sligtly odd arrangement in service of two goals.
778 //
779 // 1) Make a logger available synchronously.
780 // 2) Nuke old log files before reusing their names.
781 //
782 // In support of these goals we push the "rotator" between
783 // the call to load the file entry and the method that
784 // produces the name of the file to load. That method
785 // (getDebugLogFilename) returns promise. We exploit this.
731 importer.logger_ = new importer.RuntimeLogger( 786 importer.logger_ = new importer.RuntimeLogger(
732 importer.ChromeSyncFileEntryProvider.getFileEntry( 787 importer.ChromeSyncFileEntryProvider.getFileEntry(
733 importer.getDebugLogFilename())); 788 /** @type {!Promise.<string>} */ (rotator().then(
789 importer.getDebugLogFilename.bind(null, nextLogId)))),
790 importer.getTracker_());
734 } 791 }
792
735 return importer.logger_; 793 return importer.logger_;
736 }; 794 };
737 795
738 /** 796 /**
797 * Fetch analytics.Tracker from background page.
798 * @return {!Promise.<!analytics.Tracker>}
799 * @private
800 */
801 importer.getTracker_ = function() {
802 return new Promise(
803 function(resolve, reject) {
804 chrome.runtime.getBackgroundPage(
805 /** @param {Window=} opt_background */
806 function(opt_background) {
807 if (chrome.runtime.lastError) {
808 reject(chrome.runtime.lastError);
809 }
810 opt_background.background.ready(
811 function() {
812 resolve(opt_background.background.tracker);
813 });
814 });
815 });
816 };
817
818 /**
819 * Returns the log ID for the next debug log to use.
820 * @private
821 */
822 importer.getNextDebugLogId_ = function() {
823 // Changes every other month.
824 return new Date().getMonth() % 2;
825 };
826
827 /**
828 * Deletes the "next" log file if it has just-now become active.
829 *
830 * Basically we toggle back and forth writing to two log files. At the time
831 * we flip from one to another we want to delete the oldest data we have.
832 * In this case it will be the "next" log.
833 *
834 * This function must be run before instantiating the logger.
835 *
836 * @param {number} nextLogId
837 * @param {function(!Promise<string>): !Promise<!FileEntry>} fileFactory
838 * Injected primarily to facilitate testing.
839 * @return {!Promise} Resolves when trimming is complete.
840 */
841 importer.rotateLogs = function(nextLogId, fileFactory) {
842 var storage = importer.ChromeLocalStorage.getInstance();
843
844 /** @return {!Promise} */
845 var rememberLogId = function() {
846 return storage.set(
847 importer.Setting.LAST_KNOWN_LOG_ID,
848 nextLogId);
849 };
850
851 return storage.get(importer.Setting.LAST_KNOWN_LOG_ID)
852 .then(
853 /** @param {number} lastKnownLogId */
854 function(lastKnownLogId) {
855 if (nextLogId === lastKnownLogId ||
856 lastKnownLogId === undefined) {
857 return Promise.resolve();
858 }
859
860 return fileFactory(importer.getDebugLogFilename(nextLogId))
861 .then(
862 /**
863 * @param {!FileEntry} entry
864 * @return {!Promise}
865 * @suppress {checkTypes}
866 */
867 function(entry) {
868 return new Promise(entry.remove.bind(entry));
869 });
870 })
871 .then(rememberLogId)
872 .catch(rememberLogId);
873 };
874
875 /**
739 * Friendly wrapper around chrome.storage.local. 876 * Friendly wrapper around chrome.storage.local.
740 * 877 *
741 * NOTE: If you want to use this in a test, install MockChromeStorageAPI. 878 * NOTE: If you want to use this in a test, install MockChromeStorageAPI.
742 * 879 *
743 * @constructor 880 * @constructor
744 */ 881 */
745 importer.ChromeLocalStorage = function() {}; 882 importer.ChromeLocalStorage = function() {};
746 883
747 /** 884 /**
748 * @param {string} key 885 * @param {string} key
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
791 }); 928 });
792 }; 929 };
793 930
794 /** @private @const {!importer.ChromeLocalStorage} */ 931 /** @private @const {!importer.ChromeLocalStorage} */
795 importer.ChromeLocalStorage.INSTANCE_ = new importer.ChromeLocalStorage(); 932 importer.ChromeLocalStorage.INSTANCE_ = new importer.ChromeLocalStorage();
796 933
797 /** @return {!importer.ChromeLocalStorage} */ 934 /** @return {!importer.ChromeLocalStorage} */
798 importer.ChromeLocalStorage.getInstance = function() { 935 importer.ChromeLocalStorage.getInstance = function() {
799 return importer.ChromeLocalStorage.INSTANCE_; 936 return importer.ChromeLocalStorage.INSTANCE_;
800 }; 937 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698