Bug 1003204: Removed CommonUtils.exceptionStr() in services/ r=gfritzsche
authorAnup Kumar <allamsetty.anup@gmail.com>
Wed, 06 Jan 2016 17:53:00 +0100
changeset 278959 9433893449d376f76d22faed6cdffe20ee3ab4ac
parent 278958 ec660a46136a6df47ebbcf9274ac35738c550331
child 278960 d818de93b48f531eb13789bed8ca9917771e1c9a
push id29862
push userkwierso@gmail.com
push dateFri, 08 Jan 2016 00:35:36 +0000
treeherdermozilla-central@2c8701e3ee11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgfritzsche
bugs1003204
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1003204: Removed CommonUtils.exceptionStr() in services/ r=gfritzsche
services/datareporting/DataReportingService.js
services/datareporting/policy.jsm
services/healthreport/healthreporter.jsm
services/healthreport/providers.jsm
services/metrics/providermanager.jsm
services/metrics/storage.jsm
--- a/services/datareporting/DataReportingService.js
+++ b/services/datareporting/DataReportingService.js
@@ -4,21 +4,20 @@
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/ClientID.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://services-common/utils.js");
 Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
-
+XPCOMUtils.defineLazyModuleGetter(this, "Log",
+                                  "resource://gre/modules/Log.jsm");
 
 const ROOT_BRANCH = "datareporting.";
 const POLICY_BRANCH = ROOT_BRANCH + "policy.";
 const HEALTHREPORT_BRANCH = ROOT_BRANCH + "healthreport.";
 const HEALTHREPORT_LOGGING_BRANCH = HEALTHREPORT_BRANCH + "logging.";
 const DEFAULT_LOAD_DELAY_MSEC = 10 * 1000;
 const DEFAULT_LOAD_DELAY_FIRST_RUN_MSEC = 60 * 1000;
 
@@ -117,17 +116,17 @@ DataReportingService.prototype = Object.
 
           // We can't interact with prefs until after the profile is present.
           let policyPrefs = new Preferences(POLICY_BRANCH);
           this.policy = new DataReportingPolicy(policyPrefs, this._prefs, this);
 
           this._os.addObserver(this, "sessionstore-windows-restored", true);
         } catch (ex) {
           Cu.reportError("Exception when initializing data reporting service: " +
-                         CommonUtils.exceptionStr(ex));
+                         Log.exceptionStr(ex));
         }
         break;
 
       case "sessionstore-windows-restored":
         this._os.removeObserver(this, "sessionstore-windows-restored");
         this._os.addObserver(this, "quit-application", false);
 
         let policy = this.policy;
