Add console.log to logcat support to GeckoView draft
authorRandall Barker <rbarker@mozilla.com>
Tue, 17 Oct 2017 14:06:34 -0700
changeset 763467 0e3ea4ac0b9db6736cce373e5c5ae38203ca3e19
parent 763466 f72fd25e822fc7c8f625a0b6f659a7aaee4d4a41
child 763468 4b7cb33d8761520b275241c62c9c8dff8ef33fa7
push id101458
push userbmo:rbarker@mozilla.com
push dateMon, 05 Mar 2018 23:59:13 +0000
milestone60.0a1
Add console.log to logcat support to GeckoView MozReview-Commit-ID: CAjA3BIc1rm
mobile/android/chrome/geckoview/geckoview.js
mobile/android/modules/geckoview/ConsoleAPI.jsm
mobile/android/modules/geckoview/moz.build
--- a/mobile/android/chrome/geckoview/geckoview.js
+++ b/mobile/android/chrome/geckoview/geckoview.js
@@ -1,16 +1,17 @@
 /* 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/AppConstants.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://gre/modules/ConsoleAPI.jsm");
 
 ChromeUtils.defineModuleGetter(this, "EventDispatcher",
   "resource://gre/modules/Messaging.jsm");
 ChromeUtils.defineModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyGetter(this, "WindowEventDispatcher",
   () => EventDispatcher.for(window));
 
new file mode 100644
--- /dev/null
+++ b/mobile/android/modules/geckoview/ConsoleAPI.jsm
@@ -0,0 +1,103 @@
+/* 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";
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+this.EXPORTED_SYMBOLS = [];
+
+Services.obs.addObserver(
+{
+  observe: function observe(aMessage, aTopic, aData) {
+    aMessage = aMessage.wrappedJSObject;
+
+    let mappedArguments = Array.map(aMessage.arguments, this.formatResult, this);
+    let joinedArguments = Array.join(mappedArguments, " ");
+
+    if (aMessage.level == "error" || aMessage.level == "warn") {
+      let flag = (aMessage.level == "error" ? Ci.nsIScriptError.errorFlag : Ci.nsIScriptError.warningFlag);
+      let consoleMsg = Cc["@mozilla.org/scripterror;1"].createInstance(Ci.nsIScriptError);
+      consoleMsg.init(joinedArguments, null, null, 0, 0, flag, "content javascript");
+      Services.console.logMessage(consoleMsg);
+    } else if (aMessage.level == "trace") {
+      let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+      let args = aMessage.arguments;
+      let filename = this.abbreviateSourceURL(args[0].filename);
+      let functionName = args[0].functionName || bundle.GetStringFromName("stacktrace.anonymousFunction");
+      let lineNumber = args[0].lineNumber;
+
+      let body = bundle.formatStringFromName("stacktrace.outputMessage", [filename, functionName, lineNumber], 3);
+      body += "\n";
+      args.forEach(function(aFrame) {
+        let functionName = aFrame.functionName || bundle.GetStringFromName("stacktrace.anonymousFunction");
+        body += "  " + aFrame.filename + " :: " + functionName + " :: " + aFrame.lineNumber + "\n";
+      });
+
+      Services.console.logStringMessage(body);
+    } else if (aMessage.level == "time" && aMessage.arguments) {
+      let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+      let body = bundle.formatStringFromName("timer.start", [aMessage.arguments.name], 1);
+      Services.console.logStringMessage(body);
+    } else if (aMessage.level == "timeEnd" && aMessage.arguments) {
+      let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+      let body = bundle.formatStringFromName("timer.end", [aMessage.arguments.name, aMessage.arguments.duration], 2);
+      Services.console.logStringMessage(body);
+    } else if (["group", "groupCollapsed", "groupEnd"].indexOf(aMessage.level) != -1) {
+      // Do nothing yet
+    } else {
+      Services.console.logStringMessage(joinedArguments);
+    }
+  },
+
+  getResultType: function getResultType(aResult) {
+    let type = aResult === null ? "null" : typeof aResult;
+    if (type == "object" && aResult.constructor && aResult.constructor.name)
+      type = aResult.constructor.name;
+    return type.toLowerCase();
+  },
+
+  formatResult: function formatResult(aResult) {
+    let output = "";
+    let type = this.getResultType(aResult);
+    switch (type) {
+      case "string":
+      case "boolean":
+      case "date":
+      case "error":
+      case "number":
+      case "regexp":
+        output = aResult.toString();
+        break;
+      case "null":
+      case "undefined":
+        output = type;
+        break;
+      default:
+        output = aResult.toString();
+        break;
+    }
+
+    return output;
+  },
+
+  abbreviateSourceURL: function abbreviateSourceURL(aSourceURL) {
+    // Remove any query parameters.
+    let hookIndex = aSourceURL.indexOf("?");
+    if (hookIndex > -1)
+      aSourceURL = aSourceURL.substring(0, hookIndex);
+
+    // Remove a trailing "/".
+    if (aSourceURL[aSourceURL.length - 1] == "/")
+      aSourceURL = aSourceURL.substring(0, aSourceURL.length - 1);
+
+    // Remove all but the last path component.
+    let slashIndex = aSourceURL.lastIndexOf("/");
+    if (slashIndex > -1)
+      aSourceURL = aSourceURL.substring(slashIndex + 1);
+
+    return aSourceURL;
+  }
+}, "console-api-log-event");
--- a/mobile/android/modules/geckoview/moz.build
+++ b/mobile/android/modules/geckoview/moz.build
@@ -1,16 +1,17 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 EXTRA_JS_MODULES += [
     'AndroidLog.jsm',
+    'ConsoleAPI.jsm',
     'GeckoViewContent.jsm',
     'GeckoViewContentModule.jsm',
     'GeckoViewModule.jsm',
     'GeckoViewNavigation.jsm',
     'GeckoViewProgress.jsm',
     'GeckoViewRemoteDebugger.jsm',
     'GeckoViewScroll.jsm',
     'GeckoViewSettings.jsm',