Bug 1480327: Part 1 - Get rid of most of Log.jsm. r?Mossop draft
authorKris Maglione <maglione.k@gmail.com>
Wed, 01 Aug 2018 23:41:01 -0700
changeset 825740 65c94be2b7473940496285d354959b30eff5167c
parent 825665 915862a355e959c92c9ea7fb1cd7adbcf03bfb98
child 825741 e42c2933d26828bfbb2d5cefed63da4454162aaa
push id118157
push usermaglione.k@gmail.com
push dateThu, 02 Aug 2018 07:02:10 +0000
reviewersMossop
bugs1480327
milestone63.0a1
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);