@@ -210,64 +209,62 @@ DataReportingService.prototype = Object.
       return this._healthReporter;
     }
 
     try {
       this._loadHealthReporter();
     } catch (ex) {
       this._healthReporter = null;
       Cu.reportError("Exception when obtaining health reporter: " +
-                     CommonUtils.exceptionStr(ex));
+                     Log.exceptionStr(ex));
     }
 
     return this._healthReporter;
   },
 
   _loadHealthReporter: function () {
     // This should never happen. It was added to help trace down bug 924307.
     if (!this.policy) {
       throw new Error("this.policy not set.");
     }
 
     let ns = {};
     // Lazy import so application startup isn't adversely affected.
 
-    Cu.import("resource://gre/modules/Task.jsm", ns);
     Cu.import("resource://gre/modules/HealthReport.jsm", ns);
-    Cu.import("resource://gre/modules/Log.jsm", ns);
 
     // How many times will we rewrite this code before rolling it up into a
     // generic module? See also bug 451283.
     const LOGGERS = [
       "Services.DataReporting",
       "Services.HealthReport",
       "Services.Metrics",
       "Services.BagheeraClient",
       "Sqlite.Connection.healthreport",
     ];
 
     let loggingPrefs = new Preferences(HEALTHREPORT_LOGGING_BRANCH);
     if (loggingPrefs.get("consoleEnabled", true)) {
       let level = loggingPrefs.get("consoleLevel", "Warn");
-      let appender = new ns.Log.ConsoleAppender();
-      appender.level = ns.Log.Level[level] || ns.Log.Level.Warn;
+      let appender = new Log.ConsoleAppender();
+      appender.level = Log.Level[level] || Log.Level.Warn;
 
       for (let name of LOGGERS) {
-        let logger = ns.Log.repository.getLogger(name);
+        let logger = Log.repository.getLogger(name);
         logger.addAppender(appender);
       }
     }
 
     if (loggingPrefs.get("dumpEnabled", false)) {
       let level = loggingPrefs.get("dumpLevel", "Debug");
-      let appender = new ns.Log.DumpAppender();
-      appender.level = ns.Log.Level[level] || ns.Log.Level.Debug;
+      let appender = new Log.DumpAppender();
+      appender.level = Log.Level[level] || Log.Level.Debug;
 
       for (let name of LOGGERS) {
-        let logger = ns.Log.repository.getLogger(name);
+        let logger = Log.repository.getLogger(name);
         logger.addAppender(appender);
       }
     }
 
     this._healthReporter = new ns.HealthReporter(HEALTHREPORT_BRANCH, this.policy);
 
     // Wait for initialization to finish so if a shutdown occurs before init
     // has finished we don't adversely affect app startup on next run.
--- a/services/datareporting/policy.jsm
+++ b/services/datareporting/policy.jsm
@@ -738,28 +738,26 @@ this.DataReportingPolicy.prototype = Obj
       return false;
     }
 
     let deferred = Promise.defer();
     deferred.promise.then((function onSuccess() {
       this._recordDataPolicyNotification(this.now(), this.currentPolicyVersion);
       this._userNotifyPromise = null;
     }).bind(this), ((error) => {
-      this._log.warn("Data policy notification presentation failed: " +
-                     CommonUtils.exceptionStr(error));
+      this._log.warn("Data policy notification presentation failed", error);
       this._userNotifyPromise = null;
     }).bind(this));
 
     this._log.info("Requesting display of data policy.");
     let request = new NotifyPolicyRequest(this, deferred);
     try {
       this._listener.onNotifyDataPolicy(request);
     } catch (ex) {
-      this._log.warn("Exception when calling onNotifyDataPolicy: " +
-                     CommonUtils.exceptionStr(ex));
+      this._log.warn("Exception when calling onNotifyDataPolicy", ex);
     }
 
     this._userNotifyPromise = deferred.promise;
 
     return false;
   },
 
   _recordDataPolicyNotification: function (date, version) {
@@ -811,32 +809,30 @@ this.DataReportingPolicy.prototype = Obj
                                                                   isDelete);
 
     let onSuccess = function onSuccess(result) {
       this._inProgressSubmissionRequest = null;
       this._handleSubmissionResult(result);
     }.bind(this);
 
     let onError = function onError(error) {
-      this._log.error("Error when handling data submission result: " +
-                      CommonUtils.exceptionStr(error));
+      this._log.error("Error when handling data submission result", error);
       this._inProgressSubmissionRequest = null;
       this._handleSubmissionFailure();
     }.bind(this);
 
     let chained = deferred.promise.then(onSuccess, onError);
 
     this._log.info("Requesting data submission. Will expire at " +
                    requestExpiresDate);
     try {
       let promise = this._listener[handler](this._inProgressSubmissionRequest);
       chained = chained.then(() => promise, null);
     } catch (ex) {
-      this._log.warn("Exception when calling " + handler + ": " +
-                     CommonUtils.exceptionStr(ex));
+      this._log.warn("Exception when calling " + handler, ex);
       this._inProgressSubmissionRequest = null;
       this._handleSubmissionFailure();
       return;
     }
 
     return chained;
   },
 
