Bug 1452200 - 1c. Inject logging functions into GeckoView JS modules; r=snorp

Inject new logging functions, "debug" and "warn", into each GeckoView JS
module that geckoview.js loads. Also do the same thing for frame script
classes that extend from GeckoViewContentModule.

The new logging functions are used with template literals (debug `hello
${foo} world`;), which are lazily evaluated, so disabled logs don't use
as many CPU cycles. They can also be easily enabled/disabled.

MozReview-Commit-ID: 7ZfYAMrcCyU

--HG--
extra : rebase_source : 8a830f29ea1cabcdc5055fc86c9880a5216aa456
This commit is contained in:
Jim Chen 2018-04-15 14:53:29 -04:00
Родитель 48885775a4
Коммит 9fd43f9378
12 изменённых файлов: 143 добавлений и 14 удалений

Просмотреть файл

@ -4,6 +4,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
/* global debug:false, warn:false */
GeckoViewUtils.initLogging("GeckoView.ErrorPageEventHandler", this);
ChromeUtils.defineModuleGetter(this, "SSLExceptions",
"resource://gre/modules/SSLExceptions.jsm");

Просмотреть файл

@ -197,4 +197,5 @@ class GeckoViewContent extends GeckoViewContentModule {
}
}
var contentListener = new GeckoViewContent("GeckoViewContent", this);
let {debug, warn} = GeckoViewContent.initLogging("GeckoViewContent");
let module = GeckoViewContent.create(this);

Просмотреть файл

@ -71,4 +71,5 @@ class GeckoViewContentSettings extends GeckoViewContentModule {
}
}
var settings = new GeckoViewContentSettings("GeckoViewSettings", this);
let {debug, warn} = GeckoViewContentSettings.initLogging("GeckoViewSettings");
let module = GeckoViewContentSettings.create(this);

Просмотреть файл

@ -47,4 +47,5 @@ class GeckoViewNavigationContent extends GeckoViewContentModule {
}
}
var navigationListener = new GeckoViewNavigationContent("GeckoViewNavigation", this);
let {debug, warn} = GeckoViewNavigationContent.initLogging("GeckoViewNavigation");
let module = GeckoViewNavigationContent.create(this);

Просмотреть файл

@ -43,4 +43,6 @@ class GeckoViewScrollContent extends GeckoViewContentModule {
}
}
}
var scrollListener = new GeckoViewScrollContent("GeckoViewScroll", this);
let {debug, warn} = GeckoViewScrollContent.initLogging("GeckoViewScroll");
let module = GeckoViewScrollContent.create(this);

Просмотреть файл

@ -258,5 +258,6 @@ class GeckoViewSelectionActionContent extends GeckoViewContentModule {
}
}
var selectionActionListener =
new GeckoViewSelectionActionContent("GeckoViewSelectionAction", this);
let {debug, warn} =
GeckoViewSelectionActionContent.initLogging("GeckoViewSelectionAction");
let module = GeckoViewSelectionActionContent.create(this);

Просмотреть файл

