toolkit/components/url-classifier/content/moz/debug.js

branch
TOR_BUG_9701
changeset 14
925c144e1f1f
equal deleted inserted replaced
-1:000000000000 0:fbea82fffbbe
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5 #ifdef DEBUG
6
7 // Generic logging/debugging functionality that:
8 //
9 // (*) when disabled compiles to no-ops at worst (for calls to the service)
10 // and to nothing at best (calls to G_Debug() and similar are compiled
11 // away when you use a jscompiler that strips dead code)
12 //
13 // (*) has dynamically configurable/creatable debugging "zones" enabling
14 // selective logging
15 //
16 // (*) hides its plumbing so that all calls in different zones are uniform,
17 // so you can drop files using this library into other apps that use it
18 // without any configuration
19 //
20 // (*) can be controlled programmatically or via preferences. The
21 // preferences that control the service and its zones are under
22 // the preference branch "safebrowsing-debug-service."
23 //
24 // (*) outputs function call traces when the "loggifier" zone is enabled
25 //
26 // (*) can write output to logfiles so that you can get a call trace
27 // from someone who is having a problem
28 //
29 // Example:
30 //
31 // var G_GDEBUG = true // Enable this module
32 // var G_debugService = new G_DebugService(); // in global context
33 //
34 // // You can use it with arbitrary primitive first arguement
35 // G_Debug("myzone", "Yo yo yo"); // outputs: [myzone] Yo yo yo\n
36 //
37 // // But it's nice to use it with an object; it will probe for the zone name
38 // function Obj() {
39 // this.debugZone = "someobj";
40 // }
41 // Obj.prototype.foo = function() {
42 // G_Debug(this, "foo called");
43 // }
44 // (new Obj).foo(); // outputs: [someobj] foo called\n
45 //
46 // G_debugService.loggifier.loggify(Obj.prototype); // enable call tracing
47 //
48 // // En/disable specific zones programmatically (you can also use preferences)
49 // G_debugService.enableZone("somezone");
50 // G_debugService.disableZone("someotherzone");
51 // G_debugService.enableAllZones();
52 //
53 // // We also have asserts and errors:
54 // G_Error(this, "Some error occurred"); // will throw
55 // G_Assert(this, (x > 3), "x not greater than three!"); // will throw
56 //
57 // See classes below for more methods.
58 //
59 // TODO add code to set prefs when not found to the default value of a tristate
60 // TODO add error level support
61 // TODO add ability to turn off console output
62 //
63 // -------> TO START DEBUGGING: set G_GDEBUG to true
64
65 // These are the functions code will typically call. Everything is
66 // wrapped in if's so we can compile it away when G_GDEBUG is false.
67
68
69 if (typeof G_GDEBUG == "undefined") {
70 throw new Error("G_GDEBUG constant must be set before loading debug.js");
71 }
72
73
74 /**
75 * Write out a debugging message.
76 *
77 * @param who The thingy to convert into a zone name corresponding to the
78 * zone to which this message belongs
79 * @param msg Message to output
80 */
81 function G_Debug(who, msg) {
82 if (G_GDEBUG) {
83 G_GetDebugZone(who).debug(msg);
84 }
85 }
86
87 /**
88 * Debugs loudly
89 */
90 function G_DebugL(who, msg) {
91 if (G_GDEBUG) {
92 var zone = G_GetDebugZone(who);
93
94 if (zone.zoneIsEnabled()) {
95 G_debugService.dump(
96 "\n************************************************************\n");
97
98 G_Debug(who, msg);
99
100 G_debugService.dump(
101 "************************************************************\n\n");
102 }
103 }
104 }
105
106 /**
107 * Write out a call tracing message
108 *
109 * @param who The thingy to convert into a zone name corresponding to the
110 * zone to which this message belongs
111 * @param msg Message to output
112 */
113 function G_TraceCall(who, msg) {
114 if (G_GDEBUG) {
115 if (G_debugService.callTracingEnabled()) {
116 G_debugService.dump(msg + "\n");
117 }
118 }
119 }
120
121 /**
122 * Write out an error (and throw)
123 *
124 * @param who The thingy to convert into a zone name corresponding to the
125 * zone to which this message belongs
126 * @param msg Message to output
127 */
128 function G_Error(who, msg) {
129 if (G_GDEBUG) {
130 G_GetDebugZone(who).error(msg);
131 }
132 }
133
134 /**
135 * Assert something as true and signal an error if it's not
136 *
137 * @param who The thingy to convert into a zone name corresponding to the
138 * zone to which this message belongs
139 * @param condition Boolean condition to test
140 * @param msg Message to output
141 */
142 function G_Assert(who, condition, msg) {
143 if (G_GDEBUG) {
144 G_GetDebugZone(who).assert(condition, msg);
145 }
146 }
147
148 /**
149 * Helper function that takes input and returns the DebugZone
150 * corresponding to it.
151 *
152 * @param who Arbitrary input that will be converted into a zone name. Most
153 * likely an object that has .debugZone property, or a string.
154 * @returns The DebugZone object corresponding to the input
155 */
156 function G_GetDebugZone(who) {
157 if (G_GDEBUG) {
158 var zone = "?";
159
160 if (who && who.debugZone) {
161 zone = who.debugZone;
162 } else if (typeof who == "string") {
163 zone = who;
164 }
165
166 return G_debugService.getZone(zone);
167 }
168 }
169
170 // Classes that implement the functionality.
171
172 /**
173 * A debug "zone" is a string derived from arbitrary types (but
174 * typically derived from another string or an object). All debugging
175 * messages using a particular zone can be enabled or disabled
176 * independent of other zones. This enables you to turn on/off logging
177 * of particular objects or modules. This object implements a single
178 * zone and the methods required to use it.
179 *
180 * @constructor
181 * @param service Reference to the DebugService object we use for
182 * registration
183 * @param prefix String indicating the unique prefix we should use
184 * when creating preferences to control this zone
185 * @param zone String indicating the name of the zone
186 */
187 function G_DebugZone(service, prefix, zone) {
188 if (G_GDEBUG) {
189 this.debugService_ = service;
190 this.prefix_ = prefix;
191 this.zone_ = zone;
192 this.zoneEnabledPrefName_ = prefix + ".zone." + this.zone_;
193 this.settings_ = new G_DebugSettings();
194 }
195 }
196
197 /**
198 * @returns Boolean indicating if this zone is enabled
199 */
200 G_DebugZone.prototype.zoneIsEnabled = function() {
201 if (G_GDEBUG) {
202 var explicit = this.settings_.getSetting(this.zoneEnabledPrefName_, null);
203
204 if (explicit !== null) {
205 return explicit;
206 } else {
207 return this.debugService_.allZonesEnabled();
208 }
209 }
210 }
211
212 /**
213 * Enable this logging zone
214 */
215 G_DebugZone.prototype.enableZone = function() {
216 if (G_GDEBUG) {
217 this.settings_.setDefault(this.zoneEnabledPrefName_, true);
218 }
219 }
220
221 /**
222 * Disable this logging zone
223 */
224 G_DebugZone.prototype.disableZone = function() {
225 if (G_GDEBUG) {
226 this.settings_.setDefault(this.zoneEnabledPrefName_, false);
227 }
228 }
229
230 /**
231 * Write a debugging message to this zone
232 *
233 * @param msg String of message to write
234 */
235 G_DebugZone.prototype.debug = function(msg) {
236 if (G_GDEBUG) {
237 if (this.zoneIsEnabled()) {
238 this.debugService_.dump("[" + this.zone_ + "] " + msg + "\n");
239 }
240 }
241 }
242
243 /**
244 * Write an error to this zone and throw
245 *
246 * @param msg String of error to write
247 */
248 G_DebugZone.prototype.error = function(msg) {
249 if (G_GDEBUG) {
250 this.debugService_.dump("[" + this.zone_ + "] " + msg + "\n");
251 throw new Error(msg);
252 debugger;
253 }
254 }
255
256 /**
257 * Assert something as true and error if it is not
258 *
259 * @param condition Boolean condition to test
260 * @param msg String of message to write if is false
261 */
262 G_DebugZone.prototype.assert = function(condition, msg) {
263 if (G_GDEBUG) {
264 if (condition !== true) {
265 G_Error(this.zone_, "ASSERT FAILED: " + msg);
266 }
267 }
268 }
269
270
271 /**
272 * The debug service handles auto-registration of zones, namespacing
273 * the zones preferences, and various global settings such as whether
274 * all zones are enabled.
275 *
276 * @constructor
277 * @param opt_prefix Optional string indicating the unique prefix we should
278 * use when creating preferences
279 */
280 function G_DebugService(opt_prefix) {
281 if (G_GDEBUG) {
282 this.prefix_ = opt_prefix ? opt_prefix : "safebrowsing-debug-service";
283 this.consoleEnabledPrefName_ = this.prefix_ + ".alsologtoconsole";
284 this.allZonesEnabledPrefName_ = this.prefix_ + ".enableallzones";
285 this.callTracingEnabledPrefName_ = this.prefix_ + ".trace-function-calls";
286 this.logFileEnabledPrefName_ = this.prefix_ + ".logfileenabled";
287 this.logFileErrorLevelPrefName_ = this.prefix_ + ".logfile-errorlevel";
288 this.zones_ = {};
289
290 this.loggifier = new G_Loggifier();
291 this.settings_ = new G_DebugSettings();
292 }
293 }
294
295 // Error levels for reporting console messages to the log.
296 G_DebugService.ERROR_LEVEL_INFO = "INFO";
297 G_DebugService.ERROR_LEVEL_WARNING = "WARNING";
298 G_DebugService.ERROR_LEVEL_EXCEPTION = "EXCEPTION";
299
300
301 /**
302 * @returns Boolean indicating if we should send messages to the jsconsole
303 */
304 G_DebugService.prototype.alsoDumpToConsole = function() {
305 if (G_GDEBUG) {
306 return this.settings_.getSetting(this.consoleEnabledPrefName_, false);
307 }
308 }
309
310 /**
311 * @returns whether to log output to a file as well as the console.
312 */
313 G_DebugService.prototype.logFileIsEnabled = function() {
314 if (G_GDEBUG) {
315 return this.settings_.getSetting(this.logFileEnabledPrefName_, false);
316 }
317 }
318
319 /**
320 * Turns on file logging. dump() output will also go to the file specified by
321 * setLogFile()
322 */
323 G_DebugService.prototype.enableLogFile = function() {
324 if (G_GDEBUG) {
325 this.settings_.setDefault(this.logFileEnabledPrefName_, true);
326 }
327 }
328
329 /**
330 * Turns off file logging
331 */
332 G_DebugService.prototype.disableLogFile = function() {
333 if (G_GDEBUG) {
334 this.settings_.setDefault(this.logFileEnabledPrefName_, false);
335 }
336 }
337
338 /**
339 * @returns an nsIFile instance pointing to the current log file location
340 */
341 G_DebugService.prototype.getLogFile = function() {
342 if (G_GDEBUG) {
343 return this.logFile_;
344 }
345 }
346
347 /**
348 * Sets a new log file location
349 */
350 G_DebugService.prototype.setLogFile = function(file) {
351 if (G_GDEBUG) {
352 this.logFile_ = file;
353 }
354 }
355
356 /**
357 * Enables sending messages to the jsconsole
358 */
359 G_DebugService.prototype.enableDumpToConsole = function() {
360 if (G_GDEBUG) {
361 this.settings_.setDefault(this.consoleEnabledPrefName_, true);
362 }
363 }
364
365 /**
366 * Disables sending messages to the jsconsole
367 */
368 G_DebugService.prototype.disableDumpToConsole = function() {
369 if (G_GDEBUG) {
370 this.settings_.setDefault(this.consoleEnabledPrefName_, false);
371 }
372 }
373
374 /**
375 * @param zone Name of the zone to get
376 * @returns The DebugZone object corresopnding to input. If not such
377 * zone exists, a new one is created and returned
378 */
379 G_DebugService.prototype.getZone = function(zone) {
380 if (G_GDEBUG) {
381 if (!this.zones_[zone])
382 this.zones_[zone] = new G_DebugZone(this, this.prefix_, zone);
383
384 return this.zones_[zone];
385 }
386 }
387
388 /**
389 * @param zone Zone to enable debugging for
390 */
391 G_DebugService.prototype.enableZone = function(zone) {
392 if (G_GDEBUG) {
393 var toEnable = this.getZone(zone);
394 toEnable.enableZone();
395 }
396 }
397
398 /**
399 * @param zone Zone to disable debugging for
400 */
401 G_DebugService.prototype.disableZone = function(zone) {
402 if (G_GDEBUG) {
403 var toDisable = this.getZone(zone);
404 toDisable.disableZone();
405 }
406 }
407
408 /**
409 * @returns Boolean indicating whether debugging is enabled for all zones
410 */
411 G_DebugService.prototype.allZonesEnabled = function() {
412 if (G_GDEBUG) {
413 return this.settings_.getSetting(this.allZonesEnabledPrefName_, false);
414 }
415 }
416
417 /**
418 * Enables all debugging zones
419 */
420 G_DebugService.prototype.enableAllZones = function() {
421 if (G_GDEBUG) {
422 this.settings_.setDefault(this.allZonesEnabledPrefName_, true);
423 }
424 }
425
426 /**
427 * Disables all debugging zones
428 */
429 G_DebugService.prototype.disableAllZones = function() {
430 if (G_GDEBUG) {
431 this.settings_.setDefault(this.allZonesEnabledPrefName_, false);
432 }
433 }
434
435 /**
436 * @returns Boolean indicating whether call tracing is enabled
437 */
438 G_DebugService.prototype.callTracingEnabled = function() {
439 if (G_GDEBUG) {
440 return this.settings_.getSetting(this.callTracingEnabledPrefName_, false);
441 }
442 }
443
444 /**
445 * Enables call tracing
446 */
447 G_DebugService.prototype.enableCallTracing = function() {
448 if (G_GDEBUG) {
449 this.settings_.setDefault(this.callTracingEnabledPrefName_, true);
450 }
451 }
452
453 /**
454 * Disables call tracing
455 */
456 G_DebugService.prototype.disableCallTracing = function() {
457 if (G_GDEBUG) {
458 this.settings_.setDefault(this.callTracingEnabledPrefName_, false);
459 }
460 }
461
462 /**
463 * Gets the minimum error that will be reported to the log.
464 */
465 G_DebugService.prototype.getLogFileErrorLevel = function() {
466 if (G_GDEBUG) {
467 var level = this.settings_.getSetting(this.logFileErrorLevelPrefName_,
468 G_DebugService.ERROR_LEVEL_EXCEPTION);
469
470 return level.toUpperCase();
471 }
472 }
473
474 /**
475 * Sets the minimum error level that will be reported to the log.
476 */
477 G_DebugService.prototype.setLogFileErrorLevel = function(level) {
478 if (G_GDEBUG) {
479 // normalize case just to make it slightly easier to not screw up.
480 level = level.toUpperCase();
481
482 if (level != G_DebugService.ERROR_LEVEL_INFO &&
483 level != G_DebugService.ERROR_LEVEL_WARNING &&
484 level != G_DebugService.ERROR_LEVEL_EXCEPTION) {
485 throw new Error("Invalid error level specified: {" + level + "}");
486 }
487
488 this.settings_.setDefault(this.logFileErrorLevelPrefName_, level);
489 }
490 }
491
492 /**
493 * Internal dump() method
494 *
495 * @param msg String of message to dump
496 */
497 G_DebugService.prototype.dump = function(msg) {
498 if (G_GDEBUG) {
499 dump(msg);
500
501 if (this.alsoDumpToConsole()) {
502 try {
503 var console = Components.classes['@mozilla.org/consoleservice;1']
504 .getService(Components.interfaces.nsIConsoleService);
505 console.logStringMessage(msg);
506 } catch(e) {
507 dump("G_DebugZone ERROR: COULD NOT DUMP TO CONSOLE\n");
508 }
509 }
510
511 this.maybeDumpToFile(msg);
512 }
513 }
514
515 /**
516 * Writes the specified message to the log file, if file logging is enabled.
517 */
518 G_DebugService.prototype.maybeDumpToFile = function(msg) {
519 if (this.logFileIsEnabled() && this.logFile_) {
520
521 /* try to get the correct line end character for this platform */
522 if (!this._LINE_END_CHAR)
523 this._LINE_END_CHAR =
524 Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
525 .OS == "WINNT" ? "\r\n" : "\n";
526 if (this._LINE_END_CHAR != "\n")
527 msg = msg.replace(/\n/g, this._LINE_END_CHAR);
528
529 try {
530 var stream = Cc["@mozilla.org/network/file-output-stream;1"]
531 .createInstance(Ci.nsIFileOutputStream);
532 stream.init(this.logFile_,
533 0x02 | 0x08 | 0x10 /* PR_WRONLY | PR_CREATE_FILE | PR_APPEND */
534 -1 /* default perms */, 0 /* no special behavior */);
535 stream.write(msg, msg.length);
536 } finally {
537 stream.close();
538 }
539 }
540 }
541
542 /**
543 * Implements nsIConsoleListener.observe(). Gets called when an error message
544 * gets reported to the console and sends it to the log file as well.
545 */
546 G_DebugService.prototype.observe = function(consoleMessage) {
547 if (G_GDEBUG) {
548 var errorLevel = this.getLogFileErrorLevel();
549
550 // consoleMessage can be either nsIScriptError or nsIConsoleMessage. The
551 // latter does not have things like line number, etc. So we special case
552 // it first.
553 if (!(consoleMessage instanceof Ci.nsIScriptError)) {
554 // Only report these messages if the error level is INFO.
555 if (errorLevel == G_DebugService.ERROR_LEVEL_INFO) {
556 this.maybeDumpToFile(G_DebugService.ERROR_LEVEL_INFO + ": " +
557 consoleMessage.message + "\n");
558 }
559
560 return;
561 }
562
563 // We make a local copy of these fields because writing to it doesn't seem
564 // to work.
565 var flags = consoleMessage.flags;
566 var sourceName = consoleMessage.sourceName;
567 var lineNumber = consoleMessage.lineNumber;
568
569 // Sometimes, a scripterror instance won't have any flags set. We
570 // default to exception.
571 if (!flags) {
572 flags = Ci.nsIScriptError.exceptionFlag;
573 }
574
575 // Default the filename and line number if they aren't set.
576 if (!sourceName) {
577 sourceName = "<unknown>";
578 }
579
580 if (!lineNumber) {
581 lineNumber = "<unknown>";
582 }
583
584 // Report the error in the log file.
585 if (flags & Ci.nsIScriptError.warningFlag) {
586 // Only report warnings if the error level is warning or better.
587 if (errorLevel == G_DebugService.ERROR_LEVEL_WARNING ||
588 errorLevel == G_DebugService.ERROR_LEVEL_INFO) {
589 this.reportScriptError_(consoleMessage.message,
590 sourceName,
591 lineNumber,
592 G_DebugService.ERROR_LEVEL_WARNING);
593 }
594 } else if (flags & Ci.nsIScriptError.exceptionFlag) {
595 // Always report exceptions.
596 this.reportScriptError_(consoleMessage.message,
597 sourceName,
598 lineNumber,
599 G_DebugService.ERROR_LEVEL_EXCEPTION);
600 }
601 }
602 }
603
604 /**
605 * Private helper to report an nsIScriptError instance to the log/console.
606 */
607 G_DebugService.prototype.reportScriptError_ = function(message, sourceName,
608 lineNumber, label) {
609 message = "\n------------------------------------------------------------\n" +
610 label + ": " + message +
611 "\nlocation: " + sourceName + ", " + "line: " + lineNumber +
612 "\n------------------------------------------------------------\n\n";
613
614 dump(message);
615 this.maybeDumpToFile(message);
616 }
617
618
619
620 /**
621 * A class that instruments methods so they output a call trace,
622 * including the values of their actual parameters and return value.
623 * This code is mostly stolen from Aaron Boodman's original
624 * implementation in clobber utils.
625 *
626 * Note that this class uses the "loggifier" debug zone, so you'll see
627 * a complete call trace when that zone is enabled.
628 *
629 * @constructor
630 */
631 function G_Loggifier() {
632 if (G_GDEBUG) {
633 // Careful not to loggify ourselves!
634 this.mark_(this);
635 }
636 }
637
638 /**
639 * Marks an object as having been loggified. Loggification is not
640 * idempotent :)
641 *
642 * @param obj Object to be marked
643 */
644 G_Loggifier.prototype.mark_ = function(obj) {
645 if (G_GDEBUG) {
646 obj.__loggified_ = true;
647 }
648 }
649
650 /**
651 * @param obj Object to be examined
652 * @returns Boolean indicating if the object has been loggified
653 */
654 G_Loggifier.prototype.isLoggified = function(obj) {
655 if (G_GDEBUG) {
656 return !!obj.__loggified_;
657 }
658 }
659
660 /**
661 * Attempt to extract the class name from the constructor definition.
662 * Assumes the object was created using new.
663 *
664 * @param constructor String containing the definition of a constructor,
665 * for example what you'd get by examining obj.constructor
666 * @returns Name of the constructor/object if it could be found, else "???"
667 */
668 G_Loggifier.prototype.getFunctionName_ = function(constructor) {
669 if (G_GDEBUG) {
670 return constructor.name || "???";
671 }
672 }
673
674 /**
675 * Wraps all the methods in an object so that call traces are
676 * automatically outputted.
677 *
678 * @param obj Object to loggify. SHOULD BE THE PROTOTYPE OF A USER-DEFINED
679 * object. You can get into trouble if you attempt to
680 * loggify something that isn't, for example the Window.
681 *
682 * Any additional parameters are considered method names which should not be
683 * loggified.
684 *
685 * Usage:
686 * G_debugService.loggifier.loggify(MyClass.prototype,
687 * "firstMethodNotToLog",
688 * "secondMethodNotToLog",
689 * ... etc ...);
690 */
691 G_Loggifier.prototype.loggify = function(obj) {
692 if (G_GDEBUG) {
693 if (!G_debugService.callTracingEnabled()) {
694 return;
695 }
696
697 if (typeof window != "undefined" && obj == window ||
698 this.isLoggified(obj)) // Don't go berserk!
699 return;
700
701 var zone = G_GetDebugZone(obj);
702 if (!zone || !zone.zoneIsEnabled()) {
703 return;
704 }
705
706 this.mark_(obj);
707
708 // Helper function returns an instrumented version of
709 // objName.meth, with "this" bound properly. (BTW, because we're
710 // in a conditional here, functions will only be defined as
711 // they're encountered during execution, so declare this helper
712 // before using it.)
713
714 function wrap(meth, objName, methName) {
715 return function() {
716
717 // First output the call along with actual parameters
718 var args = new Array(arguments.length);
719 var argsString = "";
720 for (var i = 0; i < args.length; i++) {
721 args[i] = arguments[i];
722 argsString += (i == 0 ? "" : ", ");
723
724 if (typeof args[i] == "function") {
725 argsString += "[function]";
726 } else {
727 argsString += args[i];
728 }
729 }
730
731 G_TraceCall(this, "> " + objName + "." + methName + "(" +
732 argsString + ")");
733
734 // Then run the function, capturing the return value and throws
735 try {
736 var retVal = meth.apply(this, arguments);
737 var reportedRetVal = retVal;
738
739 if (typeof reportedRetVal == "undefined")
740 reportedRetVal = "void";
741 else if (reportedRetVal === "")
742 reportedRetVal = "\"\" (empty string)";
743 } catch (e) {
744 if (e && !e.__logged) {
745 G_TraceCall(this, "Error: " + e.message + ". " +
746 e.fileName + ": " + e.lineNumber);
747 try {
748 e.__logged = true;
749 } catch (e2) {
750 // Sometimes we can't add the __logged flag because it's an
751 // XPC wrapper
752 throw e;
753 }
754 }
755
756 throw e; // Re-throw!
757 }
758
759 // And spit it out already
760 G_TraceCall(
761 this,
762 "< " + objName + "." + methName + ": " + reportedRetVal);
763
764 return retVal;
765 };
766 };
767
768 var ignoreLookup = {};
769
770 if (arguments.length > 1) {
771 for (var i = 1; i < arguments.length; i++) {
772 ignoreLookup[arguments[i]] = true;
773 }
774 }
775
776 // Wrap each method of obj
777 for (var p in obj) {
778 // Work around bug in Firefox. In ffox typeof RegExp is "function",
779 // so make sure this really is a function. Bug as of FFox 1.5b2.
780 if (typeof obj[p] == "function" && obj[p].call && !ignoreLookup[p]) {
781 var objName = this.getFunctionName_(obj.constructor);
782 obj[p] = wrap(obj[p], objName, p);
783 }
784 }
785 }
786 }
787
788
789 /**
790 * Simple abstraction around debug settings. The thing with debug settings is
791 * that we want to be able to specify a default in the application's startup,
792 * but have that default be overridable by the user via their prefs.
793 *
794 * To generalize this, we package up a dictionary of defaults with the
795 * preferences tree. If a setting isn't in the preferences tree, then we grab it
796 * from the defaults.
797 */
798 function G_DebugSettings() {
799 this.defaults_ = {};
800 this.prefs_ = new G_Preferences();
801 }
802
803 /**
804 * Returns the value of a settings, optionally defaulting to a given value if it
805 * doesn't exist. If no default is specified, the default is |undefined|.
806 */
807 G_DebugSettings.prototype.getSetting = function(name, opt_default) {
808 var override = this.prefs_.getPref(name, null);
809
810 if (override !== null) {
811 return override;
812 } else if (typeof this.defaults_[name] != "undefined") {
813 return this.defaults_[name];
814 } else {
815 return opt_default;
816 }
817 }
818
819 /**
820 * Sets the default value for a setting. If the user doesn't override it with a
821 * preference, this is the value which will be returned by getSetting().
822 */
823 G_DebugSettings.prototype.setDefault = function(name, val) {
824 this.defaults_[name] = val;
825 }
826
827 var G_debugService = new G_DebugService(); // Instantiate us!
828
829 if (G_GDEBUG) {
830 G_debugService.enableAllZones();
831 }
832
833 #else
834
835 // Stubs for the debugging aids scattered through this component.
836 // They will be expanded if you compile yourself a debug build.
837
838 function G_Debug(who, msg) { }
839 function G_Assert(who, condition, msg) { }
840 function G_Error(who, msg) { }
841 var G_debugService = { __noSuchMethod__: function() { } };
842
843 #endif

mercurial