summaryrefslogtreecommitdiffstats
path: root/toolkit/components/url-classifier/content/moz/debug.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/url-classifier/content/moz/debug.js')
-rw-r--r--toolkit/components/url-classifier/content/moz/debug.js867
1 files changed, 867 insertions, 0 deletions
diff --git a/toolkit/components/url-classifier/content/moz/debug.js b/toolkit/components/url-classifier/content/moz/debug.js
new file mode 100644
index 000000000..ed4c11793
--- /dev/null
+++ b/toolkit/components/url-classifier/content/moz/debug.js
@@ -0,0 +1,867 @@
+# 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/.
+
+#ifdef DEBUG
+
+// Generic logging/debugging functionality that:
+//
+// (*) when disabled compiles to no-ops at worst (for calls to the service)
+// and to nothing at best (calls to G_Debug() and similar are compiled
+// away when you use a jscompiler that strips dead code)
+//
+// (*) has dynamically configurable/creatable debugging "zones" enabling
+// selective logging
+//
+// (*) hides its plumbing so that all calls in different zones are uniform,
+// so you can drop files using this library into other apps that use it
+// without any configuration
+//
+// (*) can be controlled programmatically or via preferences. The
+// preferences that control the service and its zones are under
+// the preference branch "safebrowsing-debug-service."
+//
+// (*) outputs function call traces when the "loggifier" zone is enabled
+//
+// (*) can write output to logfiles so that you can get a call trace
+// from someone who is having a problem
+//
+// Example:
+//
+// var G_GDEBUG = true // Enable this module
+// var G_debugService = new G_DebugService(); // in global context
+//
+// // You can use it with arbitrary primitive first arguement
+// G_Debug("myzone", "Yo yo yo"); // outputs: [myzone] Yo yo yo\n
+//
+// // But it's nice to use it with an object; it will probe for the zone name
+// function Obj() {
+// this.debugZone = "someobj";
+// }
+// Obj.prototype.foo = function() {
+// G_Debug(this, "foo called");
+// }
+// (new Obj).foo(); // outputs: [someobj] foo called\n
+//
+// G_debugService.loggifier.loggify(Obj.prototype); // enable call tracing
+//
+// // En/disable specific zones programmatically (you can also use preferences)
+// G_debugService.enableZone("somezone");
+// G_debugService.disableZone("someotherzone");
+// G_debugService.enableAllZones();
+//
+// // We also have asserts and errors:
+// G_Error(this, "Some error occurred"); // will throw
+// G_Assert(this, (x > 3), "x not greater than three!"); // will throw
+//
+// See classes below for more methods.
+//
+// TODO add code to set prefs when not found to the default value of a tristate
+// TODO add error level support
+// TODO add ability to turn off console output
+//
+// -------> TO START DEBUGGING: set G_GDEBUG to true
+
+// These are the functions code will typically call. Everything is
+// wrapped in if's so we can compile it away when G_GDEBUG is false.
+
+
+if (typeof G_GDEBUG == "undefined") {
+ throw new Error("G_GDEBUG constant must be set before loading debug.js");
+}
+
+
+/**
+ * Write out a debugging message.
+ *
+ * @param who The thingy to convert into a zone name corresponding to the
+ * zone to which this message belongs
+ * @param msg Message to output
+ */
+this.G_Debug = function G_Debug(who, msg) {
+ if (G_GDEBUG) {
+ G_GetDebugZone(who).debug(msg);
+ }
+}
+
+/**
+ * Debugs loudly
+ */
+this.G_DebugL = function G_DebugL(who, msg) {
+ if (G_GDEBUG) {
+ var zone = G_GetDebugZone(who);
+
+ if (zone.zoneIsEnabled()) {
+ G_debugService.dump(
+ "\n************************************************************\n");
+
+ G_Debug(who, msg);
+
+ G_debugService.dump(
+ "************************************************************\n\n");
+ }
+ }
+}
+
+/**
+ * Write out a call tracing message
+ *
+ * @param who The thingy to convert into a zone name corresponding to the
+ * zone to which this message belongs
+ * @param msg Message to output
+ */
+this.G_TraceCall = function G_TraceCall(who, msg) {
+ if (G_GDEBUG) {
+ if (G_debugService.callTracingEnabled()) {
+ G_debugService.dump(msg + "\n");
+ }
+ }
+}
+
+/**
+ * Write out an error (and throw)
+ *
+ * @param who The thingy to convert into a zone name corresponding to the
+ * zone to which this message belongs
+ * @param msg Message to output
+ */
+this.G_Error = function G_Error(who, msg) {
+ if (G_GDEBUG) {
+ G_GetDebugZone(who).error(msg);
+ }
+}
+
+/**
+ * Assert something as true and signal an error if it's not
+ *
+ * @param who The thingy to convert into a zone name corresponding to the
+ * zone to which this message belongs
+ * @param condition Boolean condition to test
+ * @param msg Message to output
+ */
+this.G_Assert = function G_Assert(who, condition, msg) {
+ if (G_GDEBUG) {
+ G_GetDebugZone(who).assert(condition, msg);
+ }
+}
+
+/**
+ * Helper function that takes input and returns the DebugZone
+ * corresponding to it.
+ *
+ * @param who Arbitrary input that will be converted into a zone name. Most
+ * likely an object that has .debugZone property, or a string.
+ * @returns The DebugZone object corresponding to the input
+ */
+this.G_GetDebugZone = function G_GetDebugZone(who) {
+ if (G_GDEBUG) {
+ var zone = "?";
+
+ if (who && who.debugZone) {
+ zone = who.debugZone;
+ } else if (typeof who == "string") {
+ zone = who;
+ }
+
+ return G_debugService.getZone(zone);
+ }
+}
+
+// Classes that implement the functionality.
+
+/**
+ * A debug "zone" is a string derived from arbitrary types (but
+ * typically derived from another string or an object). All debugging
+ * messages using a particular zone can be enabled or disabled
+ * independent of other zones. This enables you to turn on/off logging
+ * of particular objects or modules. This object implements a single
+ * zone and the methods required to use it.
+ *
+ * @constructor
+ * @param service Reference to the DebugService object we use for
+ * registration
+ * @param prefix String indicating the unique prefix we should use
+ * when creating preferences to control this zone
+ * @param zone String indicating the name of the zone
+ */
+this.G_DebugZone = function G_DebugZone(service, prefix, zone) {
+ if (G_GDEBUG) {
+ this.debugService_ = service;
+ this.prefix_ = prefix;
+ this.zone_ = zone;
+ this.zoneEnabledPrefName_ = prefix + ".zone." + this.zone_;
+ this.settings_ = new G_DebugSettings();
+ }
+}
+
+/**
+ * @returns Boolean indicating if this zone is enabled
+ */
+G_DebugZone.prototype.zoneIsEnabled = function() {
+ if (G_GDEBUG) {
+ var explicit = this.settings_.getSetting(this.zoneEnabledPrefName_, null);
+
+ if (explicit !== null) {
+ return explicit;
+ } else {
+ return this.debugService_.allZonesEnabled();
+ }
+ }
+}
+
+/**
+ * Enable this logging zone
+ */
+G_DebugZone.prototype.enableZone = function() {
+ if (G_GDEBUG) {
+ this.settings_.setDefault(this.zoneEnabledPrefName_, true);
+ }
+}
+
+/**
+ * Disable this logging zone
+ */
+G_DebugZone.prototype.disableZone = function() {
+ if (G_GDEBUG) {
+ this.settings_.setDefault(this.zoneEnabledPrefName_, false);
+ }
+}
+
+/**
+ * Write a debugging message to this zone
+ *
+ * @param msg String of message to write
+ */
+G_DebugZone.prototype.debug = function(msg) {
+ if (G_GDEBUG) {
+ if (this.zoneIsEnabled()) {
+ this.debugService_.dump("[" + this.zone_ + "] " + msg + "\n");
+ }
+ }
+}
+
+/**
+ * Write an error to this zone and throw
+ *
+ * @param msg String of error to write
+ */
+G_DebugZone.prototype.error = function(msg) {
+ if (G_GDEBUG) {
+ this.debugService_.dump("[" + this.zone_ + "] " + msg + "\n");
+ throw new Error(msg);
+ debugger;
+ }
+}
+
+/**
+ * Assert something as true and error if it is not
+ *
+ * @param condition Boolean condition to test
+ * @param msg String of message to write if is false
+ */
+G_DebugZone.prototype.assert = function(condition, msg) {
+ if (G_GDEBUG) {
+ if (condition !== true) {
+ G_Error(this.zone_, "ASSERT FAILED: " + msg);
+ }
+ }
+}
+
+
+/**
+ * The debug service handles auto-registration of zones, namespacing
+ * the zones preferences, and various global settings such as whether
+ * all zones are enabled.
+ *
+ * @constructor
+ * @param opt_prefix Optional string indicating the unique prefix we should
+ * use when creating preferences
+ */
+this.G_DebugService = function G_DebugService(opt_prefix) {
+ if (G_GDEBUG) {
+ this.prefix_ = opt_prefix ? opt_prefix : "safebrowsing-debug-service";
+ this.consoleEnabledPrefName_ = this.prefix_ + ".alsologtoconsole";
+ this.allZonesEnabledPrefName_ = this.prefix_ + ".enableallzones";
+ this.callTracingEnabledPrefName_ = this.prefix_ + ".trace-function-calls";
+ this.logFileEnabledPrefName_ = this.prefix_ + ".logfileenabled";
+ this.logFileErrorLevelPrefName_ = this.prefix_ + ".logfile-errorlevel";
+ this.zones_ = {};
+
+ this.loggifier = new G_Loggifier();
+ this.settings_ = new G_DebugSettings();
+ }
+}
+
+// Error levels for reporting console messages to the log.
+G_DebugService.ERROR_LEVEL_INFO = "INFO";
+G_DebugService.ERROR_LEVEL_WARNING = "WARNING";
+G_DebugService.ERROR_LEVEL_EXCEPTION = "EXCEPTION";
+
+
+/**
+ * @returns Boolean indicating if we should send messages to the jsconsole
+ */
+G_DebugService.prototype.alsoDumpToConsole = function() {
+ if (G_GDEBUG) {
+ return this.settings_.getSetting(this.consoleEnabledPrefName_, false);
+ }
+}
+
+/**
+ * @returns whether to log output to a file as well as the console.
+ */
+G_DebugService.prototype.logFileIsEnabled = function() {
+ if (G_GDEBUG) {
+ return this.settings_.getSetting(this.logFileEnabledPrefName_, false);
+ }
+}
+
+/**
+ * Turns on file logging. dump() output will also go to the file specified by
+ * setLogFile()
+ */
+G_DebugService.prototype.enableLogFile = function() {
+ if (G_GDEBUG) {
+ this.settings_.setDefault(this.logFileEnabledPrefName_, true);
+ }
+}
+
+/**
+ * Turns off file logging
+ */
+G_DebugService.prototype.disableLogFile = function() {
+ if (G_GDEBUG) {
+ this.settings_.setDefault(this.logFileEnabledPrefName_, false);
+ }
+}
+
+/**
+ * @returns an nsIFile instance pointing to the current log file location
+ */
+G_DebugService.prototype.getLogFile = function() {
+ if (G_GDEBUG) {
+ return this.logFile_;
+ }
+}
+
+/**
+ * Sets a new log file location
+ */
+G_DebugService.prototype.setLogFile = function(file) {
+ if (G_GDEBUG) {
+ this.logFile_ = file;
+ }
+}
+
+/**
+ * Enables sending messages to the jsconsole
+ */
+G_DebugService.prototype.enableDumpToConsole = function() {
+ if (G_GDEBUG) {
+ this.settings_.setDefault(this.consoleEnabledPrefName_, true);
+ }
+}
+
+/**
+ * Disables sending messages to the jsconsole
+ */
+G_DebugService.prototype.disableDumpToConsole = function() {
+ if (G_GDEBUG) {
+ this.settings_.setDefault(this.consoleEnabledPrefName_, false);
+ }
+}
+
+/**
+ * @param zone Name of the zone to get
+ * @returns The DebugZone object corresopnding to input. If not such
+ * zone exists, a new one is created and returned
+ */
+G_DebugService.prototype.getZone = function(zone) {
+ if (G_GDEBUG) {
+ if (!this.zones_[zone])
+ this.zones_[zone] = new G_DebugZone(this, this.prefix_, zone);
+
+ return this.zones_[zone];
+ }
+}
+
+/**
+ * @param zone Zone to enable debugging for
+ */
+G_DebugService.prototype.enableZone = function(zone) {
+ if (G_GDEBUG) {
+ var toEnable = this.getZone(zone);
+ toEnable.enableZone();
+ }
+}
+
+/**
+ * @param zone Zone to disable debugging for
+ */
+G_DebugService.prototype.disableZone = function(zone) {
+ if (G_GDEBUG) {
+ var toDisable = this.getZone(zone);
+ toDisable.disableZone();
+ }
+}
+
+/**
+ * @returns Boolean indicating whether debugging is enabled for all zones
+ */
+G_DebugService.prototype.allZonesEnabled = function() {
+ if (G_GDEBUG) {
+ return this.settings_.getSetting(this.allZonesEnabledPrefName_, false);
+ }
+}
+
+/**
+ * Enables all debugging zones
+ */
+G_DebugService.prototype.enableAllZones = function() {
+ if (G_GDEBUG) {
+ this.settings_.setDefault(this.allZonesEnabledPrefName_, true);
+ }
+}
+
+/**
+ * Disables all debugging zones
+ */
+G_DebugService.prototype.disableAllZones = function() {
+ if (G_GDEBUG) {
+ this.settings_.setDefault(this.allZonesEnabledPrefName_, false);
+ }
+}
+
+/**
+ * @returns Boolean indicating whether call tracing is enabled
+ */
+G_DebugService.prototype.callTracingEnabled = function() {
+ if (G_GDEBUG) {
+ return this.settings_.getSetting(this.callTracingEnabledPrefName_, false);
+ }
+}
+
+/**
+ * Enables call tracing
+ */
+G_DebugService.prototype.enableCallTracing = function() {
+ if (G_GDEBUG) {
+ this.settings_.setDefault(this.callTracingEnabledPrefName_, true);
+ }
+}
+
+/**
+ * Disables call tracing
+ */
+G_DebugService.prototype.disableCallTracing = function() {
+ if (G_GDEBUG) {
+ this.settings_.setDefault(this.callTracingEnabledPrefName_, false);
+ }
+}
+
+/**
+ * Gets the minimum error that will be reported to the log.
+ */
+G_DebugService.prototype.getLogFileErrorLevel = function() {
+ if (G_GDEBUG) {
+ var level = this.settings_.getSetting(this.logFileErrorLevelPrefName_,
+ G_DebugService.ERROR_LEVEL_EXCEPTION);
+
+ return level.toUpperCase();
+ }
+}
+
+/**
+ * Sets the minimum error level that will be reported to the log.
+ */
+G_DebugService.prototype.setLogFileErrorLevel = function(level) {
+ if (G_GDEBUG) {
+ // normalize case just to make it slightly easier to not screw up.
+ level = level.toUpperCase();
+
+ if (level != G_DebugService.ERROR_LEVEL_INFO &&
+ level != G_DebugService.ERROR_LEVEL_WARNING &&
+ level != G_DebugService.ERROR_LEVEL_EXCEPTION) {
+ throw new Error("Invalid error level specified: {" + level + "}");
+ }
+
+ this.settings_.setDefault(this.logFileErrorLevelPrefName_, level);
+ }
+}
+
+/**
+ * Internal dump() method
+ *
+ * @param msg String of message to dump
+ */
+G_DebugService.prototype.dump = function(msg) {
+ if (G_GDEBUG) {
+ dump(msg);
+
+ if (this.alsoDumpToConsole()) {
+ try {
+ var console = Components.classes['@mozilla.org/consoleservice;1']
+ .getService(Components.interfaces.nsIConsoleService);
+ console.logStringMessage(msg);
+ } catch(e) {
+ dump("G_DebugZone ERROR: COULD NOT DUMP TO CONSOLE\n");
+ }
+ }
+
+ this.maybeDumpToFile(msg);
+ }
+}
+
+/**
+ * Writes the specified message to the log file, if file logging is enabled.
+ */
+G_DebugService.prototype.maybeDumpToFile = function(msg) {
+ if (this.logFileIsEnabled() && this.logFile_) {
+
+ /* try to get the correct line end character for this platform */
+ if (!this._LINE_END_CHAR)
+ this._LINE_END_CHAR =
+ Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
+ .OS == "WINNT" ? "\r\n" : "\n";
+ if (this._LINE_END_CHAR != "\n")
+ msg = msg.replace(/\n/g, this._LINE_END_CHAR);
+
+ try {
+ var stream = Cc["@mozilla.org/network/file-output-stream;1"]
+ .createInstance(Ci.nsIFileOutputStream);
+ stream.init(this.logFile_,
+ 0x02 | 0x08 | 0x10 /* PR_WRONLY | PR_CREATE_FILE | PR_APPEND */
+ -1 /* default perms */, 0 /* no special behavior */);
+ stream.write(msg, msg.length);
+ } finally {
+ stream.close();
+ }
+ }
+}
+
+/**
+ * Implements nsIConsoleListener.observe(). Gets called when an error message
+ * gets reported to the console and sends it to the log file as well.
+ */
+G_DebugService.prototype.observe = function(consoleMessage) {
+ if (G_GDEBUG) {
+ var errorLevel = this.getLogFileErrorLevel();
+
+ // consoleMessage can be either nsIScriptError or nsIConsoleMessage. The
+ // latter does not have things like line number, etc. So we special case
+ // it first.
+ if (!(consoleMessage instanceof Ci.nsIScriptError)) {
+ // Only report these messages if the error level is INFO.
+ if (errorLevel == G_DebugService.ERROR_LEVEL_INFO) {
+ this.maybeDumpToFile(G_DebugService.ERROR_LEVEL_INFO + ": " +
+ consoleMessage.message + "\n");
+ }
+
+ return;
+ }
+
+ // We make a local copy of these fields because writing to it doesn't seem
+ // to work.
+ var flags = consoleMessage.flags;
+ var sourceName = consoleMessage.sourceName;
+ var lineNumber = consoleMessage.lineNumber;
+
+ // Sometimes, a scripterror instance won't have any flags set. We
+ // default to exception.
+ if (!flags) {
+ flags = Ci.nsIScriptError.exceptionFlag;
+ }
+
+ // Default the filename and line number if they aren't set.
+ if (!sourceName) {
+ sourceName = "<unknown>";
+ }
+
+ if (!lineNumber) {
+ lineNumber = "<unknown>";
+ }
+
+ // Report the error in the log file.
+ if (flags & Ci.nsIScriptError.warningFlag) {
+ // Only report warnings if the error level is warning or better.
+ if (errorLevel == G_DebugService.ERROR_LEVEL_WARNING ||
+ errorLevel == G_DebugService.ERROR_LEVEL_INFO) {
+ this.reportScriptError_(consoleMessage.message,
+ sourceName,
+ lineNumber,
+ G_DebugService.ERROR_LEVEL_WARNING);
+ }
+ } else if (flags & Ci.nsIScriptError.exceptionFlag) {
+ // Always report exceptions.
+ this.reportScriptError_(consoleMessage.message,
+ sourceName,
+ lineNumber,
+ G_DebugService.ERROR_LEVEL_EXCEPTION);
+ }
+ }
+}
+
+/**
+ * Private helper to report an nsIScriptError instance to the log/console.
+ */
+G_DebugService.prototype.reportScriptError_ = function(message, sourceName,
+ lineNumber, label) {
+ message = "\n------------------------------------------------------------\n" +
+ label + ": " + message +
+ "\nlocation: " + sourceName + ", " + "line: " + lineNumber +
+ "\n------------------------------------------------------------\n\n";
+
+ dump(message);
+ this.maybeDumpToFile(message);
+}
+
+
+
+/**
+ * A class that instruments methods so they output a call trace,
+ * including the values of their actual parameters and return value.
+ * This code is mostly stolen from Aaron Boodman's original
+ * implementation in clobber utils.
+ *
+ * Note that this class uses the "loggifier" debug zone, so you'll see
+ * a complete call trace when that zone is enabled.
+ *
+ * @constructor
+ */
+this.G_Loggifier = function G_Loggifier() {
+ if (G_GDEBUG) {
+ // Careful not to loggify ourselves!
+ this.mark_(this);
+ }
+}
+
+/**
+ * Marks an object as having been loggified. Loggification is not
+ * idempotent :)
+ *
+ * @param obj Object to be marked
+ */
+G_Loggifier.prototype.mark_ = function(obj) {
+ if (G_GDEBUG) {
+ obj.__loggified_ = true;
+ }
+}
+
+/**
+ * @param obj Object to be examined
+ * @returns Boolean indicating if the object has been loggified
+ */
+G_Loggifier.prototype.isLoggified = function(obj) {
+ if (G_GDEBUG) {
+ return !!obj.__loggified_;
+ }
+}
+
+/**
+ * Attempt to extract the class name from the constructor definition.
+ * Assumes the object was created using new.
+ *
+ * @param constructor String containing the definition of a constructor,
+ * for example what you'd get by examining obj.constructor
+ * @returns Name of the constructor/object if it could be found, else "???"
+ */
+G_Loggifier.prototype.getFunctionName_ = function(constructor) {
+ if (G_GDEBUG) {
+ return constructor.name || "???";
+ }
+}
+
+/**
+ * Wraps all the methods in an object so that call traces are
+ * automatically outputted.
+ *
+ * @param obj Object to loggify. SHOULD BE THE PROTOTYPE OF A USER-DEFINED
+ * object. You can get into trouble if you attempt to
+ * loggify something that isn't, for example the Window.
+ *
+ * Any additional parameters are considered method names which should not be
+ * loggified.
+ *
+ * Usage:
+ * G_debugService.loggifier.loggify(MyClass.prototype,
+ * "firstMethodNotToLog",
+ * "secondMethodNotToLog",
+ * ... etc ...);
+ */
+G_Loggifier.prototype.loggify = function(obj) {
+ if (G_GDEBUG) {
+ if (!G_debugService.callTracingEnabled()) {
+ return;
+ }
+
+ if (typeof window != "undefined" && obj == window ||
+ this.isLoggified(obj)) // Don't go berserk!
+ return;
+
+ var zone = G_GetDebugZone(obj);
+ if (!zone || !zone.zoneIsEnabled()) {
+ return;
+ }
+
+ this.mark_(obj);
+
+ // Helper function returns an instrumented version of
+ // objName.meth, with "this" bound properly. (BTW, because we're
+ // in a conditional here, functions will only be defined as
+ // they're encountered during execution, so declare this helper
+ // before using it.)
+
+ let wrap = function (meth, objName, methName) {
+ return function() {
+
+ // First output the call along with actual parameters
+ var args = new Array(arguments.length);
+ var argsString = "";
+ for (var i = 0; i < args.length; i++) {
+ args[i] = arguments[i];
+ argsString += (i == 0 ? "" : ", ");
+
+ if (typeof args[i] == "function") {
+ argsString += "[function]";
+ } else {
+ argsString += args[i];
+ }
+ }
+
+ G_TraceCall(this, "> " + objName + "." + methName + "(" +
+ argsString + ")");
+
+ // Then run the function, capturing the return value and throws
+ try {
+ var retVal = meth.apply(this, arguments);
+ var reportedRetVal = retVal;
+
+ if (typeof reportedRetVal == "undefined")
+ reportedRetVal = "void";
+ else if (reportedRetVal === "")
+ reportedRetVal = "\"\" (empty string)";
+ } catch (e) {
+ if (e && !e.__logged) {
+ G_TraceCall(this, "Error: " + e.message + ". " +
+ e.fileName + ": " + e.lineNumber);
+ try {
+ e.__logged = true;
+ } catch (e2) {
+ // Sometimes we can't add the __logged flag because it's an
+ // XPC wrapper
+ throw e;
+ }
+ }
+
+ throw e; // Re-throw!
+ }
+
+ // And spit it out already
+ G_TraceCall(
+ this,
+ "< " + objName + "." + methName + ": " + reportedRetVal);
+
+ return retVal;
+ };
+ };
+
+ var ignoreLookup = {};
+
+ if (arguments.length > 1) {
+ for (var i = 1; i < arguments.length; i++) {
+ ignoreLookup[arguments[i]] = true;
+ }
+ }
+
+ // Wrap each method of obj
+ for (var p in obj) {
+ // Work around bug in Firefox. In ffox typeof RegExp is "function",
+ // so make sure this really is a function. Bug as of FFox 1.5b2.
+ if (typeof obj[p] == "function" && obj[p].call && !ignoreLookup[p]) {
+ var objName = this.getFunctionName_(obj.constructor);
+ obj[p] = wrap(obj[p], objName, p);
+ }
+ }
+ }
+}
+
+
+/**
+ * Simple abstraction around debug settings. The thing with debug settings is
+ * that we want to be able to specify a default in the application's startup,
+ * but have that default be overridable by the user via their prefs.
+ *
+ * To generalize this, we package up a dictionary of defaults with the
+ * preferences tree. If a setting isn't in the preferences tree, then we grab it
+ * from the defaults.
+ */
+this.G_DebugSettings = function G_DebugSettings() {
+ this.defaults_ = {};
+ this.prefs_ = new G_Preferences();
+}
+
+/**
+ * Returns the value of a settings, optionally defaulting to a given value if it
+ * doesn't exist. If no default is specified, the default is |undefined|.
+ */
+G_DebugSettings.prototype.getSetting = function(name, opt_default) {
+ var override = this.prefs_.getPref(name, null);
+
+ if (override !== null) {
+ return override;
+ } else if (typeof this.defaults_[name] != "undefined") {
+ return this.defaults_[name];
+ } else {
+ return opt_default;
+ }
+}
+
+/**
+ * Sets the default value for a setting. If the user doesn't override it with a
+ * preference, this is the value which will be returned by getSetting().
+ */
+G_DebugSettings.prototype.setDefault = function(name, val) {
+ this.defaults_[name] = val;
+}
+
+var G_debugService = new G_DebugService(); // Instantiate us!
+
+if (G_GDEBUG) {
+ G_debugService.enableAllZones();
+}
+
+#else
+
+// Stubs for the debugging aids scattered through this component.
+// They will be expanded if you compile yourself a debug build.
+
+this.G_Debug = function G_Debug(who, msg) { }
+this.G_Assert = function G_Assert(who, condition, msg) { }
+this.G_Error = function G_Error(who, msg) { }
+this.G_debugService = {
+ alsoDumpToConsole: () => {},
+ logFileIsEnabled: () => {},
+ enableLogFile: () => {},
+ disableLogFile: () => {},
+ getLogFile: () => {},
+ setLogFile: () => {},
+ enableDumpToConsole: () => {},
+ disableDumpToConsole: () => {},
+ getZone: () => {},
+ enableZone: () => {},
+ disableZone: () => {},
+ allZonesEnabled: () => {},
+ enableAllZones: () => {},
+ disableAllZones: () => {},
+ callTracingEnabled: () => {},
+ enableCallTracing: () => {},
+ disableCallTracing: () => {},
+ getLogFileErrorLevel: () => {},
+ setLogFileErrorLevel: () => {},
+ dump: () => {},
+ maybeDumpToFile: () => {},
+ observe: () => {},
+ reportScriptError_: () => {}
+};
+
+#endif