Bug 1480327: Part 1 - Get rid of most of Log.jsm. r=Mossop
authorKris Maglione <maglione.k@gmail.com>
Wed, 01 Aug 2018 23:41:01 -0700
changeset 430461 ffcc2ae2ef834a3ebc36d18b35c5f2156dd04843
parent 430426 332b27e88d1199d89c419c9ae0fc276dfa4afaad
child 430462 af213f409e578dd4443962e4d60cb7f384103305
push id34406
push userncsoregi@mozilla.com
push dateWed, 08 Aug 2018 09:58:58 +0000
treeherdermozilla-central@17116905bc07 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMossop
bugs1480327
milestone63.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 1480327: Part 1 - Get rid of most of Log.jsm. r=Mossop MozReview-Commit-ID: JVKJtkLhCDS
mobile/android/modules/geckoview/GeckoViewUtils.jsm
services/common/logmanager.js
services/common/tests/unit/test_logmanager.js
toolkit/modules/Log.jsm
toolkit/modules/tests/xpcshell/test_Log.js
--- a/mobile/android/modules/geckoview/GeckoViewUtils.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewUtils.jsm
@@ -1,23 +1,76 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
+  AndroidLog: "resource://gre/modules/AndroidLog.jsm",
   EventDispatcher: "resource://gre/modules/Messaging.jsm",
   Log: "resource://gre/modules/Log.jsm",
   Services: "resource://gre/modules/Services.jsm",
 });
 
 var EXPORTED_SYMBOLS = ["GeckoViewUtils"];
 