@ -4,13 +4,14 @@
"use strict";
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "EventDispatcher",
"resource://gre/modules/Messaging.jsm");
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
EventDispatcher: "resource://gre/modules/Messaging.jsm",
GeckoViewUtils: "resource://gre/modules/GeckoViewUtils.jsm",
Services: "resource://gre/modules/Services.jsm",
});
XPCOMUtils.defineLazyGetter(this, "WindowEventDispatcher",
() => EventDispatcher.for(window));
@ -32,8 +33,11 @@ var ModuleManager = {
add: function(aResource, aType, ...aArgs) {
this.remove(aType);
let scope = {};
ChromeUtils.import(aResource, scope);
const scope = {};
const global = ChromeUtils.import(aResource, scope);
const tag = aType.replace("GeckoView", "GeckoView.");
GeckoViewUtils.initLogging(tag, global);
this.modules.set(aType, new scope[aType](
aType, window, this.browser, WindowEventDispatcher, ...aArgs
@ -58,6 +62,8 @@ function createBrowser() {
}
function startup() {
GeckoViewUtils.initLogging("GeckoView.XUL", window);
const browser = createBrowser();
ModuleManager.init(browser);

Просмотреть файл

@ -5,6 +5,10 @@
"use strict";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
/* global debug:false, warn:false */
GeckoViewUtils.initLogging("GeckoView.ExternalAppService", this);
ChromeUtils.defineModuleGetter(this, "EventDispatcher",
"resource://gre/modules/Messaging.jsm");

Просмотреть файл

@ -0,0 +1,8 @@
"use strict";
module.exports = {
"globals": {
"debug": false,
"warn": false,
},
};

Просмотреть файл

@ -7,6 +7,9 @@
var EXPORTED_SYMBOLS = ["GeckoViewContentModule"];
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
GeckoViewUtils.initLogging("GeckoView.Module.[C]", this);
ChromeUtils.defineModuleGetter(this, "EventDispatcher",
"resource://gre/modules/Messaging.jsm");
@ -20,6 +23,16 @@ XPCOMUtils.defineLazyGetter(this, "dump", () =>
// }
class GeckoViewContentModule {
static initLogging(aModuleName) {
this._moduleName = aModuleName;
const tag = aModuleName.replace("GeckoView", "GeckoView.") + ".[C]";
return GeckoViewUtils.initLogging(tag, {});
}
static create(aGlobal, aModuleName) {
return new this(aModuleName || this._moduleName, aGlobal);
}
constructor(aModuleName, aMessageManager) {
this.moduleName = aModuleName;
this.messageManager = aMessageManager;

Просмотреть файл

@ -7,6 +7,9 @@
var EXPORTED_SYMBOLS = ["GeckoViewModule"];
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
GeckoViewUtils.initLogging("GeckoView.Module", this);
XPCOMUtils.defineLazyGetter(this, "dump", () =>
ChromeUtils.import("resource://gre/modules/AndroidLog.jsm",

Просмотреть файл

@ -6,8 +6,9 @@
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
Services: "resource://gre/modules/Services.jsm",
EventDispatcher: "resource://gre/modules/Messaging.jsm",
Log: "resource://gre/modules/Log.jsm",
Services: "resource://gre/modules/Services.jsm",
});
var EXPORTED_SYMBOLS = ["GeckoViewUtils"];
@ -252,6 +253,90 @@ var GeckoViewUtils = {
}
return null;
},
/**
* Add logging functions to the specified scope that forward to the given
* Log.jsm logger. Currently "debug" and "warn" functions are supported. To
* log something, call the function through a template literal:
*
* function foo(bar, baz) {
* debug `hello world`;
* debug `foo called with ${bar} as bar`;
* warn `this is a warning for ${baz}`;
* }
*
* An inline format can also be used for logging:
*
* let bar = 42;
* do_something(bar); // No log.
* do_something(debug.foo = bar); // Output "foo = 42" to the log.
*
* @param tag Name of the Log.jsm logger to forward logs to.
* @param scope Scope to add the logging functions to.
*/
initLogging: function(tag, scope) {
// Only provide two levels for simplicity.
// For "info", use "debug" instead.
// For "error", throw an actual JS error instead.
for (const level of ["debug", "warn"]) {
const log = (strings, ...exprs) =>
this._log(log.logger, level, strings, exprs);
XPCOMUtils.defineLazyGetter(log, "logger", _ => {
const logger = Log.repository.getLogger(tag);
logger.parent = this.rootLogger;
return logger;
});
scope[level] = new Proxy(log, {
set: (obj, prop, value) => obj([prop + " = ", ""], value) || true,
});
}
return scope;
},
get rootLogger() {
if (!this._rootLogger) {
this._rootLogger = Log.repository.getLogger("GeckoView");
this._rootLogger.addAppender(new Log.AndroidAppender());
}
return this._rootLogger;
},
_log: function(logger, level, strings, exprs) {
if (!Array.isArray(strings)) {
const [, file, line] =
(new Error()).stack.match(/.*\n.*\n.*@(.*):(\d+):/);
throw Error(`Expecting template literal: ${level} \`foo \${bar}\``,
file, +line);
}
// Do some GeckoView-specific formatting:
// 1) Heuristically format flags as hex.
// 2) Heuristically format nsresult as string name or hex.
for (let i = 0; i < exprs.length; i++) {
const expr = exprs[i];
switch (typeof expr) {
case "number":
if (expr > 0 && /\ba?[fF]lags?[\s=:]+$/.test(strings[i])) {
// Likely a flag; display in hex.
exprs[i] = `0x${expr.toString(0x10)}`;
} else if (expr >= 0 && /\b(a?[sS]tatus|rv)[\s=:]+$/.test(strings[i])) {
// Likely an nsresult; display in name or hex.
exprs[i] = `0x${expr.toString(0x10)}`;
for (const name in Cr) {
if (expr === Cr[name]) {
exprs[i] = name;
break;
}
}
}
break;
}
}
return logger[level](strings, ...exprs);
},
};
XPCOMUtils.defineLazyGetter(GeckoViewUtils, "IS_PARENT_PROCESS", _ =>