Bug 1632303 - Replace SearchUtils.log with console.createInstance. r=daleharvey
authorMark Banner <standard8@mozilla.com>
Thu, 04 Jun 2020 21:47:57 +0000
changeset 534065 0a0feb5361c96fbaefe8db6e821d92409623ea7d
parent 534064 2e5d8bebf8c782ba5919b78fc30bb64f04e4c6c2
child 534066 dd60c4a35ba721d262d696328427e830944ec7e0
push id37482
push usernbeleuzu@mozilla.com
push dateFri, 05 Jun 2020 14:35:19 +0000
treeherdermozilla-central@c835da226e6d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdaleharvey
bugs1632303
milestone79.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 1632303 - Replace SearchUtils.log with console.createInstance. r=daleharvey Differential Revision: https://phabricator.services.mozilla.com/D77649
toolkit/components/search/SearchEngine.jsm
toolkit/components/search/SearchService.jsm
toolkit/components/search/SearchUtils.jsm
--- a/toolkit/components/search/SearchEngine.jsm
+++ b/toolkit/components/search/SearchEngine.jsm
@@ -28,16 +28,23 @@ const BinaryInputStream = Components.Con
 
 XPCOMUtils.defineLazyPreferenceGetter(
   this,
   "gModernConfig",
   SearchUtils.BROWSER_SEARCH_PREF + "modernConfig",
   false
 );
 
+XPCOMUtils.defineLazyGetter(this, "logConsole", () => {
+  return console.createInstance({
+    prefix: "SearchEngine",
+    maxLogLevel: SearchUtils.loggingEnabled ? "Debug" : "Warn",
+  });
+});
+
 const SEARCH_BUNDLE = "chrome://global/locale/search/search.properties";
 const BRAND_BUNDLE = "chrome://branding/locale/brand.properties";
 
 const OPENSEARCH_NS_10 = "http://a9.com/-/spec/opensearch/1.0/";
 const OPENSEARCH_NS_11 = "http://a9.com/-/spec/opensearch/1.1/";
 
 // Although the specification at http://opensearch.a9.com/spec/1.1/description/
 // gives the namespace names defined above, many existing OpenSearch engines
@@ -147,32 +154,32 @@ loadListener.prototype = {
     Ci.nsIStreamListener,
     Ci.nsIChannelEventSink,
     Ci.nsIInterfaceRequestor,
     Ci.nsIProgressEventSink,
   ]),
 
   // nsIRequestObserver
   onStartRequest(request) {
-    SearchUtils.log("loadListener: Starting request: " + request.name);
+    logConsole.debug("loadListener: Starting request:", request.name);
     this._stream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
       Ci.nsIBinaryInputStream
     );
   },
 
   onStopRequest(request, statusCode) {
-    SearchUtils.log("loadListener: Stopping request: " + request.name);
+    logConsole.debug("loadListener: Stopping request:", request.name);
 
     var requestFailed = !Components.isSuccessCode(statusCode);
     if (!requestFailed && request instanceof Ci.nsIHttpChannel) {
       requestFailed = !request.requestSucceeded;
     }
 
     if (requestFailed || this._countRead == 0) {
-      SearchUtils.log("loadListener: request failed!");
+      logConsole.warn("loadListener: request failed!");
       // send null so the callback can deal with the failure
       this._bytes = null;
     }
     this._callback(this._bytes, this._engine);
     this._channel = null;
     this._engine = null;
   },
 