--- a/services/healthreport/healthreporter.jsm
+++ b/services/healthreport/healthreporter.jsm
@@ -158,18 +158,17 @@ HealthReporterState.prototype = Object.f
 
       try {
         this._s = yield CommonUtils.readJSON(this._filename);
       } catch (ex if ex instanceof OS.File.Error &&
                ex.becauseNoSuchFile) {
         this._log.warn("Saved state file does not exist.");
         resetObjectState();
       } catch (ex) {
-        this._log.error("Exception when reading state from disk: " +
-                        CommonUtils.exceptionStr(ex));
+        this._log.error("Exception when reading state from disk", ex);
         resetObjectState();
 
         // Don't save in case it goes away on next run.
       }
 
       if (typeof(this._s) != "object") {
         this._log.warn("Read state is not an object. Resetting state.");
         resetObjectState();
@@ -367,18 +366,17 @@ AbstractHealthReporter.prototype = Objec
         if (!this._state._s.removedOutdatedLastpayload) {
           yield this._deleteOldLastPayload();
           this._state._s.removedOutdatedLastpayload = true;
           // Normally we should save this to a file but it directly conflicts with
           // the "application re-upgrade" decision in HealthReporterState::init()
           // which specifically does not save the state to a file.
         }
       } catch (ex) {
-        this._log.error("Error deleting last payload: " +
-                        CommonUtils.exceptionStr(ex));
+        this._log.error("Error deleting last payload", ex);
       }
 
       // As soon as we have could have storage, we need to register cleanup or
       // else bad things happen on shutdown.
       Services.obs.addObserver(this, "quit-application", false);
 
       // The database needs to be shut down by the end of shutdown
       // phase profileBeforeChange.