+var {Appender, BasicFormatter} = Log;
+
+/**
+ * A formatter that does not prepend time/name/level information to messages,
+ * because those fields are logged separately when using the Android logger.
+ */
+function AndroidFormatter() {
+  BasicFormatter.call(this);
+}
+AndroidFormatter.prototype = Object.freeze({
+  __proto__: BasicFormatter.prototype,
+
+  format(message) {
+    return this.formatText(message);
+  },
+});
+
+/*
+ * AndroidAppender
+ * Logs to Android logcat using AndroidLog.jsm
+ */
+function AndroidAppender(aFormatter) {
+  Appender.call(this, aFormatter || new AndroidFormatter());
+  this._name = "AndroidAppender";
+}
+AndroidAppender.prototype = {
+  __proto__: Appender.prototype,
+
+  // Map log level to AndroidLog.foo method.
+  _mapping: {
+    [Log.Level.Fatal]:  "e",
+    [Log.Level.Error]:  "e",
+    [Log.Level.Warn]:   "w",
+    [Log.Level.Info]:   "i",
+    [Log.Level.Config]: "d",
+    [Log.Level.Debug]:  "d",
+    [Log.Level.Trace]:  "v",
+  },
+
+  append(aMessage) {
+    if (!aMessage) {
+      return;
+    }
+
+    // AndroidLog.jsm always prepends "Gecko" to the tag, so we strip any
+    // leading "Gecko" here. Also strip dots to save space.
+    const tag = aMessage.loggerName.replace(/^Gecko|\./g, "");
+    const msg = this._formatter.format(aMessage);
+    AndroidLog[this._mapping[aMessage.level]](tag, msg);
+  },
+};
+
 var GeckoViewUtils = {
   /**
    * Define a lazy getter that loads an object from external code, and
    * optionally handles observer and/or message manager notifications for the
    * object, so the object only loads when a notification is received.
    *
    * @param scope     Scope for holding the loaded object.
    * @param name      Name of the object to load.
@@ -350,17 +403,17 @@ var GeckoViewUtils = {
       });
     }
     return aScope;
   },
 
   get rootLogger() {
     if (!this._rootLogger) {
       this._rootLogger = Log.repository.getLogger("GeckoView");
-      this._rootLogger.addAppender(new Log.AndroidAppender());
+      this._rootLogger.addAppender(new AndroidAppender());
     }
     return this._rootLogger;
   },
 
   _log: function(aLogger, aLevel, aStrings, aExprs) {
     if (!Array.isArray(aStrings)) {
       const [, file, line] =
           (new Error()).stack.match(/.*\n.*\n.*@(.*):(\d+):/);
--- a/services/common/logmanager.js
+++ b/services/common/logmanager.js
@@ -37,33 +37,125 @@ const DEFAULT_MAX_ERROR_AGE = 20 * 24 * 
 // Singletons used by each instance.
 var formatter;
 var dumpAppender;
 var consoleAppender;
 
 // A set of all preference roots used by all instances.
 var allBranches = new Set();
 
+let {Appender} = Log;
+
+const ONE_BYTE = 1;
+const ONE_KILOBYTE = 1024 * ONE_BYTE;
+const ONE_MEGABYTE = 1024 * ONE_KILOBYTE;
+
+const STREAM_SEGMENT_SIZE = 4096;
+const PR_UINT32_MAX = 0xffffffff;
+
+/**
+ * Append to an nsIStorageStream
+ *
+ * This writes logging output to an in-memory stream which can later be read
+ * back as an nsIInputStream. It can be used to avoid expensive I/O operations
+ * during logging. Instead, one can periodically consume the input stream and
+ * e.g. write it to disk asynchronously.
+ */
+function StorageStreamAppender(formatter) {
+  Appender.call(this, formatter);
+  this._name = "StorageStreamAppender";
+}
+
+StorageStreamAppender.prototype = {
+  __proto__: Appender.prototype,
+
+  _converterStream: null, // holds the nsIConverterOutputStream
+  _outputStream: null,    // holds the underlying nsIOutputStream
+
+  _ss: null,
+
+  get outputStream() {
+    if (!this._outputStream) {
+      // First create a raw stream. We can bail out early if that fails.
+      this._outputStream = this.newOutputStream();
+      if (!this._outputStream) {
+        return null;
+      }
+
+      // Wrap the raw stream in an nsIConverterOutputStream. We can reuse
+      // the instance if we already have one.
+      if (!this._converterStream) {
+        this._converterStream = Cc["@mozilla.org/intl/converter-output-stream;1"]
+                                  .createInstance(Ci.nsIConverterOutputStream);
+      }
+      this._converterStream.init(this._outputStream, "UTF-8");
+    }
+    return this._converterStream;
+  },
+
+  newOutputStream: function newOutputStream() {
+    let ss = this._ss = Cc["@mozilla.org/storagestream;1"]
+                          .createInstance(Ci.nsIStorageStream);
+    ss.init(STREAM_SEGMENT_SIZE, PR_UINT32_MAX, null);
+    return ss.getOutputStream(0);
+  },
+
+  getInputStream: function getInputStream() {
+    if (!this._ss) {
+      return null;
+    }
+    return this._ss.newInputStream(0);
+  },
+
+  reset: function reset() {
+    if (!this._outputStream) {
+      return;
+    }
+    this.outputStream.close();
+    this._outputStream = null;
+    this._ss = null;
+  },
+
+  doAppend(formatted) {
+    if (!formatted) {
+      return;
+    }
+    try {
+      this.outputStream.writeString(formatted + "\n");
+    } catch (ex) {
+      if (ex.result == Cr.NS_BASE_STREAM_CLOSED) {
+        // The underlying output stream is closed, so let's open a new one
+        // and try again.
+        this._outputStream = null;
+      } try {
+          this.outputStream.writeString(formatted + "\n");
+      } catch (ex) {
+        // Ah well, we tried, but something seems to be hosed permanently.
+      }
+    }
+  }
+};
+
 // A storage appender that is flushable to a file on disk.  Policies for
 // when to flush, to what file, log rotation etc are up to the consumer
 // (although it does maintain a .sawError property to help the consumer decide
 // based on its policies)
 function FlushableStorageAppender(formatter) {
-  Log.StorageStreamAppender.call(this, formatter);
+  StorageStreamAppender.call(this, formatter);
   this.sawError = false;
 }
 
 FlushableStorageAppender.prototype = {
-  __proto__: Log.StorageStreamAppender.prototype,
+  __proto__: StorageStreamAppender.prototype,
 
   append(message) {
     if (message.level >= Log.Level.Error) {
       this.sawError = true;
     }
-    Log.StorageStreamAppender.prototype.append.call(this, message);
+    StorageStreamAppender.prototype.append.call(this, message);
   },
 
   reset() {
     Log.StorageStreamAppender.prototype.reset.call(this);
     this.sawError = false;
   },
 
   // Flush the current stream to a file. Somewhat counter-intuitively, you
@@ -128,16 +220,18 @@ FlushableStorageAppender.prototype = {
 };
 
 // The public LogManager object.
 function LogManager(prefRoot, logNames, logFilePrefix) {
   this._prefObservers = [];
   this.init(prefRoot, logNames, logFilePrefix);
 }
 
+LogManager.StorageStreamAppender = StorageStreamAppender;
+
 LogManager.prototype = {
   _cleaningUpFileLogs: false,
 
   init(prefRoot, logNames, logFilePrefix) {
     if (prefRoot instanceof Preferences) {
       this._prefs = prefRoot;
     } else {
       this._prefs = new Preferences(prefRoot);
--- a/services/common/tests/unit/test_logmanager.js
+++ b/services/common/tests/unit/test_logmanager.js
@@ -10,17 +10,17 @@ ChromeUtils.import("resource://gre/modul
 
 // Returns an array of [consoleAppender, dumpAppender, [fileAppenders]] for
 // the specified log.  Note that fileAppenders will usually have length=1
 function getAppenders(log) {
   let capps = log.appenders.filter(app => app instanceof Log.ConsoleAppender);
   equal(capps.length, 1, "should only have one console appender");
   let dapps = log.appenders.filter(app => app instanceof Log.DumpAppender);
   equal(dapps.length, 1, "should only have one dump appender");
-  let fapps = log.appenders.filter(app => app instanceof Log.StorageStreamAppender);
+  let fapps = log.appenders.filter(app => app instanceof LogManager.StorageStreamAppender);
   return [capps[0], dapps[0], fapps];
 }
 
 // Test that the correct thing happens when no prefs exist for the log manager.
 add_task(async function test_noPrefs() {
   // tell the log manager to init with a pref branch that doesn't exist.
   let lm = new LogManager("no-such-branch.", ["TestLog"], "test");
 
--- a/toolkit/modules/Log.jsm
+++ b/toolkit/modules/Log.jsm
@@ -1,27 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["Log"];
 
-const ONE_BYTE = 1;
-const ONE_KILOBYTE = 1024 * ONE_BYTE;
-const ONE_MEGABYTE = 1024 * ONE_KILOBYTE;
-
-const STREAM_SEGMENT_SIZE = 4096;
-const PR_UINT32_MAX = 0xffffffff;
-
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetters(this, {
-  AndroidLog: "resource://gre/modules/AndroidLog.jsm", // Only used on Android.
-  OS: "resource://gre/modules/osfile.jsm",
   Services: "resource://gre/modules/Services.jsm",
   Task: "resource://gre/modules/Task.jsm",
 });
 const INTERNAL_FIELDS = new Set(["_level", "_message", "_time", "_namespace"]);
 
 
 /*
  * Dump a message everywhere we can if we have a failure.
@@ -72,66 +63,23 @@ var Log = {
     delete Log.repository;
     Log.repository = value;
   },
 
   LogMessage,
   Logger,
   LoggerRepository,
 
-  Formatter,
   BasicFormatter,
-  MessageOnlyFormatter,
-  StructuredFormatter,
 
   Appender,
   DumpAppender,
   ConsoleAppender,
-  StorageStreamAppender,
-  AndroidAppender,
-
-  FileAppender,
-  BoundedFileAppender,
 
   ParameterFormatter,
-  // Logging helper:
-  // let logger = Log.repository.getLogger("foo");
-  // logger.info(Log.enumerateInterfaces(someObject).join(","));
-  enumerateInterfaces: function Log_enumerateInterfaces(aObject) {
-    let interfaces = [];
-
-    for (let i in Ci) {
-      try {
-        aObject.QueryInterface(Ci[i]);
-        interfaces.push(i);
-      } catch (ex) {}
-    }
-
-    return interfaces;
-  },
-
-  // Logging helper:
-  // let logger = Log.repository.getLogger("foo");
-  // logger.info(Log.enumerateProperties(someObject).join(","));
-  enumerateProperties(aObject, aExcludeComplexTypes) {
-    let properties = [];
-
-    for (let p in aObject) {
-      try {
-        if (aExcludeComplexTypes &&
-            (typeof(aObject[p]) == "object" || typeof(aObject[p]) == "function"))
-          continue;
-        properties.push(p + " = " + aObject[p]);
-      } catch (ex) {
-        properties.push(p + " = " + ex);
-      }
-    }
-
-    return properties;
-  },
 
   _formatError: function _formatError(e) {
     let result = e.toString();
     if (e.fileName) {
       result +=  " (" + e.fileName;
       if (e.lineNumber) {
         result += ":" + e.lineNumber;
       }
@@ -150,17 +98,17 @@ var Log = {
       return "" + e;
     }
     if (e instanceof Ci.nsIException) {
       return e.toString() + " " + Log.stackTrace(e);
     } else if (isError(e)) {
       return Log._formatError(e);
     }
     // else
-    let message = e.message ? e.message : e;
+    let message = e.message || e;
     return message + " " + Log.stackTrace(e);
   },
 
   stackTrace: function stackTrace(e) {
     // Wrapped nsIException
     if (e.location) {
       let frame = e.location;
       let output = [];
@@ -374,55 +322,16 @@ Logger.prototype = {
     let index = this.ownAppenders.indexOf(appender);
     if (index == -1) {
       return;
     }
     this.ownAppenders.splice(index, 1);
     this.updateAppenders();
   },
 
-  /**
-   * Logs a structured message object.
-   *
-   * @param action
-   *        (string) A message action, one of a set of actions known to the
-   *          log consumer.
-   * @param params
-   *        (object) Parameters to be included in the message.
-   *          If _level is included as a key and the corresponding value
-   *          is a number or known level name, the message will be logged
-   *          at the indicated level. If _message is included as a key, the
-   *          value is used as the descriptive text for the message.
-   */
-  logStructured(action, params) {
-    if (!action) {
-      throw "An action is required when logging a structured message.";
-    }
-    if (!params) {
-      this.log(this.level, undefined, {"action": action});
-      return;
-    }
-    if (typeof(params) != "object") {
-      throw "The params argument is required to be an object.";
-    }
-
-    let level = params._level;
-    if (level) {
-      let ulevel = level.toUpperCase();
-      if (ulevel in Log.Level.Numbers) {
-        level = Log.Level.Numbers[ulevel];
-      }
-    } else {
-      level = this.level;
-    }
-
-    params.action = action;
-    this.log(level, params._message, params);
-  },
-
   _unpackTemplateLiteral(string, params) {
     if (!Array.isArray(params)) {
       // Regular log() call.
       return [string, params];
     }
 
     if (!Array.isArray(string)) {
       // Not using template literal. However params was packed into an array by
@@ -591,35 +500,26 @@ LoggerRepository.prototype = {
     };
     return proxy;
   },
 };
 
 /*
  * Formatters
  * These massage a LogMessage into whatever output is desired.
- * BasicFormatter and StructuredFormatter are implemented here.
  */
 
-// Abstract formatter
-function Formatter() {}
-Formatter.prototype = {
-  format: function Formatter_format(message) {}
-};
-
 // Basic formatter that doesn't do anything fancy.
 function BasicFormatter(dateFormat) {
   if (dateFormat) {
     this.dateFormat = dateFormat;
   }
   this.parameterFormatter = new ParameterFormatter();
 }
 BasicFormatter.prototype = {
-  __proto__: Formatter.prototype,
-
   /**
    * Format the text of a message with optional parameters.
    * If the text contains ${identifier}, replace that with
    * the value of params[identifier]; if ${}, replace that with
    * the entire params object. If no params have been substituted
    * into the text, format the entire object and append that
    * to the message.
    */
@@ -670,74 +570,16 @@ BasicFormatter.prototype = {
     return message.time + "\t" +
       message.loggerName + "\t" +
       message.levelDesc + "\t" +
       this.formatText(message);
   }
 };
 
 /**
- * A formatter that only formats the string message component.
- */
-function MessageOnlyFormatter() {
-}
-MessageOnlyFormatter.prototype = Object.freeze({
-  __proto__: Formatter.prototype,
-
-  format(message) {
-    return message.message;
-  },
-});
-
-// Structured formatter that outputs JSON based on message data.
-// This formatter will format unstructured messages by supplying
-// default values.
-function StructuredFormatter() { }
-StructuredFormatter.prototype = {
-  __proto__: Formatter.prototype,
-
-  format(logMessage) {
-    let output = {
-      _time: logMessage.time,
-      _namespace: logMessage.loggerName,
-      _level: logMessage.levelDesc
-    };
-
-    for (let key in logMessage.params) {
-      output[key] = logMessage.params[key];
-    }
-
-    if (!output.action) {
-      output.action = "UNKNOWN";
-    }
-
-    if (!output._message && logMessage.message) {
-      output._message = logMessage.message;
-    }
-
-    return JSON.stringify(output);
-  }
-};
-
-/**
- * A formatter that does not prepend time/name/level information to messages,
- * because those fields are logged separately when using the Android logger.
- */
-function AndroidFormatter() {
-  BasicFormatter.call(this);
-}
-AndroidFormatter.prototype = Object.freeze({
-  __proto__: BasicFormatter.prototype,
-
-  format(message) {
-    return this.formatText(message);
-  },
-});
-
-/**
  * Test an object to see if it is a Mozilla JS Error.
  */
 function isError(aObj) {
   return (aObj && typeof(aObj) == "object" && "name" in aObj && "message" in aObj &&
           "fileName" in aObj && "lineNumber" in aObj && "stack" in aObj);
 }
 
 /*
@@ -794,31 +636,30 @@ ParameterFormatter.prototype = {
 /*
  * Appenders
  * These can be attached to Loggers to log to different places
  * Simply subclass and override doAppend to implement a new one
  */
 
 function Appender(formatter) {
   this._name = "Appender";
-  this._formatter = formatter ? formatter : new BasicFormatter();
+  this._formatter = formatter || new BasicFormatter();
 }
 Appender.prototype = {
   level: Log.Level.All,
 
   append: function App_append(message) {
     if (message) {
       this.doAppend(this._formatter.format(message));
     }
   },
   toString: function App_toString() {
     return this._name + " [level=" + this.level +
       ", formatter=" + this._formatter + "]";
   },
-  doAppend: function App_doAppend(formatted) {}
 };
 
 /*
  * DumpAppender
  * Logs to standard out
  */
 
 function DumpAppender(formatter) {
@@ -856,245 +697,8 @@ ConsoleAppender.prototype = {
       this.doAppend(m);
     }
   },
 
   doAppend: function CApp_doAppend(formatted) {
     Services.console.logStringMessage(formatted);
   }
 };
-
-/**
- * Append to an nsIStorageStream
- *
- * This writes logging output to an in-memory stream which can later be read
- * back as an nsIInputStream. It can be used to avoid expensive I/O operations
- * during logging. Instead, one can periodically consume the input stream and
- * e.g. write it to disk asynchronously.
- */
-function StorageStreamAppender(formatter) {
-  Appender.call(this, formatter);
-  this._name = "StorageStreamAppender";
-}
-
-StorageStreamAppender.prototype = {
-  __proto__: Appender.prototype,
-
-  _converterStream: null, // holds the nsIConverterOutputStream
-  _outputStream: null,    // holds the underlying nsIOutputStream
-
-  _ss: null,
-
-  get outputStream() {
-    if (!this._outputStream) {
-      // First create a raw stream. We can bail out early if that fails.
-      this._outputStream = this.newOutputStream();
-      if (!this._outputStream) {
-        return null;
-      }
-
-      // Wrap the raw stream in an nsIConverterOutputStream. We can reuse
-      // the instance if we already have one.
-      if (!this._converterStream) {
-        this._converterStream = Cc["@mozilla.org/intl/converter-output-stream;1"]
-                                  .createInstance(Ci.nsIConverterOutputStream);
-      }
-      this._converterStream.init(this._outputStream, "UTF-8");
-    }
-    return this._converterStream;
-  },
-
-  newOutputStream: function newOutputStream() {
-    let ss = this._ss = Cc["@mozilla.org/storagestream;1"]
-                          .createInstance(Ci.nsIStorageStream);
-    ss.init(STREAM_SEGMENT_SIZE, PR_UINT32_MAX, null);
-    return ss.getOutputStream(0);
-  },
-
-  getInputStream: function getInputStream() {
-    if (!this._ss) {
-      return null;
-    }
-    return this._ss.newInputStream(0);
-  },
-
-  reset: function reset() {
-    if (!this._outputStream) {
-      return;
-    }
-    this.outputStream.close();
-    this._outputStream = null;
-    this._ss = null;
-  },
-
-  doAppend(formatted) {
-    if (!formatted) {
-      return;
-    }
-    try {
-      this.outputStream.writeString(formatted + "\n");
-    } catch (ex) {
-      if (ex.result == Cr.NS_BASE_STREAM_CLOSED) {
-        // The underlying output stream is closed, so let's open a new one
-        // and try again.
-        this._outputStream = null;
-      } try {
-          this.outputStream.writeString(formatted + "\n");
-      } catch (ex) {
-        // Ah well, we tried, but something seems to be hosed permanently.
-      }
-    }
-  }
-};
-
-/**
- * File appender
- *
- * Writes output to file using OS.File.
- */
-function FileAppender(path, formatter) {
-  Appender.call(this, formatter);
-  this._name = "FileAppender";
-  this._encoder = new TextEncoder();
-  this._path = path;
-  this._file = null;
-  this._fileReadyPromise = null;
-
-  // This is a promise exposed for testing/debugging the logger itself.
-  this._lastWritePromise = null;
-}
-
-FileAppender.prototype = {
-  __proto__: Appender.prototype,
-
-  _openFile() {
-    return (async () => {
-      try {
-        this._file = await OS.File.open(this._path,
-                                        {truncate: true});
-      } catch (err) {
-        if (err instanceof OS.File.Error) {
-          this._file = null;
-        } else {
-          throw err;
-        }
-      }
-    })();
-  },
-
-  _getFile() {
-    if (!this._fileReadyPromise) {
-      this._fileReadyPromise = this._openFile();
-    }
-
-    return this._fileReadyPromise;
-  },
-
-  doAppend(formatted) {
-    let array = this._encoder.encode(formatted + "\n");
-    if (this._file) {
-      this._lastWritePromise = this._file.write(array);
-    } else {
-      this._lastWritePromise = this._getFile().then(_ => {
-        this._fileReadyPromise = null;
-        if (this._file) {
-          return this._file.write(array);
-        }
-        return undefined;
-      });
-    }
-  },
-
-  reset() {
-    let fileClosePromise = this._file.close();
-    return fileClosePromise.then(_ => {
-      this._file = null;
-      return OS.File.remove(this._path);
-    });
-  }
-};
-
-/**
- * Bounded File appender
- *
- * Writes output to file using OS.File. After the total message size
- * (as defined by formatted.length) exceeds maxSize, existing messages
- * will be discarded, and subsequent writes will be appended to a new log file.
- */
-function BoundedFileAppender(path, formatter, maxSize = 2 * ONE_MEGABYTE) {
-  FileAppender.call(this, path, formatter);
-  this._name = "BoundedFileAppender";
-  this._size = 0;
-  this._maxSize = maxSize;
-  this._closeFilePromise = null;
-}
-
-BoundedFileAppender.prototype = {
-  __proto__: FileAppender.prototype,
-
-  doAppend(formatted) {
-    if (!this._removeFilePromise) {
-      if (this._size < this._maxSize) {
-        this._size += formatted.length;
-        return FileAppender.prototype.doAppend.call(this, formatted);
-      }
-      this._removeFilePromise = this.reset();
-    }
-    this._removeFilePromise.then(_ => {
-      this._removeFilePromise = null;
-      this.doAppend(formatted);
-    });
-    return undefined;
-  },
-
-  reset() {
-    let fileClosePromise;
-    if (this._fileReadyPromise) {
-      // An attempt to open the file may still be in progress.
-      fileClosePromise = this._fileReadyPromise.then(_ => {
-        return this._file.close();
-      });
-    } else {
-      fileClosePromise = this._file.close();
-    }
-
-    return fileClosePromise.then(_ => {
-      this._size = 0;
-      this._file = null;
-      return OS.File.remove(this._path);
-    });
-  }
-};
-
-/*
- * AndroidAppender
- * Logs to Android logcat using AndroidLog.jsm
- */
-function AndroidAppender(aFormatter) {
-  Appender.call(this, aFormatter || new AndroidFormatter());
-  this._name = "AndroidAppender";
-}
-AndroidAppender.prototype = {
-  __proto__: Appender.prototype,
-
-  // Map log level to AndroidLog.foo method.
-  _mapping: {
-    [Log.Level.Fatal]:  "e",
-    [Log.Level.Error]:  "e",
-    [Log.Level.Warn]:   "w",
-    [Log.Level.Info]:   "i",
-    [Log.Level.Config]: "d",
-    [Log.Level.Debug]:  "d",
-    [Log.Level.Trace]:  "v",
-  },
-
-  append(aMessage) {
-    if (!aMessage) {
-      return;
-    }
-
-    // AndroidLog.jsm always prepends "Gecko" to the tag, so we strip any
-    // leading "Gecko" here. Also strip dots to save space.
-    const tag = aMessage.loggerName.replace(/^Gecko|\./g, "");
-    const msg = this._formatter.format(aMessage);
-    AndroidLog[this._mapping[aMessage.level]](tag, msg);
-  },
-};
--- a/toolkit/modules/tests/xpcshell/test_Log.js
+++ b/toolkit/modules/tests/xpcshell/test_Log.js
@@ -59,38 +59,16 @@ add_task(function test_Logger_parent() {
   grandparentLog.addAppender(gpAppender);
   childLog.info("child info test");
   Log.repository.rootLogger.info("this shouldn't show up in gpAppender");
 
   Assert.equal(gpAppender.messages.length, 1);
   Assert.ok(gpAppender.messages[0].indexOf("child info test") > 0);
 });
 
-add_test(function test_LoggerWithMessagePrefix() {
-  let log = Log.repository.getLogger("test.logger.prefix");
-  let appender = new MockAppender(new Log.MessageOnlyFormatter());
-  log.addAppender(appender);
-
-  let prefixed = Log.repository.getLoggerWithMessagePrefix(
-    "test.logger.prefix", "prefix: ");
-
-  log.warn("no prefix");
-  prefixed.warn("with prefix");
-  prefixed.warn `with prefix`;
-
-  Assert.equal(appender.messages.length, 3, "3 messages were logged.");
-  Assert.deepEqual(appender.messages, [
-    "no prefix",
-    "prefix: with prefix",
-    "prefix: with prefix",
-  ], "Prefix logger works.");
-
-  run_next_test();
-});
-
 /*
  * A utility method for checking object equivalence.
  * Fields with a reqular expression value in expected will be tested
  * against the corresponding value in actual. Otherwise objects
  * are expected to have the same keys and equal values.
  */
 function checkObjects(expected, actual) {
   Assert.ok(expected instanceof Object);
@@ -106,235 +84,16 @@ function checkObjects(expected, actual) 
     }
   }
 
   for (let key in actual) {
     Assert.notEqual(expected[key], undefined);
   }
 }
 
-add_task(function test_StructuredLogCommands() {
-  let appender = new MockAppender(new Log.StructuredFormatter());
-  let logger = Log.repository.getLogger("test.StructuredOutput");
-  logger.addAppender(appender);
-  logger.level = Log.Level.Info;
-
-  logger.logStructured("test_message", {_message: "message string one"});
-  logger.logStructured("test_message", {_message: "message string two",
-                                        _level: "ERROR",
-                                        source_file: "test_Log.js"});
-  logger.logStructured("test_message");
-  logger.logStructured("test_message", {source_file: "test_Log.js",
-                                        message_position: 4});
-
-  let messageOne = {"_time": /\d+/,
-                    "_namespace": "test.StructuredOutput",
-                    "_level": "INFO",
-                    "_message": "message string one",
-                    "action": "test_message"};
-
-  let messageTwo = {"_time": /\d+/,
-                    "_namespace": "test.StructuredOutput",
-                    "_level": "ERROR",
-                    "_message": "message string two",
-                    "action": "test_message",
-                    "source_file": "test_Log.js"};
-
-  let messageThree = {"_time": /\d+/,
-                      "_namespace": "test.StructuredOutput",
-                      "_level": "INFO",
-                      "action": "test_message"};
-
-  let messageFour = {"_time": /\d+/,
-                     "_namespace": "test.StructuredOutput",
-                     "_level": "INFO",
-                     "action": "test_message",
-                     "source_file": "test_Log.js",
-                     "message_position": 4};
-
-  checkObjects(messageOne, JSON.parse(appender.messages[0]));
-  checkObjects(messageTwo, JSON.parse(appender.messages[1]));
-  checkObjects(messageThree, JSON.parse(appender.messages[2]));
-  checkObjects(messageFour, JSON.parse(appender.messages[3]));
-
-  let errored = false;
-  try {
-    logger.logStructured("", {_message: "invalid message"});
-  } catch (e) {
-    errored = true;
-    Assert.equal(e, "An action is required when logging a structured message.");
-  } finally {
-    Assert.ok(errored);
-  }
-
-  errored = false;
-  try {
-    logger.logStructured("message_action", "invalid params");
-  } catch (e) {
-    errored = true;
-    Assert.equal(e, "The params argument is required to be an object.");
-  } finally {
-    Assert.ok(errored);
-  }
-
-  // Logging with unstructured interface should produce the same messages
-  // as the structured interface for these cases.
-  appender = new MockAppender(new Log.StructuredFormatter());
-  logger = Log.repository.getLogger("test.StructuredOutput1");
-  messageOne._namespace = "test.StructuredOutput1";
-  messageTwo._namespace = "test.StructuredOutput1";
-  logger.addAppender(appender);
-  logger.level = Log.Level.All;
-  logger.info("message string one", {action: "test_message"});
-  logger.error("message string two", {action: "test_message",
-                                      source_file: "test_Log.js"});
-
-  checkObjects(messageOne, JSON.parse(appender.messages[0]));
-  checkObjects(messageTwo, JSON.parse(appender.messages[1]));
-});
-
-add_task(function test_StorageStreamAppender() {
-  let appender = new Log.StorageStreamAppender(testFormatter);
-  Assert.equal(appender.getInputStream(), null);
-
-  // Log to the storage stream and verify the log was written and can be
-  // read back.
-  let logger = Log.repository.getLogger("test.StorageStreamAppender");
-  logger.addAppender(appender);
-  logger.info("OHAI");
-  let inputStream = appender.getInputStream();
-  let data = NetUtil.readInputStreamToString(inputStream,
-                                             inputStream.available());
-  Assert.equal(data, "test.StorageStreamAppender\tINFO\tOHAI\n");
-
-  // We can read it again even.
-  let sndInputStream = appender.getInputStream();
-  let sameData = NetUtil.readInputStreamToString(sndInputStream,
-                                                 sndInputStream.available());
-  Assert.equal(data, sameData);
-
-  // Reset the appender and log some more.
-  appender.reset();
-  Assert.equal(appender.getInputStream(), null);
-  logger.debug("wut?!?");
-  inputStream = appender.getInputStream();
-  data = NetUtil.readInputStreamToString(inputStream,
-                                         inputStream.available());
-  Assert.equal(data, "test.StorageStreamAppender\tDEBUG\twut?!?\n");
-});
-
-function fileContents(path) {
-  let decoder = new TextDecoder();
-  return OS.File.read(path).then(array => {
-    return decoder.decode(array);
-  });
-}
-
-add_task(async function test_FileAppender() {
-  // This directory does not exist yet
-  let dir = OS.Path.join(do_get_profile().path, "test_Log");
-  Assert.equal(false, await OS.File.exists(dir));
-  let path = OS.Path.join(dir, "test_FileAppender");
-  let appender = new Log.FileAppender(path, testFormatter);
-  let logger = Log.repository.getLogger("test.FileAppender");
-  logger.addAppender(appender);
-
-  // Logging to a file that can't be created won't do harm.
-  Assert.equal(false, await OS.File.exists(path));
-  logger.info("OHAI!");
-
-  await OS.File.makeDir(dir);
-  logger.info("OHAI");
-  await appender._lastWritePromise;
-
-  Assert.equal((await fileContents(path)),
-               "test.FileAppender\tINFO\tOHAI\n");
-
-  logger.info("OHAI");
-  await appender._lastWritePromise;
-
-  Assert.equal((await fileContents(path)),
-               "test.FileAppender\tINFO\tOHAI\n" +
-               "test.FileAppender\tINFO\tOHAI\n");
-
-  // Reset the appender and log some more.
-  await appender.reset();
-  Assert.equal(false, await OS.File.exists(path));
-
-  logger.debug("O RLY?!?");
-  await appender._lastWritePromise;
-  Assert.equal((await fileContents(path)),
-               "test.FileAppender\tDEBUG\tO RLY?!?\n");
-
-  await appender.reset();
-  logger.debug("1");
-  logger.info("2");
-  logger.info("3");
-  logger.info("4");
-  logger.info("5");
-  // Waiting on only the last promise should account for all of these.
-  await appender._lastWritePromise;
-
-  // Messages ought to be logged in order.
-  Assert.equal((await fileContents(path)),
-               "test.FileAppender\tDEBUG\t1\n" +
-               "test.FileAppender\tINFO\t2\n" +
-               "test.FileAppender\tINFO\t3\n" +
-               "test.FileAppender\tINFO\t4\n" +
-               "test.FileAppender\tINFO\t5\n");
-});
-
-add_task(async function test_BoundedFileAppender() {
-  let dir = OS.Path.join(do_get_profile().path, "test_Log");
-
-  if (!(await OS.File.exists(dir))) {
-    await OS.File.makeDir(dir);
-  }
-
-  let path = OS.Path.join(dir, "test_BoundedFileAppender");
-  // This appender will hold about two lines at a time.
-  let appender = new Log.BoundedFileAppender(path, testFormatter, 40);
-  let logger = Log.repository.getLogger("test.BoundedFileAppender");
-  logger.addAppender(appender);
-
-  logger.info("ONE");
-  logger.info("TWO");
-  await appender._lastWritePromise;
-
-  Assert.equal((await fileContents(path)),
-               "test.BoundedFileAppender\tINFO\tONE\n" +
-               "test.BoundedFileAppender\tINFO\tTWO\n");
-
-  logger.info("THREE");
-  logger.info("FOUR");
-
-  Assert.notEqual(appender._removeFilePromise, undefined);
-  await appender._removeFilePromise;
-  await appender._lastWritePromise;
-
-  Assert.equal((await fileContents(path)),
-               "test.BoundedFileAppender\tINFO\tTHREE\n" +
-               "test.BoundedFileAppender\tINFO\tFOUR\n");
-
-  await appender.reset();
-  logger.info("ONE");
-  logger.info("TWO");
-  logger.info("THREE");
-  logger.info("FOUR");
-
-  Assert.notEqual(appender._removeFilePromise, undefined);
-  await appender._removeFilePromise;
-  await appender._lastWritePromise;
-
-  Assert.equal((await fileContents(path)),
-               "test.BoundedFileAppender\tINFO\tTHREE\n" +
-               "test.BoundedFileAppender\tINFO\tFOUR\n");
-
-});
-
 /*
  * Test parameter formatting.
  */
 add_task(async function log_message_with_params() {
   let formatter = new Log.BasicFormatter();
 
   function formatMessage(text, params) {
     let full = formatter.format(new Log.LogMessage("test.logger", Log.Level.Warn, text, params));
@@ -507,41 +266,16 @@ add_task(async function test_log_err_onl
     log.error(e);
     let msg = appender.messages.pop();
     Assert.equal(msg.message, null);
     Assert.equal(msg.params, e);
   }
 });
 
 /*
- * Test logStructured() messages through basic formatter.
- */
-add_task(async function test_structured_basic() {
-  let log = Log.repository.getLogger("test.logger");
-  let appender = new MockAppender(new Log.BasicFormatter());
-
-  log.level = Log.Level.Info;
-  appender.level = Log.Level.Info;
-  log.addAppender(appender);
-
-  // A structured entry with no _message is treated the same as log./level/(null, params)
-  // except the 'action' field is added to the object.
-  log.logStructured("action", {data: "structure"});
-  Assert.equal(appender.messages.length, 1);
-  Assert.ok(appender.messages[0].includes('{"data":"structure","action":"action"}'));
-
-  // A structured entry with _message and substitution is treated the same as
-  // log./level/(null, params).
-  log.logStructured("action", {_message: "Structured sub ${data}", data: "structure"});
-  Assert.equal(appender.messages.length, 2);
-  info(appender.messages[1]);
-  Assert.ok(appender.messages[1].includes("Structured sub structure"));
-});
-
-/*
  * Test that all the basic logger methods pass the message and params through to the appender.
  */
 add_task(async function log_message_with_params() {
   let log = Log.repository.getLogger("error.logger");
   let mockFormatter = { format: msg => msg };
   let appender = new MockAppender(mockFormatter);
   log.addAppender(appender);