@@ -867,19 +874,19 @@ SearchEngine.prototype = {
   __searchForm: null,
   get _searchForm() {
     return this.__searchForm;
   },
   set _searchForm(value) {
     if (/^https?:/i.test(value)) {
       this.__searchForm = value;
     } else {
-      SearchUtils.log(
-        "_searchForm: Invalid URL dropped for " + this._name ||
-          "the current engine"
+      logConsole.debug(
+        "_searchForm: Invalid URL dropped for",
+        this._name || "the current engine"
       );
     }
   },
   // Whether to obtain user confirmation before adding the engine. This is only
   // used when the engine is first added to the list.
   _confirm: false,
   // Whether to set this as the current engine as soon as it is loaded.  This
   // is only used when the engine is first added to the list.
@@ -935,18 +942,19 @@ SearchEngine.prototype = {
   _initFromURIAndLoad(uri) {
     let loadURI = uri instanceof Ci.nsIURI ? uri : SearchUtils.makeURI(uri);
     ENSURE_WARN(
       loadURI,
       "Must have URI when calling _initFromURIAndLoad!",
       Cr.NS_ERROR_UNEXPECTED
     );
 
-    SearchUtils.log(
-      '_initFromURIAndLoad: Downloading engine from: "' + loadURI.spec + '".'
+    logConsole.debug(
+      "_initFromURIAndLoad: Downloading engine from:",
+      loadURI.spec
     );
 
     var chan = SearchUtils.makeChannel(loadURI);
 
     if (this._engineToUpdate && chan instanceof Ci.nsIHttpChannel) {
       var lastModified = this._engineToUpdate.getAttr("updatelastmodified");
       if (lastModified) {
         chan.setRequestHeader("If-Modified-Since", lastModified, false);
@@ -960,17 +968,17 @@ SearchEngine.prototype = {
 
   /**
    * Retrieves the engine data from a URI asynchronously and initializes it.
    *
    * @param {nsIURI} uri
    *   The uri to load the search plugin from.
    */
   async _initFromURI(uri) {
-    SearchUtils.log('_initFromURI: Loading engine from: "' + uri.spec + '".');
+    logConsole.debug("_initFromURI: Loading engine from:", uri.spec);
     await this._retrieveSearchXMLData(uri.spec);
     // Now that the data is loaded, initialize the engine object
     this._initFromData();
   },
 
   /**
    * Retrieves the engine data for a given URI asynchronously.
    *
@@ -1092,17 +1100,17 @@ SearchEngine.prototype = {
       }
     }
 
     function promptError(strings = {}, error = undefined) {
       onError(error);
 
       if (engine._engineToUpdate) {
         // We're in an update, so just fail quietly
-        SearchUtils.log("updating " + engine._engineToUpdate.name + " failed");
+        logConsole.warn("Failed to update", engine._engineToUpdate.name);
         return;
       }
       var brandBundle = Services.strings.createBundle(BRAND_BUNDLE);
       var brandName = brandBundle.GetStringFromName("brandShortName");
 
       var searchBundle = Services.strings.createBundle(SEARCH_BUNDLE);
       var msgStringName = strings.error || "error_loading_engine_msg2";
       var titleStringName = strings.title || "error_loading_engine_title";
@@ -1123,17 +1131,17 @@ SearchEngine.prototype = {
     var parser = new DOMParser();
     var doc = parser.parseFromBuffer(bytes, "text/xml");
     engine._data = doc.documentElement;
 
     try {
       // Initialize the engine from the obtained data
       engine._initFromData();
     } catch (ex) {
-      SearchUtils.log("_onLoad: Failed to init engine!\n" + ex);
+      logConsole.error("_onLoad: Failed to init engine!", ex);
       // Report an error to the user
       if (ex.result == Cr.NS_ERROR_FILE_CORRUPTED) {
         promptError({
           error: "error_invalid_engine_msg2",
           title: "error_invalid_format_title",
         });
       } else {
         promptError();
@@ -1172,31 +1180,26 @@ SearchEngine.prototype = {
               error: "error_duplicate_engine_msg",
               title: "error_invalid_engine_title",
             },
             Ci.nsISearchService.ERROR_DUPLICATE_ENGINE
           );
         } else {
           onError(Ci.nsISearchService.ERROR_DUPLICATE_ENGINE);
         }
-        SearchUtils.log("_onLoad: duplicate engine found, bailing");
+        logConsole.debug("_onLoad: duplicate engine found, bailing");
         return;
       }
 
       // If requested, confirm the addition now that we have the title.
       // This property is only ever true for engines added via
       // nsISearchService::addEngine.
       if (engine._confirm) {
         var confirmation = engine._confirmAddEngine();
-        SearchUtils.log(
-          "_onLoad: confirm is " +
-            confirmation.confirmed +
-            "; useNow is " +
-            confirmation.useNow
-        );
+        logConsole.debug("_onLoad: confirm", confirmation);
         if (!confirmation.confirmed) {
           onError();
           return;
         }
         engine._useNow = confirmation.useNow;
       }
 
       engine._shortName = sanitizeName(engine.name);
@@ -1280,22 +1283,21 @@ SearchEngine.prototype = {
   _setIcon(iconURL, isPreferred, width, height) {
     var uri = SearchUtils.makeURI(iconURL);
 
     // Ignore bad URIs
     if (!uri) {
       return;
     }
 
-    SearchUtils.log(
-      '_setIcon: Setting icon url "' +
-        limitURILength(uri.spec) +
-        '" for engine "' +
-        this.name +
-        '".'
+    logConsole.debug(
+      "_setIcon: Setting icon url for",
+      this.name,
+      "to",
+      limitURILength(uri.spec)
     );
     // Only accept remote icons from http[s] or ftp
     switch (uri.scheme) {
       // Fall through to the data case
       case "moz-extension":
       case "data":
         if (!this._hasPreferredIcon || isPreferred) {
           this._iconURI = uri;
@@ -1305,47 +1307,37 @@ SearchEngine.prototype = {
 
         if (width && height) {
           this._addIconToMap(width, height, iconURL);
         }
         break;
       case "http":
       case "https":
       case "ftp":
-        SearchUtils.log(
-          '_setIcon: Downloading icon: "' +
-            uri.spec +
-            '" for engine: "' +
-            this.name +
-            '"'
-        );
         var chan = SearchUtils.makeChannel(uri);
 
         let iconLoadCallback = function(byteArray, engine) {
           // This callback may run after we've already set a preferred icon,
           // so check again.
           if (engine._hasPreferredIcon && !isPreferred) {
             return;
           }
 
           if (!byteArray) {
-            SearchUtils.log("iconLoadCallback: load failed");
+            logConsole.warn("iconLoadCallback: load failed");
             return;
           }
 
           let contentType = chan.contentType;
           if (byteArray.length > SearchUtils.MAX_ICON_SIZE) {
             try {
-              SearchUtils.log("iconLoadCallback: rescaling icon");
+              logConsole.debug("iconLoadCallback: rescaling icon");
               [byteArray, contentType] = rescaleIcon(byteArray, contentType);
             } catch (ex) {
-              SearchUtils.log("iconLoadCallback: got exception: " + ex);
-              Cu.reportError(
-                "Unable to set an icon for the search engine because: " + ex
-              );
+              logConsole.error("Unable to set icon for the search engine:", ex);
               return;
             }
           }
 
           if (!contentType.startsWith("image/")) {
             contentType = "image/x-icon";
           }
           let dataURL =
@@ -1389,17 +1381,17 @@ SearchEngine.prototype = {
     // Ensure we have a supported engine type before attempting to parse it.
     let element = this._data;
     if (
       (element.localName == MOZSEARCH_LOCALNAME &&
         element.namespaceURI == MOZSEARCH_NS_10) ||
       (element.localName == OPENSEARCH_LOCALNAME &&
         OPENSEARCH_NAMESPACES.includes(element.namespaceURI))
     ) {
-      SearchUtils.log("_init: Initing search plugin from " + this._location);
+      logConsole.debug("Initing search plugin from", this._location);
 
       this._parse();
     } else {
       Cu.reportError("Invalid search plugin due to namespace not matching.");
       SearchUtils.fail(
         this._location + " is not a valid search plugin.",
         Cr.NS_ERROR_FILE_CORRUPTED
       );
@@ -1633,35 +1625,26 @@ SearchEngine.prototype = {
 
     for (var i = 0; i < element.children.length; ++i) {
       var param = element.children[i];
       if (param.localName == "Param") {
         try {
           url.addParam(param.getAttribute("name"), param.getAttribute("value"));
         } catch (ex) {
           // Ignore failure
-          SearchUtils.log("_parseURL: Url element has an invalid param");
+          logConsole.error("_parseURL: Url element has an invalid param");
         }
       } else if (
         param.localName == "MozParam" &&
         // We only support MozParams for default search engines
         this.isAppProvided
       ) {
         let condition = param.getAttribute("condition");
 
-        // MozParams must have a condition to be valid
         if (!condition) {
-          let engineLoc = this._location;
-          let paramName = param.getAttribute("name");
-          SearchUtils.log(
-            "_parseURL: MozParam (" +
-              paramName +
-              ") without a condition attribute found parsing engine: " +
-              engineLoc
-          );
           continue;
         }
 
         // We can't make these both use _addMozParam due to the fallback
         // handling - WebExtension parameters get treated as MozParams even
         // if they are not, and hence don't have the condition parameter, so
         // we can't warn for them.
         switch (condition) {
@@ -1675,25 +1658,24 @@ SearchEngine.prototype = {
           case "pref":
             url._addMozParam({
               pref: param.getAttribute("pref"),
               name: param.getAttribute("name"),
               condition: "pref",
             });
             break;
           default:
-            let engineLoc = this._location;
-            let paramName = param.getAttribute("name");
-            SearchUtils.log(
-              "_parseURL: MozParam (" +
-                paramName +
-                ") has an unknown condition: " +
-                condition +
-                ". Found parsing engine: " +
-                engineLoc
+            // MozParams must have a condition to be valid
+            logConsole.error(
+              "Parsing engine:",
+              this._location,
+              "MozParam:",
+              param.getAttribute("name"),
+              "has an unknown condition:",
+              condition
             );
             break;
         }
       }
     }
 
     this._urls.push(url);
   },
@@ -1701,28 +1683,22 @@ SearchEngine.prototype = {
   /**
    * Get the icon from an OpenSearch Image element.
    *
    * @param {HTMLLinkElement} element
    *   The OpenSearch URL element.
    * @see http://opensearch.a9.com/spec/1.1/description/#image
    */
   _parseImage(element) {
-    SearchUtils.log(
-      '_parseImage: Image textContent: "' +
-        limitURILength(element.textContent) +
-        '"'
-    );
-
     let width = parseInt(element.getAttribute("width"), 10);
     let height = parseInt(element.getAttribute("height"), 10);
     let isPrefered = width == 16 && height == 16;
 
     if (isNaN(width) || isNaN(height) || width <= 0 || height <= 0) {
-      SearchUtils.log(
+      logConsole.warn(
         "OpenSearch image element must have positive width and height."
       );
       return;
     }
 
     this._setIcon(element.textContent, isPrefered, width, height);
   },
 
@@ -1745,17 +1721,17 @@ SearchEngine.prototype = {
         case "Description":
           this._description = child.textContent;
           break;
         case "Url":
           try {
             this._parseURL(child);
           } catch (ex) {
             // Parsing of the element failed, just skip it.
-            SearchUtils.log("_parse: failed to parse URL child: " + ex);
+            logConsole.error("Failed to parse URL child:", ex);
           }
           break;
         case "Image":
           this._parseImage(child);
           break;
         case "InputEncoding":
           this._queryCharset = child.textContent.toUpperCase();
           break;
@@ -2245,33 +2221,29 @@ SearchEngine.prototype = {
 
     if (!data) {
       // Return a dummy submission object with our searchForm attribute
       return new Submission(
         SearchUtils.makeURI(this._getSearchFormWithPurpose(purpose))
       );
     }
 
-    SearchUtils.log(
-      'getSubmission: In data: "' + data + '"; Purpose: "' + purpose + '"'
-    );
     var submissionData = "";
     try {
       submissionData = Services.textToSubURI.ConvertAndEscape(
         this.queryCharset,
         data
       );
     } catch (ex) {
-      SearchUtils.log("getSubmission: Falling back to default queryCharset!");
+      logConsole.warn("getSubmission: Falling back to default queryCharset!");
       submissionData = Services.textToSubURI.ConvertAndEscape(
         SearchUtils.DEFAULT_QUERY_CHARSET,
         data
       );
     }
-    SearchUtils.log('getSubmission: Out data: "' + submissionData + '"');
     return url.getSubmission(submissionData, this, purpose);
   },
 
   // from nsISearchEngine
   supportsResponseType(type) {
     return this._getURLOfType(type) != null;
   },
 
@@ -2279,18 +2251,16 @@ SearchEngine.prototype = {
   getResultDomain(responseType) {
     if (!responseType) {
       responseType =
         AppConstants.platform == "android"
           ? this._defaultMobileResponseType
           : SearchUtils.URL_TYPE.SEARCH;
     }
 
-    SearchUtils.log('getResultDomain: responseType: "' + responseType + '"');
-
     let url = this._getURLOfType(responseType);
     if (url) {
       return url.resultDomain;
     }
     return "";
   },
 
   /**
--- a/toolkit/components/search/SearchService.jsm
+++ b/toolkit/components/search/SearchService.jsm
@@ -213,81 +213,85 @@ var fetchRegionDefault = ss =>
 
     // Append the optional cohort value.
     const cohortPref = "browser.search.cohort";
     let cohort = Services.prefs.getCharPref(cohortPref, "");
     if (cohort) {
       endpoint += "/" + cohort;
     }
 
-    SearchUtils.log("fetchRegionDefault starting with endpoint " + endpoint);
+    logConsole.debug("fetchRegionDefault starting with endpoint ", endpoint);
 
     let startTime = Date.now();
     let request = new XMLHttpRequest();
     request.timeout = 100000; // 100 seconds as the last-chance fallback
     request.onload = function(event) {
       let took = Date.now() - startTime;
 
       let status = event.target.status;
       if (status != 200) {
-        SearchUtils.log("fetchRegionDefault failed with HTTP code " + status);
+        logConsole.debug("fetchRegionDefault failed with HTTP code ", status);
         let retryAfter = request.getResponseHeader("retry-after");
         if (retryAfter) {
           ss.setGlobalAttr(
             "searchDefaultExpir",
             Date.now() + retryAfter * 1000
           );
         }
         resolve();
         return;
       }
 
       let response = event.target.response || {};
-      SearchUtils.log("received " + response.toSource());
+      logConsole.debug("received", response.toSource());
 
       if (response.cohort) {
         Services.prefs.setCharPref(cohortPref, response.cohort);
       } else {
         Services.prefs.clearUserPref(cohortPref);
       }
 
       if (response.settings && response.settings.searchDefault) {
         let defaultEngine = response.settings.searchDefault;
         ss.setVerifiedGlobalAttr("searchDefault", defaultEngine);
-        SearchUtils.log(
-          "fetchRegionDefault saved searchDefault: " + defaultEngine
+        logConsole.debug(
+          "fetchRegionDefault saved searchDefault:",
+          defaultEngine
         );
       }
 
       if (response.settings && response.settings.visibleDefaultEngines) {
         let visibleDefaultEngines = response.settings.visibleDefaultEngines;
         let string = visibleDefaultEngines.join(",");
         ss.setVerifiedGlobalAttr("visibleDefaultEngines", string);
-        SearchUtils.log(
-          "fetchRegionDefault saved visibleDefaultEngines: " + string
+        logConsole.debug(
+          "fetchRegionDefault saved visibleDefaultEngines:",
+          string
         );
       }
 
       let interval = response.interval || SEARCH_GEO_DEFAULT_UPDATE_INTERVAL;
       let milliseconds = interval * 1000; // |interval| is in seconds.
       ss.setGlobalAttr("searchDefaultExpir", Date.now() + milliseconds);
 
-      SearchUtils.log(
-        "fetchRegionDefault got success response in " + took + "ms"
+      logConsole.debug(
+        "fetchRegionDefault got success response in",
+        took,
+        "ms"
       );
       // If we're doing this somewhere during the app's lifetime, reload the list
       // of engines in order to pick up any geo-specific changes.
       ss._maybeReloadEngines().finally(resolve);
     };
     request.ontimeout = function(event) {
-      SearchUtils.log("fetchRegionDefault: XHR finally timed-out");
+      logConsole.debug("fetchRegionDefault: XHR finally timed-out");
       resolve();
     };
     request.onerror = function(event) {
-      SearchUtils.log(
+      logConsole.debug(
         "fetchRegionDefault: failed to retrieve territory default information"
       );
       resolve();
     };
     request.open("GET", endpoint, true);
     request.setRequestHeader("Content-Type", "application/json");
     request.responseType = "json";
     request.send();
@@ -500,17 +504,17 @@ SearchService.prototype = {
   },
 
   // If initialization has not been completed yet, perform synchronous
   // initialization.
   // Throws in case of initialization error.
   _ensureInitialized() {
     if (gInitialized) {
       if (!Components.isSuccessCode(this._initRV)) {
-        SearchUtils.log("_ensureInitialized: failure");
+        logConsole.debug("_ensureInitialized: failure");
         throw Components.Exception(
           "SearchService previously failed to initialize",
           this._initRV
         );
       }
       return;
     }
 
@@ -525,17 +529,17 @@ SearchService.prototype = {
 
   /**
    * Asynchronous implementation of the initializer.
    *
    * @returns {number}
    *   A Components.results success code on success, otherwise a failure code.
    */
   async _init() {
-    SearchUtils.log("_init start");
+    logConsole.debug("_init start");
 
     XPCOMUtils.defineLazyPreferenceGetter(
       this,
       "_separatePrivateDefaultPrefValue",
       SearchUtils.BROWSER_SEARCH_PREF + "separatePrivateDefault",
       false,
       this._onSeparateDefaultPrefChanged.bind(this)
     );
@@ -563,64 +567,60 @@ SearchService.prototype = {
 
       // See if we have a cache file so we don't have to parse a bunch of XML.
       let cache = await this._readCacheFile();
 
       // The init flow is not going to block on a fetch from an external service,
       // but we're kicking it off as soon as possible to prevent UI flickering as
       // much as possible.
       this._ensureKnownRegionPromise = ensureKnownRegion(this)
-        .catch(ex =>
-          SearchUtils.log("_init: failure determining region: " + ex)
-        )
+        .catch(ex => logConsole.error("_init: failure determining region:", ex))
         .finally(() => (this._ensureKnownRegionPromise = null));
 
       this._setupRemoteSettings().catch(Cu.reportError);
 
       await this._loadEngines(cache);
 
       // If we've got this far, but the application is now shutting down,
       // then we need to abandon any further work, especially not writing
       // the cache. We do this, because the add-on manager has also
       // started shutting down and as a result, we might have an incomplete
       // picture of the installed search engines. Writing the cache at
       // this stage would potentially mean the user would loose their engine
       // data.
       // We will however, rebuild the cache on next start up if we detect
       // it is necessary.
       if (Services.startup.shuttingDown) {
-        SearchUtils.log("_init: abandoning init due to shutting down");
+        logConsole.warn("_init: abandoning init due to shutting down");
         this._initRV = Cr.NS_ERROR_ABORT;
         this._initObservers.reject(this._initRV);
         return this._initRV;
       }
 
       // Make sure the current list of engines is persisted, without the need to wait.
-      SearchUtils.log("_init: engines loaded, writing cache");
+      logConsole.debug("_init: engines loaded, writing cache");
       this._buildCache();
       this._addObservers();
     } catch (ex) {
       this._initRV = ex.result !== undefined ? ex.result : Cr.NS_ERROR_FAILURE;
-      SearchUtils.log(
-        "_init: failure initializing search: " + ex + "\n" + ex.stack
-      );
+      logConsole.error("_init: failure initializing search:", ex);
     }
     gInitialized = true;
     if (Components.isSuccessCode(this._initRV)) {
       this._initObservers.resolve(this._initRV);
     } else {
       this._initObservers.reject(this._initRV);
     }
     Services.obs.notifyObservers(
       null,
       SearchUtils.TOPIC_SEARCH_SERVICE,
       "init-complete"
     );
 
-    SearchUtils.log("_init: Completed _init");
+    logConsole.debug("Completed _init");
     return this._initRV;
   },
 
   /**
    * Obtains the remote settings for the search service. This should only be
    * called from init(). Any subsequent updates to the remote settings are
    * handled via a sync listener.
    *
@@ -647,17 +647,17 @@ SearchService.prototype = {
   /**
    * This handles updating of the ignore list settings, and removing any ignored
    * engines.
    *
    * @param {object} eventData
    *   The event in the format received from RemoteSettings.
    */
   async _handleIgnoreListUpdated(eventData) {
-    SearchUtils.log("_handleIgnoreListUpdated");
+    logConsole.debug("_handleIgnoreListUpdated");
     const {
       data: { current },
     } = eventData;
 
     for (const entry of current) {
       if (entry.id == "load-paths") {
         this._loadPathIgnoreList = [...entry.matches];
       } else if (entry.id == "submission-urls") {
@@ -826,17 +826,17 @@ SearchService.prototype = {
   },
 
   getGlobalAttr(name) {
     return this._metaData[name] || undefined;
   },
   getVerifiedGlobalAttr(name) {
     let val = this.getGlobalAttr(name);
     if (val && this.getGlobalAttr(name + "Hash") != getVerificationHash(val)) {
-      SearchUtils.log("getVerifiedGlobalAttr, invalid hash for " + name);
+      logConsole.warn("getVerifiedGlobalAttr, invalid hash for", name);
       return "";
     }
     return val;
   },
 
   _listJSONURL: `${EXT_SEARCH_PREFIX}list.json`,
 
   get _sortedEngines() {
@@ -1008,44 +1008,44 @@ SearchService.prototype = {
     }
     cache.metaData = this._metaData;
 
     try {
       if (!cache.engines.length) {
         throw new Error("cannot write without any engine.");
       }
 
-      SearchUtils.log("_buildCache: Writing to cache file.");
+      logConsole.debug("_buildCache: Writing to cache file.");
       let path = OS.Path.join(OS.Constants.Path.profileDir, CACHE_FILENAME);
       let data = gEncoder.encode(JSON.stringify(cache));
       await OS.File.writeAtomic(path, data, {
         compression: "lz4",
         tmpPath: path + ".tmp",
       });
-      SearchUtils.log("_buildCache: cache file written to disk.");
+      logConsole.debug("_buildCache: cache file written to disk.");
       Services.obs.notifyObservers(
         null,
         SearchUtils.TOPIC_SEARCH_SERVICE,
         "write-cache-to-disk-complete"
       );
     } catch (ex) {
-      SearchUtils.log("_buildCache: Could not write to cache file: " + ex);
+      logConsole.error("_buildCache: Could not write to cache file:", ex);
     }
   },
 
   /**
    * Loads engines asynchronously.
    *
    * @param {object} cache
    *   An object representing the search engine cache.
    * @param {boolean} isReload
    *   Set to true if this load is happening during a reload.
    */
   async _loadEngines(cache, isReload) {
-    SearchUtils.log("_loadEngines: start");
+    logConsole.debug("_loadEngines: start");
     let engines = await this._findEngines();
 
     let buildID = Services.appinfo.platformBuildID;
     let rebuildCache =
       gEnvironment.get("RELOAD_ENGINES") ||
       !cache.engines ||
       cache.version != SearchUtils.CACHE_VERSION ||
       cache.locale != Services.locale.requestedLocale ||
@@ -1101,39 +1101,39 @@ SearchService.prototype = {
     }
 
     Services.telemetry.scalarSet(
       "browser.searchinit.engines_cache_corrupted",
       enginesCorrupted
     );
 
     if (!rebuildCache) {
-      SearchUtils.log("_loadEngines: loading from cache directories");
+      logConsole.debug("_loadEngines: loading from cache directories");
       if (gModernConfig) {
         const newEngines = await this._loadEnginesFromConfig(engines, isReload);
         for (let engine of newEngines) {
           this._addEngineToStore(engine);
         }
         // TODO: Remove the second argument when we remove the legacy config
         // (the function should then always skip-builtin engines).
         this._loadEnginesFromCache(cache, true);
         this._loadEnginesMetadataFromCache(cache);
       } else {
         this._loadEnginesFromCache(cache);
       }
       if (this._engines.size) {
-        SearchUtils.log("_loadEngines: done using existing cache");
+        logConsole.debug("_loadEngines: done using existing cache");
         return;
       }
-      SearchUtils.log(
+      logConsole.debug(
         "_loadEngines: No valid engines found in cache. Loading engines from disk."
       );
     }
 
-    SearchUtils.log(
+    logConsole.debug(
       "_loadEngines: Absent or outdated cache. Loading engines from disk."
     );
     if (gModernConfig) {
       let newEngines = await this._loadEnginesFromConfig(engines, isReload);
       newEngines.forEach(this._addEngineToStore, this);
     } else {
       let distDirs = await this._getDistibutionEngineDirectories();
       for (let loadDir of distDirs) {
@@ -1141,53 +1141,53 @@ SearchService.prototype = {
         enginesFromDir.forEach(this._addEngineToStore, this);
       }
 
       let engineList = this._enginesToLocales(engines);
       for (let [id, locales] of engineList) {
         await this.ensureBuiltinExtension(id, locales, isReload);
       }
     }
-    SearchUtils.log(
-      "_loadEngines: loading " +
-        this._startupExtensions.size +
-        " engines reported by AddonManager startup"
+    logConsole.debug(
+      "_loadEngines: loading",
+      this._startupExtensions.size,
+      "engines reported by AddonManager startup"
     );
     for (let extension of this._startupExtensions) {
       await this._installExtensionEngine(
         extension,
         [SearchUtils.DEFAULT_TAG],
         true
       );
     }
 
-    SearchUtils.log(
+    logConsole.debug(
       "_loadEngines: loading user-installed engines from the obsolete cache"
     );
     this._loadEnginesFromCache(cache, true);
 
     this._loadEnginesMetadataFromCache(cache);
 
-    SearchUtils.log("_loadEngines: done using rebuilt cache");
+    logConsole.debug("_loadEngines: done using rebuilt cache");
   },
 
   /**
    * Loads engines as specified by the configuration. We only expect
    * configured engines here, user engines should not be listed.
    *
    * @param {array} engineConfigs
    *   An array of engines configurations based on the schema.
    * @param {boolean} [isReload]
    *   Set to true to indicate a reload is happening.
    * @returns {array.<nsISearchEngine>}
    *   Returns an array of the loaded search engines. This may be
    *   smaller than the original list if not all engines can be loaded.
    */
   async _loadEnginesFromConfig(engineConfigs, isReload = false) {
-    SearchUtils.log("_loadEnginesFromConfig");
+    logConsole.debug("_loadEnginesFromConfig");
     let engines = [];
     for (let config of engineConfigs) {
       try {
         let engine = await this.makeEngineFromConfig(config, isReload);
         engines.push(engine);
       } catch (ex) {
         console.error(
           `Could not load engine ${
@@ -1265,35 +1265,35 @@ SearchService.prototype = {
    * @param {boolean} [isReload]
    *   is being called from maybeReloadEngines.
    */
   async ensureBuiltinExtension(
     id,
     locales = [SearchUtils.DEFAULT_TAG],
     isReload = false
   ) {
-    SearchUtils.log("ensureBuiltinExtension: " + id);
+    logConsole.debug("ensureBuiltinExtension: ", id);
     try {
       let policy = WebExtensionPolicy.getByID(id);
       if (!policy) {
-        SearchUtils.log("ensureBuiltinExtension: Installing " + id);
+        logConsole.debug("ensureBuiltinExtension: Installing ", id);
         let path = EXT_SEARCH_PREFIX + id.split("@")[0] + "/";
         await AddonManager.installBuiltinAddon(path);
         policy = WebExtensionPolicy.getByID(id);
       }
       // On startup the extension may have not finished parsing the
       // manifest, wait for that here.
       await policy.readyPromise;
       await this._installExtensionEngine(
         policy.extension,
         locales,
         false,
         isReload
       );
-      SearchUtils.log("ensureBuiltinExtension: " + id + " installed.");
+      logConsole.debug("ensureBuiltinExtension: ", id, " installed.");
     } catch (err) {
       Cu.reportError(
         "Failed to install engine: " + err.message + "\n" + err.stack
       );
     }
   },
 
   /**
@@ -1341,42 +1341,42 @@ SearchService.prototype = {
 
   /**
    * Reloads engines asynchronously, but only when
    * the service has already been initialized.
    */
   async _maybeReloadEngines() {
     if (!gInitialized) {
       if (this._maybeReloadDebounce) {
-        SearchUtils.log(
+        logConsole.debug(
           "We're already waiting for init to finish and reload engines after."
         );
         return;
       }
       this._maybeReloadDebounce = true;
       // Schedule a reload to happen at most 10 seconds after initialization of
       // the service finished, during an idle moment.
       this._initObservers.promise.then(() => {
         Services.tm.idleDispatchToMainThread(() => {
           if (!this._maybeReloadDebounce) {
             return;
           }
           delete this._maybeReloadDebounce;
           this._maybeReloadEngines();
         }, 10000);
       });
-      SearchUtils.log(
+      logConsole.debug(
         "Post-poning maybeReloadEngines() as we're currently initializing."
       );
       return;
     }
     // There's no point in already reloading the list of engines, when the service
     // hasn't even initialized yet.
     if (!gInitialized) {
-      SearchUtils.log("Ignoring maybeReloadEngines() as inside init()");
+      logConsole.debug("Ignoring maybeReloadEngines() as inside init()");
       return;
     }
 
     // Before we read the cache file, first make sure all pending tasks are clear.
     if (this._batchTask) {
       let task = this._batchTask;
       this._batchTask = null;
       await task.finalize();
@@ -1425,20 +1425,20 @@ SearchService.prototype = {
     Services.obs.notifyObservers(
       null,
       SearchUtils.TOPIC_SEARCH_SERVICE,
       "engines-reloaded"
     );
   },
 
   _reInit(origin) {
-    SearchUtils.log("_reInit");
+    logConsole.debug("_reInit");
     // Re-entrance guard, because we're using an async lambda below.
     if (gReinitializing) {
-      SearchUtils.log("_reInit: already re-initializing, bailing out.");
+      logConsole.debug("_reInit: already re-initializing, bailing out.");
       return;
     }
     gReinitializing = true;
 
     // Start by clearing the initialized state, so we don't abort early.
     gInitialized = false;
 
     // Tests want to know when we've started.
@@ -1455,17 +1455,17 @@ SearchService.prototype = {
         if (gModernConfig && !this._engineSelector) {
           this._engineSelector = new SearchEngineSelector(
             this._handleConfigurationUpdated.bind(this)
           );
         }
 
         this._initObservers = PromiseUtils.defer();
         if (this._batchTask) {
-          SearchUtils.log("finalizing batch task");
+          logConsole.debug("finalizing batch task");
           let task = this._batchTask;
           this._batchTask = null;
           // Tests manipulate the cache directly, so let's not double-write with
           // stale cache data here.
           if (origin == "test") {
             task.disarm();
           } else {
             await task.finalize();
@@ -1484,33 +1484,33 @@ SearchService.prototype = {
         );
 
         let cache = await this._readCacheFile();
         // The init flow is not going to block on a fetch from an external service,
         // but we're kicking it off as soon as possible to prevent UI flickering as
         // much as possible.
         this._ensureKnownRegionPromise = ensureKnownRegion(this)
           .catch(ex =>
-            SearchUtils.log("_reInit: failure determining region: " + ex)
+            logConsole.error("_reInit: failure determining region:", ex)
           )
           .finally(() => (this._ensureKnownRegionPromise = null));
 
         await this._loadEngines(cache);
 
         // If we've got this far, but the application is now shutting down,
         // then we need to abandon any further work, especially not writing
         // the cache. We do this, because the add-on manager has also
         // started shutting down and as a result, we might have an incomplete
         // picture of the installed search engines. Writing the cache at
         // this stage would potentially mean the user would loose their engine
         // data.
         // We will however, rebuild the cache on next start up if we detect
         // it is necessary.
         if (Services.startup.shuttingDown) {
-          SearchUtils.log("_reInit: abandoning reInit due to shutting down");
+          logConsole.warn("_reInit: abandoning reInit due to shutting down");
           this._initObservers.reject(Cr.NS_ERROR_ABORT);
           return;
         }
 
         // Make sure the current list of engines is persisted.
         await this._buildCache();
 
         // Typically we'll re-init as a result of a pref observer,
@@ -1518,18 +1518,17 @@ SearchService.prototype = {
         gInitialized = true;
         this._initObservers.resolve();
         Services.obs.notifyObservers(
           null,
           SearchUtils.TOPIC_SEARCH_SERVICE,
           "init-complete"
         );
       } catch (err) {
-        SearchUtils.log("Reinit failed: " + err);
-        SearchUtils.log(err.stack);
+        logConsole.error("Reinit failed:", err);
         Services.obs.notifyObservers(
           null,
           SearchUtils.TOPIC_SEARCH_SERVICE,
           "reinit-failed"
         );
       } finally {
         gReinitializing = false;
         Services.obs.notifyObservers(
@@ -1572,52 +1571,52 @@ SearchService.prototype = {
         !gModernConfig &&
         json.appVersion != Services.appinfo.version &&
         gGeoSpecificDefaultsEnabled &&
         json.metaData
       ) {
         json.metaData.searchDefaultExpir = 0;
       }
     } catch (ex) {
-      SearchUtils.log("_readCacheFile: Error reading cache file: " + ex);
+      logConsole.error("_readCacheFile: Error reading cache file:", ex);
       json = {};
     }
     if (!gInitialized && json.metaData) {
       this._metaData = json.metaData;
     }
 
     return json;
   },
 
   _batchTask: null,
   get batchTask() {
     if (!this._batchTask) {
       let task = async () => {
-        SearchUtils.log("batchTask: Invalidating engine cache");
+        logConsole.debug("batchTask: Invalidating engine cache");
         await this._buildCache();
       };
       this._batchTask = new DeferredTask(task, CACHE_INVALIDATION_DELAY);
     }
     return this._batchTask;
   },
 
   _addEngineToStore(engine) {
     if (this._engineMatchesIgnoreLists(engine)) {
-      SearchUtils.log("_addEngineToStore: Ignoring engine");
+      logConsole.debug("_addEngineToStore: Ignoring engine");
       return;
     }
 
-    SearchUtils.log('_addEngineToStore: Adding engine: "' + engine.name + '"');
+    logConsole.debug("_addEngineToStore: Adding engine:", engine.name);
 
     // See if there is an existing engine with the same name. However, if this
     // engine is updating another engine, it's allowed to have the same name.
     var hasSameNameAsUpdate =
       engine._engineToUpdate && engine.name == engine._engineToUpdate.name;
     if (this._engines.has(engine.name) && !hasSameNameAsUpdate) {
-      SearchUtils.log("_addEngineToStore: Duplicate engine found, aborting!");
+      logConsole.debug("_addEngineToStore: Duplicate engine found, aborting!");
       return;
     }
 
     if (engine._engineToUpdate) {
       // We need to replace engineToUpdate with the engine that just loaded.
       var oldEngine = engine._engineToUpdate;
 
       // Remove the old engine from the hash, since it's keyed by name, and our
@@ -1664,18 +1663,19 @@ SearchService.prototype = {
   _loadEnginesMetadataFromCache(cache) {
     if (!cache.engines) {
       return;
     }
 
     for (let engine of cache.engines) {
       let name = engine._name;
       if (this._engines.has(name)) {
-        SearchUtils.log(
-          "_loadEnginesMetadataFromCache, transfering metadata for " + name
+        logConsole.debug(
+          "_loadEnginesMetadataFromCache, transfering metadata for",
+          name
         );
         let eng = this._engines.get(name);
         // We used to store the alias in metadata.alias, in 1621892 that was
         // changed to only store the user set alias in metadata.alias, remove
         // it from metadata if it was previously set to the internal value.
         if (eng._alias === engine?._metaData?.alias) {
           delete engine._metaData.alias;
         }
@@ -1684,66 +1684,68 @@ SearchService.prototype = {
     }
   },
 
   _loadEnginesFromCache(cache, skipBuiltIn) {
     if (!cache.engines) {
       return;
     }
 
-    SearchUtils.log(
-      "_loadEnginesFromCache: Loading " +
-        cache.engines.length +
-        " engines from cache"
+    logConsole.debug(
+      "_loadEnginesFromCache: Loading",
+      cache.engines.length,
+      "engines from cache"
     );
 
     let skippedEngines = 0;
     for (let engine of cache.engines) {
       if (skipBuiltIn && engine._isBuiltin) {
         ++skippedEngines;
         continue;
       }
 
       this._loadEngineFromCache(engine);
     }
 
     if (skippedEngines) {
-      SearchUtils.log(
-        "_loadEnginesFromCache: skipped " +
-          skippedEngines +
-          " built-in engines."
+      logConsole.debug(
+        "_loadEnginesFromCache: skipped",
+        skippedEngines,
+        "built-in engines."
       );
     }
   },
 
   _loadEngineFromCache(json) {
     try {
       let engine = new SearchEngine({
         shortName: json._shortName,
         isBuiltin: !!json._isBuiltin,
       });
       engine._initWithJSON(json);
       this._addEngineToStore(engine);
     } catch (ex) {
-      SearchUtils.log("Failed to load " + json._name + " from cache: " + ex);
-      SearchUtils.log("Engine JSON: " + json.toSource());
+      logConsole.error("Failed to load", json._name, "from cache:", ex);
+      logConsole.debug("Engine JSON:", json.toSource());
     }
   },
 
   /**
    * Loads engines from a given directory asynchronously.
    *
    * @param {OS.File}
    *   dir the directory.
    * @returns {Array<SearchEngine>}
    *   An array of search engines that were found.
    */
   async _loadEnginesFromDir(dir) {
-    SearchUtils.log(
-      "_loadEnginesFromDir: Searching in " + dir.path + " for search engines."
+    logConsole.debug(
+      "_loadEnginesFromDir: Searching in",
+      dir.path,
+      "for search engines."
     );
 
     let iterator = new OS.File.DirectoryIterator(dir.path);
 
     let osfiles = await iterator.nextBatch();
     iterator.close();
 
     let engines = [];
@@ -1769,26 +1771,24 @@ SearchService.prototype = {
         file.initWithPath(osfile.path);
         addedEngine = new SearchEngine({
           fileURI: file,
           isBuiltin: true,
         });
         await addedEngine._initFromFile(file);
         engines.push(addedEngine);
       } catch (ex) {
-        SearchUtils.log(
-          "_loadEnginesFromDir: Failed to load " + osfile.path + "!\n" + ex
-        );
+        logConsole.error("Failed to load", osfile.path, ex);
       }
     }
     return engines;
   },
 
   async _findEngineSelectorEngines() {
-    SearchUtils.log("_findEngineSelectorEngines: init");
+    logConsole.debug("Finding engine configuration from the selector");
 
     let locale = Services.locale.appLocaleAsBCP47;
     let region = Region.home || "default";
 
     let channel = AppConstants.MOZ_APP_VERSION_DISPLAY.endsWith("esr")
       ? "esr"
       : AppConstants.MOZ_UPDATE_CHANNEL;
     let {
@@ -1831,35 +1831,33 @@ SearchService.prototype = {
    *
    * @returns {Array<string>}
    *   Returns an array of engine names.
    */
   async _findEngines() {
     if (gModernConfig) {
       return this._findEngineSelectorEngines();
     }
-    SearchUtils.log("_findEngines: looking for engines in list.json");
+    logConsole.debug("_findEngines: looking for engines in list.json");
 
     let chan = SearchUtils.makeChannel(this._listJSONURL);
     if (!chan) {
-      SearchUtils.log(
-        "_findEngines: " + this._listJSONURL + " isn't registered"
-      );
+      logConsole.debug("_findEngines:", this._listJSONURL, "isn't registered");
       return [];
     }
 
     // Read list.json to find the engines we need to load.
     let request = new XMLHttpRequest();
     request.overrideMimeType("text/plain");
     let list = await new Promise(resolve => {
       request.onload = function(event) {
         resolve(event.target.responseText);
       };
       request.onerror = function(event) {
-        SearchUtils.log("_findEngines: failed to read " + this._listJSONURL);
+        logConsole.debug("_findEngines: failed to read", this._listJSONURL);
         resolve();
       };
       request.open("GET", Services.io.newURI(this._listJSONURL).spec, true);
       request.send();
     });
 
     return this._parseListJSON(list);
   },
@@ -1871,19 +1869,18 @@ SearchService.prototype = {
    *   The engine list in json format.
    * @returns {Array<string>}
    *   Returns an array of engine names.
    */
   async _parseListJSON(list) {
     let json;
     try {
       json = JSON.parse(list);
-    } catch (e) {
-      Cu.reportError("parseListJSON: Failed to parse list.json: " + e);
-      dump("parseListJSON: Failed to parse list.json: " + e + "\n");
+    } catch (ex) {
+      logConsole.error("parseListJSON: Failed to parse list.json:", ex);
       return [];
     }
 
     let searchRegion = Region.home;
 
     let searchSettings;
     let locale = Services.locale.appLocaleAsBCP47;
     if ("locales" in json && locale in json.locales) {
@@ -1932,20 +1929,20 @@ SearchService.prototype = {
       for (let engineName of engineNames) {
         // If all engineName values are part of jarNames,
         // then we can use the region specific list, otherwise ignore it.
         // The visibleDefaultEngines string containing the name of an engine we
         // don't ship indicates the server is misconfigured to answer requests
         // from the specific Firefox version we are running, so ignoring the
         // value altogether is safer.
         if (!jarNames.has(engineName)) {
-          SearchUtils.log(
-            "_parseListJSON: ignoring visibleDefaultEngines value because " +
-              engineName +
-              " is not in the jar engines we have found"
+          logConsole.debug(
+            "_parseListJSON: ignoring visibleDefaultEngines value because",
+            engineName,
+            "is not in the jar engines we have found"
           );
           engineNames = null;
           break;
         }
       }
     }
 
     // Fallback to building a list based on the regions in the JSON
@@ -2053,51 +2050,48 @@ SearchService.prototype = {
       this._searchOrder = searchSettings.default.searchOrder;
     } else if ("searchOrder" in json.default) {
       this._searchOrder = json.default.searchOrder;
     }
     return [...engineNames];
   },
 
   _saveSortedEngineList() {
-    SearchUtils.log("_saveSortedEngineList: starting");
+    logConsole.debug("_saveSortedEngineList");
 
     // Set the useDB pref to indicate that from now on we should use the order
     // information stored in the database.
     Services.prefs.setBoolPref(
       SearchUtils.BROWSER_SEARCH_PREF + "useDBForOrder",
       true
     );
 
     var engines = this._getSortedEngines(true);
 
     for (var i = 0; i < engines.length; ++i) {
       engines[i].setAttr("order", i + 1);
     }
-
-    SearchUtils.log("_saveSortedEngineList: done");
   },
 
   _buildSortedEngineList() {
-    SearchUtils.log("_buildSortedEngineList: building list");
     // We must initialise __sortedEngines here to avoid infinite recursion
     // in the case of tests which don't define a default search engine.
     // If there's no default defined, then we revert to the first item in the
     // sorted list, but we can't do that if we don't have a list.
     this.__sortedEngines = [];
 
     // If the user has specified a custom engine order, read the order
     // information from the metadata instead of the default prefs.
     if (
       Services.prefs.getBoolPref(
         SearchUtils.BROWSER_SEARCH_PREF + "useDBForOrder",
         false
       )
     ) {
-      SearchUtils.log("_buildSortedEngineList: using db for order");
+      logConsole.debug("_buildSortedEngineList: using db for order");
       let addedEngines = {};
 
       // Flag to keep track of whether or not we need to call _saveSortedEngineList.
       let needToSaveEngineList = false;
 
       for (let engine of this._engines.values()) {
         var orderNumber = engine.getAttr("order");
 
@@ -2137,16 +2131,17 @@ SearchService.prototype = {
       }
 
       const collator = new Intl.Collator();
       alphaEngines.sort((a, b) => {
         return collator.compare(a.name, b.name);
       });
       return (this.__sortedEngines = this.__sortedEngines.concat(alphaEngines));
     }
+    logConsole.debug("_buildSortedEngineList: using default orders");
 
     return (this.__sortedEngines = this._sortEnginesByDefaults(
       Array.from(this._engines.values())
     ));
   },
 
   /**
    * Sorts engines by the default settings (prefs, configuration values).
@@ -2266,17 +2261,17 @@ SearchService.prototype = {
 
     return this._sortedEngines.filter(function(engine) {
       return !engine.hidden;
     });
   },
 
   // nsISearchService
   async init() {
-    SearchUtils.log("SearchService.init");
+    logConsole.debug("init");
     if (this._initStarted) {
       return this._initObservers.promise;
     }
 
     TelemetryStopwatch.start("SEARCH_SERVICE_INIT_MS");
     this._initStarted = true;
     try {
       // Complete initialization by calling asynchronous initializer.
@@ -2308,37 +2303,37 @@ SearchService.prototype = {
 
   // reInit is currently only exposed for testing purposes
   async reInit() {
     return this._reInit("test");
   },
 
   async getEngines() {
     await this.init();
-    SearchUtils.log("getEngines: getting all engines");
+    logConsole.debug("getEngines: getting all engines");
     return this._getSortedEngines(true);
   },
 
   async getVisibleEngines() {
     await this.init(true);
-    SearchUtils.log("getVisibleEngines: getting all visible engines");
+    logConsole.debug("getVisibleEngines: getting all visible engines");
     return this._getSortedEngines(false);
   },
 
   async getDefaultEngines() {
     await this.init();
 
     return this._sortEnginesByDefaults(
       this._sortedEngines.filter(e => e.isAppProvided)
     );
   },
 
   async getEnginesByExtensionID(extensionID) {
     await this.init();
-    SearchUtils.log("getEngines: getting all engines for " + extensionID);
+    logConsole.debug("getEngines: getting all engines for", extensionID);
     var engines = this._getSortedEngines(true).filter(function(engine) {
       return engine._extensionID == extensionID;
     });
     return engines;
   },
 
   /**
    * Returns the engine associated with the name.
@@ -2385,17 +2380,17 @@ SearchService.prototype = {
       ) {
         return engine;
       }
     }
     return null;
   },
 
   async addEngineWithDetails(name, details, isReload = false) {
-    SearchUtils.log('addEngineWithDetails: Adding "' + name + '".');
+    logConsole.debug("addEngineWithDetails: Adding", name);
     let isCurrent = false;
     var params = details;
 
     let isBuiltin = !!params.isBuiltin;
     // We install search extensions during the init phase, both built in
     // web extensions freshly installed (via addEnginesFromExtension) or
     // user installed extensions being reenabled calling this directly.
     if (!gInitialized && !isBuiltin && !params.initEngine) {
@@ -2454,21 +2449,24 @@ SearchService.prototype = {
     this._addEngineToStore(newEngine);
     if (isCurrent) {
       this.defaultEngine = newEngine;
     }
     return newEngine;
   },
 
   async addEnginesFromExtension(extension) {
-    SearchUtils.log("addEnginesFromExtension: " + extension.id);
     if (extension.addonData.builtIn) {
-      SearchUtils.log("addEnginesFromExtension: Ignoring builtIn engine.");
+      logConsole.debug(
+        "addEnginesFromExtension: Ignoring builtIn engine:",
+        extension.id
+      );
       return [];
     }
+    logConsole.debug("addEnginesFromExtension:", extension.id);
     // If we havent started SearchService yet, store this extension
     // to install in SearchService.init().
     if (!gInitialized) {
       this._startupExtensions.add(extension);
       return [];
     }
     if (extension.startupReason == "ADDON_UPGRADE") {
       let engines = await this.getEnginesByExtensionID(extension.id);
@@ -2493,19 +2491,17 @@ SearchService.prototype = {
    *   The configuration object that defines the details of the engine
    *   webExtensionId etc.
    * @param {boolean} isReload (optional)
    *   Is being called as part of maybeReloadEngines.
    * @returns {nsISearchEngine}
    *   Returns the search engine object.
    */
   async makeEngineFromConfig(config, isReload = false) {
-    if (SearchUtils.loggingEnabled) {
-      SearchUtils.log("makeEngineFromConfig: " + JSON.stringify(config));
-    }
+    logConsole.debug("makeEngineFromConfig:", config);
     let id = config.webExtension.id;
     let policy = WebExtensionPolicy.getByID(id);
     if (!policy) {
       let idPrefix = id.split("@")[0];
       let path = `resource://search-extensions/${idPrefix}/`;
       await AddonManager.installBuiltinAddon(path);
       policy = WebExtensionPolicy.getByID(id);
     }
@@ -2566,17 +2562,17 @@ SearchService.prototype = {
     }
     if (isReload && this._engines.has(engine.name)) {
       engine._engineToUpdate = this._engines.get(engine.name);
     }
     return engine;
   },
 
   async _installExtensionEngine(extension, locales, initEngine, isReload) {
-    SearchUtils.log("installExtensionEngine: " + extension.id);
+    logConsole.debug("installExtensionEngine:", extension.id);
 
     let installLocale = async locale => {
       let manifest =
         locale == SearchUtils.DEFAULT_TAG
           ? extension.manifest
           : await extension.getLocalizedManifest(locale);
       return this._addEngineForManifest(
         extension,
@@ -2584,21 +2580,21 @@ SearchService.prototype = {
         locale,
         initEngine,
         isReload
       );
     };
 
     let engines = [];
     for (let locale of locales) {
-      SearchUtils.log(
-        "addEnginesFromExtension: installing locale: " +
-          extension.id +
-          ":" +
-          locale
+      logConsole.debug(
+        "addEnginesFromExtension: installing:",
+        extension.id,
+        ":",
+        locale
       );
       engines.push(await installLocale(locale));
     }
     return engines;
   },
 
   async _addEngineForManifest(
     extension,
@@ -2697,17 +2693,17 @@ SearchService.prototype = {
       telemetryId: engineParams.telemetryId,
       initEngine: engineParams.initEngine || false,
     };
 
     return params;
   },
 
   async addEngine(engineURL, iconURL, confirm, extensionID) {
-    SearchUtils.log('addEngine: Adding "' + engineURL + '".');
+    logConsole.debug("addEngine: Adding", engineURL);
     await this.init();
     let errCode;
     try {
       var engine = new SearchEngine({
         uri: engineURL,
         isBuiltin: false,
       });
       engine._setIcon(iconURL, false);
@@ -2735,17 +2731,17 @@ SearchService.prototype = {
         "addEngine: Error adding engine:\n" + ex,
         errCode || Cr.NS_ERROR_FAILURE
       );
     }
     return engine;
   },
 
   async removeWebExtensionEngine(id) {
-    SearchUtils.log("removeWebExtensionEngine: " + id);
+    logConsole.debug("removeWebExtensionEngine:", id);
     for (let engine of await this.getEnginesByExtensionID(id)) {
       await this.removeEngine(engine);
     }
   },
 
   async removeEngine(engine) {
     await this.init();
     if (!engine) {
@@ -3472,24 +3468,20 @@ SearchService.prototype = {
 
   // nsIObserver
   observe(engine, topic, verb) {
     switch (topic) {
       case SearchUtils.TOPIC_ENGINE_MODIFIED:
         switch (verb) {
           case SearchUtils.MODIFIED_TYPE.LOADED:
             engine = engine.QueryInterface(Ci.nsISearchEngine);
-            SearchUtils.log(
-              "nsSearchService::observe: Done installation of " +
-                engine.name +
-                "."
-            );
+            logConsole.debug("observe: Done installation of ", engine.name);
             this._addEngineToStore(engine.wrappedJSObject);
             if (engine.wrappedJSObject._useNow) {
-              SearchUtils.log("nsSearchService::observe: setting current");
+              logConsole.debug("observe: setting current");
               this.defaultEngine = engine;
             }
             // The addition of the engine to the store always triggers an ADDED
             // or a CHANGED notification, that will trigger the task below.
             break;
           case SearchUtils.MODIFIED_TYPE.ADDED:
           case SearchUtils.MODIFIED_TYPE.CHANGED:
           case SearchUtils.MODIFIED_TYPE.REMOVED:
@@ -3499,17 +3491,17 @@ SearchService.prototype = {
             this._parseSubmissionMap = null;
             break;
         }
         break;
 
       case "idle": {
         this.idleService.removeIdleObserver(this, REINIT_IDLE_TIME_SEC);
         this._queuedIdle = false;
-        SearchUtils.log(
+        logConsole.debug(
           "Reloading engines after idle due to configuration change"
         );
         this._maybeReloadEngines().catch(Cu.reportError);
         break;
       }
 
       case QUIT_APPLICATION_TOPIC:
         this._removeObservers();
@@ -3531,68 +3523,67 @@ SearchService.prototype = {
           // Locales are removed during shutdown, so ignore this message
           if (!Services.startup.shuttingDown) {
             this._reInit(verb);
           }
         });
         break;
       case Region.REGION_TOPIC:
         if (verb == Region.REGION_UPDATED) {
-          SearchUtils.log("Region updated: " + Region.home);
+          logConsole.debug("Region updated:", Region.home);
           ensureKnownRegion(this)
             .then(this._maybeReloadEngines.bind(this))
             .catch(Cu.reportError);
         }
         break;
     }
   },
 
   // nsITimerCallback
   notify(timer) {
-    SearchUtils.log("_notify: checking for updates");
+    logConsole.debug("_notify: checking for updates");
 
     if (
       !Services.prefs.getBoolPref(
         SearchUtils.BROWSER_SEARCH_PREF + "update",
         true
       )
     ) {
       return;
     }
 
     // Our timer has expired, but unfortunately, we can't get any data from it.
     // Therefore, we need to walk our engine-list, looking for expired engines
     var currentTime = Date.now();
-    SearchUtils.log("currentTime: " + currentTime);
+    logConsole.debug("currentTime:" + currentTime);
     for (let e of this._engines.values()) {
       let engine = e.wrappedJSObject;
       if (!engine._hasUpdates) {
         continue;
       }
 
-      SearchUtils.log("checking " + engine.name);
-
       var expirTime = engine.getAttr("updateexpir");
-      SearchUtils.log(
-        "expirTime: " +
-          expirTime +
-          "\nupdateURL: " +
-          engine._updateURL +
-          "\niconUpdateURL: " +
-          engine._iconUpdateURL
+      logConsole.debug(
+        engine.name,
+        "expirTime:",
+        expirTime,
+        "updateURL:",
+        engine._updateURL,
+        "iconUpdateURL:",
+        engine._iconUpdateURL
       );
 
       var engineExpired = expirTime <= currentTime;
 
       if (!expirTime || !engineExpired) {
-        SearchUtils.log("skipping engine");
+        logConsole.debug("skipping engine");
         continue;
       }
 
-      SearchUtils.log(engine.name + " has expired");
+      logConsole.debug(engine.name, "has expired");
 
       engineUpdateService.update(engine);
 
       // Schedule the next update
       engineUpdateService.scheduleNextUpdate(engine);
     } // end engine iteration
   },
 
@@ -3625,17 +3616,17 @@ SearchService.prototype = {
           // to save the cache. It is likely that shutdown will have caused the
           // add-on manager to stop, which can cause initialization to fail.
           // Hence at that stage, we could have a broken cache which we don't
           // want to write.
           // The good news is, that if we don't write the cache here, we'll
           // detect the out-of-date cache on next state, and automatically
           // rebuild it.
           if (!gInitialized || gReinitializing) {
-            SearchUtils.log(
+            logConsole.warn(
               "not saving cache on shutdown due to initializing."
             );
             return;
           }
 
           if (this._batchTask) {
             shutdownState.step = "Finalizing batched task";
             try {
@@ -3688,17 +3679,17 @@ var engineUpdateService = {
   scheduleNextUpdate(engine) {
     var interval = engine._updateInterval || SEARCH_DEFAULT_UPDATE_INTERVAL;
     var milliseconds = interval * 86400000; // |interval| is in days
     engine.setAttr("updateexpir", Date.now() + milliseconds);
   },
 
   update(engine) {
     engine = engine.wrappedJSObject;
-    this._log("update called for " + engine._name);
+    logConsole.debug("update called for", engine._name);
     if (
       !Services.prefs.getBoolPref(
         SearchUtils.BROWSER_SEARCH_PREF + "update",
         true
       ) ||
       !engine._hasUpdates
     ) {
       return;
@@ -3707,56 +3698,37 @@ var engineUpdateService = {
     let testEngine = null;
     let updateURL = engine._getURLOfType(SearchUtils.URL_TYPE.OPENSEARCH);
     let updateURI =
       updateURL && updateURL._hasRelation("self")
         ? updateURL.getSubmission("", engine).uri
         : SearchUtils.makeURI(engine._updateURL);
     if (updateURI) {
       if (engine.isAppProvided && !updateURI.schemeIs("https")) {
-        this._log("Invalid scheme for default engine update");
+        logConsole.debug("Invalid scheme for default engine update");
         return;
       }
 
-      this._log("updating " + engine.name + " from " + updateURI.spec);
+      logConsole.debug("updating", engine.name, updateURI.spec);
       testEngine = new SearchEngine({
         uri: updateURI,
         isBuiltin: false,
       });
       testEngine._engineToUpdate = engine;
       testEngine._initFromURIAndLoad(updateURI);
     } else {
-      this._log("invalid updateURI");
+      logConsole.debug("invalid updateURI");
     }
 
     if (engine._iconUpdateURL) {
       // If we're updating the engine too, use the new engine object,
       // otherwise use the existing engine object.
       (testEngine || engine)._setIcon(engine._iconUpdateURL, true);
     }
   },
-
-  /**
-   * Outputs text to the JavaScript console as well as to stdout, if the search
-   * logging pref (browser.search.update.log) is set to true.
-   *
-   * @param {string} text
-   *   The message to log.
-   */
-  _log(text) {
-    if (
-      Services.prefs.getBoolPref(
-        SearchUtils.BROWSER_SEARCH_PREF + "update.log",
-        false
-      )
-    ) {
-      dump("*** Search update: " + text + "\n");
-      Services.console.logStringMessage(text);
-    }
-  },
 };
 
 XPCOMUtils.defineLazyServiceGetter(
   SearchService.prototype,
   "idleService",
   "@mozilla.org/widget/idleservice;1",
   "nsIIdleService"
 );
--- a/toolkit/components/search/SearchUtils.jsm
+++ b/toolkit/components/search/SearchUtils.jsm
@@ -11,16 +11,23 @@ var EXPORTED_SYMBOLS = ["SearchUtils"];
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   Services: "resource://gre/modules/Services.jsm",
 });
 
+XPCOMUtils.defineLazyGetter(this, "logConsole", () => {
+  return console.createInstance({
+    prefix: "SearchUtils",
+    maxLogLevel: SearchUtils.loggingEnabled ? "Debug" : "Warn",
+  });
+});
+
 const BROWSER_SEARCH_PREF = "browser.search.";
 
 var SearchUtils = {
   BROWSER_SEARCH_PREF,
 
   SETTINGS_KEY: "search-config",
 
   /**
@@ -91,43 +98,33 @@ var SearchUtils = {
    *   The engine to which the change applies.
    * @param {string} verb
    *   A verb describing the change.
    *
    * @see nsISearchService.idl
    */
   notifyAction(engine, verb) {
     if (Services.search.isInitialized) {
-      this.log('NOTIFY: Engine: "' + engine.name + '"; Verb: "' + verb + '"');
+      logConsole.debug("NOTIFY: Engine:", engine.name, "Verb:", verb);
       Services.obs.notifyObservers(engine, this.TOPIC_ENGINE_MODIFIED, verb);
     }
   },
 
   /**
-   * Outputs text to the JavaScript console.
-   *
-   * @param {string} text
-   *   The message to log.
-   */
-  log(text) {
-    if (SearchUtils.loggingEnabled) {
-      Services.console.logStringMessage(text);
-    }
-  },
-
-  /**
    * Logs the failure message (if browser.search.log is enabled) and throws.
    * @param {string} message
    *   A message to display
    * @param {number} resultCode
    *   The NS_ERROR_* value to throw.
    * @throws resultCode or NS_ERROR_INVALID_ARG if resultCode isn't specified.
    */
   fail(message, resultCode) {
-    this.log(message);
+    if (SearchUtils.loggingEnabled) {
+      Services.console.logStringMessage(message);
+    }
     throw Components.Exception(message, resultCode || Cr.NS_ERROR_INVALID_ARG);
   },
 
   /**
    * Wrapper function for nsIIOService::newURI.
    * @param {string} urlSpec
    *        The URL string from which to create an nsIURI.
    * @returns {nsIURI} an nsIURI object, or null if the creation of the URI failed.