@@ -465,18 +463,17 @@ AbstractHealthReporter.prototype = Objec
   _deleteOldLastPayload: function () {
     let paths = [this._state._lastPayloadPath, this._state._lastPayloadPath + ".tmp"];
     return Task.spawn(function removeAllFiles () {
       for (let path of paths) {
         try {
           OS.File.remove(path);
         } catch (ex) {
           if (!ex.becauseNoSuchFile) {
-            this._log.error("Exception when removing outdated payload files: " +
-                            CommonUtils.exceptionStr(ex));
+            this._log.error("Exception when removing outdated payload files", ex);
           }
         }
       }
     }.bind(this));
   },
 
   _initializeProviderManager: Task.async(function* _initializeProviderManager() {
     if (this._collector) {
@@ -533,18 +530,17 @@ AbstractHealthReporter.prototype = Objec
       // the timer ID.
       try {
         let timerName = this._branch.replace(/\./g, "-") + "lastDailyCollection";
         let tm = Cc["@mozilla.org/updates/timer-manager;1"]
                    .getService(Ci.nsIUpdateTimerManager);
         tm.registerTimer(timerName, this.collectMeasurements.bind(this),
                          24 * 60 * 60);
       } catch (ex) {
-        this._log.error("Error registering collection timer: " +
-                        CommonUtils.exceptionStr(ex));
+        this._log.error("Error registering collection timer", ex);
       }
     }
 
     // Clean up caches and reduce memory usage.
     this._storage.compact();
   },
 
   // nsIObserver to handle shutdown.
@@ -610,33 +606,31 @@ AbstractHealthReporter.prototype = Objec
         if (this._providerManager) {
           this._log.info("Shutting down provider manager.");
           for (let provider of this._providerManager.providers) {
             try {
               this._log.info("Shutting down provider: " + provider.name);
               this._currentProviderInShutdown = provider.name;
               yield provider.shutdown();
             } catch (ex) {
-              this._log.warn("Error when shutting down provider: " +
-                             CommonUtils.exceptionStr(ex));
+              this._log.warn("Error when shutting down provider", ex);
             }
           }
           this._log.info("Provider manager shut down.");
           this._providerManager = null;
           this._currentProviderInShutdown = null;
           this._onProviderManagerShutdown();
         }
         if (this._storage) {
           this._log.info("Shutting down storage.");
           try {
             yield this._storage.close();
             yield this._onStorageClose();
           } catch (error) {
-            this._log.warn("Error when closing storage: " +
-                           CommonUtils.exceptionStr(error));
+            this._log.warn("Error when closing storage", error);
           }
           this._storage = null;
         }
 
         this._log.warn("Shutdown complete.");
         this._shutdownComplete = true;
       } finally {
         this._deferredShutdown.resolve();
@@ -727,18 +721,18 @@ AbstractHealthReporter.prototype = Objec
    * @param ex
    *        (Error) The error that should be captured.
    */
   _recordError: function (message, ex) {
     let recordMessage = message;
     let logMessage = message;
 
     if (ex) {
-      recordMessage += ": " + CommonUtils.exceptionStr(ex);
-      logMessage += ": " + CommonUtils.exceptionStr(ex);
+      recordMessage += ": " + Log.exceptionStr(ex);
+      logMessage += ": " + Log.exceptionStr(ex);
     }
 
     // Scrub out potentially identifying information from strings that could
     // make the payload.
     let appData = Services.dirsvc.get("UAppData", Ci.nsIFile);
     let profile = Services.dirsvc.get("ProfD", Ci.nsIFile);
 
     let appDataURI = Services.io.newFileURI(appData);
@@ -788,18 +782,17 @@ AbstractHealthReporter.prototype = Objec
 
       try {
         TelemetryStopwatch.start(TELEMETRY_COLLECT_CONSTANT, this);
         yield this._providerManager.collectConstantData(name => this._currentProviderInCollect = name);
         this._currentProviderInCollect = null;
         TelemetryStopwatch.finish(TELEMETRY_COLLECT_CONSTANT, this);
       } catch (ex) {
         TelemetryStopwatch.cancel(TELEMETRY_COLLECT_CONSTANT, this);
-        this._log.warn("Error collecting constant data: " +
-                       CommonUtils.exceptionStr(ex));
+        this._log.warn("Error collecting constant data", ex);
       }
 
       // Daily data is collected if it hasn't yet been collected this
       // application session or if it has been more than a day since the
       // last collection. This means that providers could see many calls to
       // collectDailyData per calendar day. However, this collection API
       // makes no guarantees about limits. The alternative would involve
       // recording state. The simpler implementation prevails for now.
@@ -809,18 +802,17 @@ AbstractHealthReporter.prototype = Objec
         try {
           TelemetryStopwatch.start(TELEMETRY_COLLECT_DAILY, this);
           this._lastDailyDate = new Date();
           yield this._providerManager.collectDailyData(name => this._currentProviderInCollect = name);
           this._currentProviderInCollect = null;
           TelemetryStopwatch.finish(TELEMETRY_COLLECT_DAILY, this);
         } catch (ex) {
           TelemetryStopwatch.cancel(TELEMETRY_COLLECT_DAILY, this);
-          this._log.warn("Error collecting daily data from providers: " +
-                         CommonUtils.exceptionStr(ex));
+          this._log.warn("Error collecting daily data from providers", ex);
         }
       }
 
       yield this._providerManager.ensurePullOnlyProvidersUnregistered();
 
       // Flush gathered data to disk. This will incur an fsync. But, if
       // there is ever a time we want to persist data to disk, it's
       // after a massive collection.
@@ -1093,25 +1085,23 @@ AbstractHealthReporter.prototype = Objec
   obtainAppInfo: function () {
     let out = {"_v": this.appInfoVersion};
     try {
       let ai = Services.appinfo;
       for (let [k, v] in Iterator(this.appInfoFields)) {
         out[k] = ai[v];
       }
     } catch (ex) {
-      this._log.warn("Could not obtain Services.appinfo: " +
-                     CommonUtils.exceptionStr(ex));
+      this._log.warn("Could not obtain Services.appinfo", ex);
     }
 
     try {
       out["updateChannel"] = UpdateUtils.UpdateChannel;
     } catch (ex) {
-      this._log.warn("Could not obtain update channel: " +
-                     CommonUtils.exceptionStr(ex));
+      this._log.warn("Could not obtain update channel", ex);
     }
 
     return out;
   },
 });
 
 /**
  * HealthReporter and its abstract superclass coordinate collection and
@@ -1317,18 +1307,17 @@ this.HealthReporter.prototype = Object.f
     // Need to capture this before we call the parent else it's always
     // set.
     let inShutdown = this._shutdownRequested;
     let result;
 
     try {
       result = AbstractHealthReporter.prototype._onInitError.call(this, error);
     } catch (ex) {
-      this._log.error("Error when calling _onInitError: " +
-                      CommonUtils.exceptionStr(ex));
+      this._log.error("Error when calling _onInitError", ex);
     }
 
     // This bypasses a lot of the checks in policy, such as respect for
     // backoff. We should arguably not do this. However, reporting
     // startup errors is important. And, they should not occur with much
     // frequency in the wild. So, it shouldn't be too big of a deal.
     if (!inShutdown &&
         this._policy.healthReportUploadEnabled &&
@@ -1357,45 +1346,42 @@ this.HealthReporter.prototype = Object.f
 
       if (!result.transportSuccess) {
         // The built-in provider may not be initialized if this instance failed
         // to initialize fully.
         if (hrProvider && !isDelete) {
           try {
             hrProvider.recordEvent("uploadTransportFailure", date);
           } catch (ex) {
-            this._log.error("Error recording upload transport failure: " +
-                            CommonUtils.exceptionStr(ex));
+            this._log.error("Error recording upload transport failure", ex);
           }
         }
 
         request.onSubmissionFailureSoft("Network transport error.");
         throw new Task.Result(false);
       }
 
       if (!result.serverSuccess) {
         if (hrProvider && !isDelete) {
           try {
             hrProvider.recordEvent("uploadServerFailure", date);
           } catch (ex) {
-            this._log.error("Error recording server failure: " +
-                            CommonUtils.exceptionStr(ex));
+            this._log.error("Error recording server failure", ex);
           }
         }
 
         request.onSubmissionFailureHard("Server failure.");
         throw new Task.Result(false);
       }
 
       if (hrProvider && !isDelete) {
         try {
           hrProvider.recordEvent("uploadSuccess", date);
         } catch (ex) {
-          this._log.error("Error recording upload success: " +
-                          CommonUtils.exceptionStr(ex));
+          this._log.error("Error recording upload success", ex);
         }
       }
 
       if (isDelete) {
         this._log.warn("Marking delete as successful.");
         yield this._state.removeRemoteIDs([result.id]);
       } else {
         this._log.warn("Marking upload as successful.");
@@ -1404,18 +1390,17 @@ this.HealthReporter.prototype = Object.f
 
       request.onSubmissionSuccess(this._now());
 
       throw new Task.Result(true);
     }.bind(this));
   },
 
   _onSubmitDataRequestFailure: function (error) {
-    this._log.error("Error processing request to submit data: " +
-                    CommonUtils.exceptionStr(error));
+    this._log.error("Error processing request to submit data", error);
   },
 
   _formatDate: function (date) {
     // Why, oh, why doesn't JS have a strftime() equivalent?
     return date.toISOString().substr(0, 10);
   },
 
   _uploadData: function (request) {
@@ -1454,18 +1439,17 @@ this.HealthReporter.prototype = Object.f
 
         let hrProvider = this.getProvider("org.mozilla.healthreport");
         if (hrProvider) {
           let event = lastID ? "continuationUploadAttempt"
                              : "firstDocumentUploadAttempt";
           try {
             hrProvider.recordEvent(event, now);
           } catch (ex) {
-            this._log.error("Error when recording upload attempt: " +
-                            CommonUtils.exceptionStr(ex));
+            this._log.error("Error when recording upload attempt", ex);
           }
         }
 
         TelemetryStopwatch.start(TELEMETRY_UPLOAD, this);
         let result;
         try {
           let options = {
             deleteIDs: this._state.remoteIDs.filter((x) => { return x != id; }),
@@ -1475,18 +1459,17 @@ this.HealthReporter.prototype = Object.f
                                            options);
           TelemetryStopwatch.finish(TELEMETRY_UPLOAD, this);
         } catch (ex) {
           TelemetryStopwatch.cancel(TELEMETRY_UPLOAD, this);
           if (hrProvider) {
             try {
               hrProvider.recordEvent("uploadClientFailure", now);
             } catch (ex) {
-              this._log.error("Error when recording client failure: " +
-                              CommonUtils.exceptionStr(ex));
+              this._log.error("Error when recording client failure", ex);
             }
           }
           throw ex;
         }
 
         yield this._onBagheeraResult(request, false, now, result);
       } finally {
         this._uploadInProgress = false;
@@ -1511,15 +1494,14 @@ this.HealthReporter.prototype = Object.f
     let client = new BagheeraClient(this.serverURI);
 
     return Task.spawn(function* doDelete() {
       try {
         let result = yield client.deleteDocument(this.serverNamespace,
                                                  this.lastSubmitID);
         yield this._onBagheeraResult(request, true, this._now(), result);
       } catch (ex) {
-        this._log.error("Error processing request to delete data: " +
-                        CommonUtils.exceptionStr(error));
+        this._log.error("Error processing request to delete data", ex);
       }
     }.bind(this));
   },
 });
 
--- a/services/healthreport/providers.jsm
+++ b/services/healthreport/providers.jsm
@@ -226,18 +226,17 @@ AppInfoProvider.prototype = Object.freez
     }.bind(this);
 
     // Services.appInfo should always be defined for any reasonably behaving
     // Gecko app. If it isn't, we insert a empty string sentinel value.
     let ai;
     try {
       ai = Services.appinfo;
     } catch (ex) {
-      this._log.error("Could not obtain Services.appinfo: " +
-                     CommonUtils.exceptionStr(ex));
+      this._log.error("Could not obtain Services.appinfo", ex);
       yield recordEmptyAppInfo();
       return;
     }
 
     if (!ai) {
       this._log.error("Services.appinfo is unavailable.");
       yield recordEmptyAppInfo();
       return;
@@ -309,18 +308,17 @@ AppInfoProvider.prototype = Object.freez
   _populateConstants: function () {
     let m = this.getMeasurement(AppInfoMeasurement.prototype.name,
                                 AppInfoMeasurement.prototype.version);
 
     let ai;
     try {
       ai = Services.appinfo;
     } catch (ex) {
-      this._log.warn("Could not obtain Services.appinfo: " +
-                     CommonUtils.exceptionStr(ex));
+      this._log.warn("Could not obtain Services.appinfo", ex);
       throw ex;
     }
 
     if (!ai) {
       this._log.warn("Services.appinfo is unavailable.");
       throw ex;
     }
 
@@ -330,32 +328,30 @@ AppInfoProvider.prototype = Object.freez
       } catch (ex) {
         this._log.warn("Error obtaining Services.appinfo." + v);
       }
     }
 
     try {
       yield m.setLastText("updateChannel", UpdateUtils.UpdateChannel);
     } catch (ex) {
-      this._log.warn("Could not obtain update channel: " +
-                     CommonUtils.exceptionStr(ex));
+      this._log.warn("Could not obtain update channel", ex);
     }
 
     yield m.setLastText("distributionID", this._prefs.get("distribution.id", ""));
     yield m.setLastText("distributionVersion", this._prefs.get("distribution.version", ""));
     yield m.setLastText("hotfixVersion", this._prefs.get("extensions.hotfix.lastVersion", ""));
 
     try {
       let locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
                      .getService(Ci.nsIXULChromeRegistry)
                      .getSelectedLocale("global");
       yield m.setLastText("locale", locale);
     } catch (ex) {
-      this._log.warn("Could not obtain application locale: " +
-                     CommonUtils.exceptionStr(ex));
+      this._log.warn("Could not obtain application locale", ex);
     }
 
     // FUTURE this should be retrieved periodically or at upload time.
     yield this._recordIsTelemetryEnabled(m);
     yield this._recordIsBlocklistEnabled(m);
     yield this._recordDefaultBrowser(m);
   },
 
@@ -372,29 +368,27 @@ AppInfoProvider.prototype = Object.freez
   },
 
   _recordDefaultBrowser: function (m) {
     let shellService;
     try {
       shellService = Cc["@mozilla.org/browser/shell-service;1"]
                        .getService(Ci.nsIShellService);
     } catch (ex) {
-      this._log.warn("Could not obtain shell service: " +
-                     CommonUtils.exceptionStr(ex));
+      this._log.warn("Could not obtain shell service", ex);
     }
 
     let isDefault = -1;
 
     if (shellService) {
       try {
         // This uses the same set of flags used by the pref pane.
         isDefault = shellService.isDefaultBrowser(false, true) ? 1 : 0;
       } catch (ex) {
-        this._log.warn("Could not determine if default browser: " +
-                       CommonUtils.exceptionStr(ex));
+        this._log.warn("Could not determine if default browser", ex);
       }
     }
 
     return m.setDailyLastNumeric("isDefaultBrowser", isDefault);
   },
 
   collectDailyData: function () {
     return this.storage.enqueueTransaction(function getDaily() {
@@ -501,18 +495,17 @@ SysInfoProvider.prototype = Object.freez
             // above ensures undefined or null doesn't creep in here.
             value = value ? 1 : 0;
             method = "setLastNumeric";
             break;
         }
 
         yield m[method](v, value);
       } catch (ex) {
-        this._log.warn("Error obtaining system info field: " + k + " " +
-                       CommonUtils.exceptionStr(ex));
+        this._log.warn("Error obtaining system info field: " + k, ex);
       }
     }
   },
 });
 
 
 /**
  * Holds information about the current/active session.
@@ -903,18 +896,17 @@ AddonsProvider.prototype = Object.freeze
       let pluginsField;
       let gmPluginsField;
       try {
         data = this._createDataStructure(allAddons);
         addonsField = JSON.stringify(data.addons);
         pluginsField = JSON.stringify(data.plugins);
         gmPluginsField = JSON.stringify(data.gmPlugins);
       } catch (ex) {
-        this._log.warn("Exception when populating add-ons data structure: " +
-                       CommonUtils.exceptionStr(ex));
+        this._log.warn("Exception when populating add-ons data structure", ex);
         deferred.reject(ex);
         return;
       }
 
       let now = new Date();
       let addons = this.getMeasurement("addons", 2);
       let plugins = this.getMeasurement("plugins", 1);
       let gmPlugins = this.getMeasurement("gm-plugins", 1);
--- a/services/metrics/providermanager.jsm
+++ b/services/metrics/providermanager.jsm
@@ -272,18 +272,17 @@ this.ProviderManager.prototype = Object.
       Task.spawn(function registerPullProviders() {
 
       if (inFlightPromise) {
         this._log.debug("Waiting for in-flight pull-only provider activity " +
                         "to finish before registering.");
         try {
           yield inFlightPromise;
         } catch (ex) {
-          this._log.warn("Error when waiting for existing pull-only promise: " +
-                         CommonUtils.exceptionStr(ex));
+          this._log.warn("Error when waiting for existing pull-only promise", ex);
         }
       }
 
       for (let name in this._pullOnlyProviders) {
         let providerType = this._pullOnlyProviders[name];
         // Short-circuit if we're no longer registering.
         if (this._pullOnlyProvidersState != this.PULL_ONLY_REGISTERING) {
           this._log.debug("Aborting pull-only provider registration.");
@@ -358,18 +357,17 @@ this.ProviderManager.prototype = Object.
       Task.spawn(function unregisterPullProviders() {
 
       if (inFlightPromise) {
         this._log.debug("Waiting for in-flight pull-only provider activity " +
                         "to complete before unregistering.");
         try {
           yield inFlightPromise;
         } catch (ex) {
-          this._log.warn("Error when waiting for existing pull-only promise: " +
-                         CommonUtils.exceptionStr(ex));
+          this._log.warn("Error when waiting for existing pull-only promise", ex);
         }
       }
 
       for (let provider of this.providers) {
         if (this._pullOnlyProvidersState != this.PULL_ONLY_UNREGISTERING) {
           return;
         }
 
@@ -492,18 +490,17 @@ this.ProviderManager.prototype = Object.
         continue;
       }
 
       let promise = collectPromise.then(function onCollected(result) {
         if (onCollect) {
           try {
             onCollect(entry, result);
           } catch (ex) {
-            this._log.warn("onCollect callback threw: " +
-                           CommonUtils.exceptionStr(ex));
+            this._log.warn("onCollect callback threw", ex);
           }
         }
 
         return CommonUtils.laterTickResolvingPromise(result);
       });
 
       promises.push([provider.name, promise]);
     }
@@ -540,23 +537,22 @@ this.ProviderManager.prototype = Object.
   },
 
   /**
    * Record an error that occurred operating on a provider.
    */
   _recordProviderError: function (name, msg, ex) {
     msg = "Provider error: " + name + ": " + msg;
     if (ex) {
-      msg += ": " + CommonUtils.exceptionStr(ex);
+      msg += ": " + Log.exceptionStr(ex);
     }
     this._log.warn(msg);
 
     if (this.onProviderError) {
       try {
         this.onProviderError(msg);
       } catch (callError) {
-        this._log.warn("Exception when calling onProviderError callback: " +
-                       CommonUtils.exceptionStr(callError));
+        this._log.warn("Exception when calling onProviderError callback", callError);
       }
     }
   },
 });
 
--- a/services/metrics/storage.jsm
+++ b/services/metrics/storage.jsm
@@ -21,17 +21,16 @@ const MILLISECONDS_PER_DAY = 24 * 60 * 6
 
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Sqlite.jsm");
 Cu.import("resource://gre/modules/AsyncShutdown.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://services-common/utils.js");
 
-
 // These do not account for leap seconds. Meh.
 function dateToDays(date) {
   return Math.floor(date.getTime() / MILLISECONDS_PER_DAY);
 }
 
 function daysToDate(days) {
   return new Date(days * MILLISECONDS_PER_DAY);
 }
@@ -1423,18 +1422,17 @@ MetricsStorageSqliteBackend.prototype = 
     this._log.trace("Performing queued operation.");
     let [func, deferred] = this._queuedOperations.shift();
     let promise;
 
     try {
       this._queuedInProgress = true;
       promise = func();
     } catch (ex) {
-      this._log.warn("Queued operation threw during execution: " +
-                     CommonUtils.exceptionStr(ex));
+      this._log.warn("Queued operation threw during execution", ex);
       this._queuedInProgress = false;
       deferred.reject(ex);
       this._popAndPerformQueuedOperation();
       return;
     }
 
     if (!promise || typeof(promise.then) != "function") {
       let msg = "Queued operation did not return a promise: " + func;
@@ -1449,18 +1447,17 @@ MetricsStorageSqliteBackend.prototype = 
     promise.then(
       function onSuccess(result) {
         this._log.trace("Queued operation completed.");
         this._queuedInProgress = false;
         deferred.resolve(result);
         this._popAndPerformQueuedOperation();
       }.bind(this),
       function onError(error) {
-        this._log.warn("Failure when performing queued operation: " +
-                       CommonUtils.exceptionStr(error));
+        this._log.warn("Failure when performing queued operation", error);
         this._queuedInProgress = false;
         deferred.reject(error);
         this._popAndPerformQueuedOperation();
       }.bind(this)
     );
   },
 
   /**