Moved web root into root of project; this makes deployment easier.

Also deleted 'docs', which is now redundant.
This commit is contained in:
Simon Brooke 2020-02-27 14:18:29 +00:00
parent a5204c66b9
commit 743d8a1740
No known key found for this signature in database
GPG key ID: A7A4F18D1D4DF987
1592 changed files with 53626 additions and 139250 deletions

View file

@ -0,0 +1,632 @@
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Logging and debugging utilities.
*
* @see ../demos/debug.html
*/
goog.provide('goog.debug');
goog.require('goog.array');
goog.require('goog.debug.errorcontext');
goog.require('goog.userAgent');
/** @define {boolean} Whether logging should be enabled. */
goog.define('goog.debug.LOGGING_ENABLED', goog.DEBUG);
/** @define {boolean} Whether to force "sloppy" stack building. */
goog.define('goog.debug.FORCE_SLOPPY_STACKS', false);
/**
* Catches onerror events fired by windows and similar objects.
* @param {function(Object)} logFunc The function to call with the error
* information.
* @param {boolean=} opt_cancel Whether to stop the error from reaching the
* browser.
* @param {Object=} opt_target Object that fires onerror events.
*/
goog.debug.catchErrors = function(logFunc, opt_cancel, opt_target) {
var target = opt_target || goog.global;
var oldErrorHandler = target.onerror;
var retVal = !!opt_cancel;
// Chrome interprets onerror return value backwards (http://crbug.com/92062)
// until it was fixed in webkit revision r94061 (Webkit 535.3). This
// workaround still needs to be skipped in Safari after the webkit change
// gets pushed out in Safari.
// See https://bugs.webkit.org/show_bug.cgi?id=67119
if (goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('535.3')) {
retVal = !retVal;
}
/**
* New onerror handler for this target. This onerror handler follows the spec
* according to
* http://www.whatwg.org/specs/web-apps/current-work/#runtime-script-errors
* The spec was changed in August 2013 to support receiving column information
* and an error object for all scripts on the same origin or cross origin
* scripts with the proper headers. See
* https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
*
* @param {string} message The error message. For cross-origin errors, this
* will be scrubbed to just "Script error.". For new browsers that have
* updated to follow the latest spec, errors that come from origins that
* have proper cross origin headers will not be scrubbed.
* @param {string} url The URL of the script that caused the error. The URL
* will be scrubbed to "" for cross origin scripts unless the script has
* proper cross origin headers and the browser has updated to the latest
* spec.
* @param {number} line The line number in the script that the error
* occurred on.
* @param {number=} opt_col The optional column number that the error
* occurred on. Only browsers that have updated to the latest spec will
* include this.
* @param {Error=} opt_error The optional actual error object for this
* error that should include the stack. Only browsers that have updated
* to the latest spec will inlude this parameter.
* @return {boolean} Whether to prevent the error from reaching the browser.
*/
target.onerror = function(message, url, line, opt_col, opt_error) {
if (oldErrorHandler) {
oldErrorHandler(message, url, line, opt_col, opt_error);
}
logFunc({
message: message,
fileName: url,
line: line,
col: opt_col,
error: opt_error
});
return retVal;
};
};
/**
* Creates a string representing an object and all its properties.
* @param {Object|null|undefined} obj Object to expose.
* @param {boolean=} opt_showFn Show the functions as well as the properties,
* default is false.
* @return {string} The string representation of {@code obj}.
*/
goog.debug.expose = function(obj, opt_showFn) {
if (typeof obj == 'undefined') {
return 'undefined';
}
if (obj == null) {
return 'NULL';
}
var str = [];
for (var x in obj) {
if (!opt_showFn && goog.isFunction(obj[x])) {
continue;
}
var s = x + ' = ';
try {
s += obj[x];
} catch (e) {
s += '*** ' + e + ' ***';
}
str.push(s);
}
return str.join('\n');
};
/**
* Creates a string representing a given primitive or object, and for an
* object, all its properties and nested objects. NOTE: The output will include
* Uids on all objects that were exposed. Any added Uids will be removed before
* returning.
* @param {*} obj Object to expose.
* @param {boolean=} opt_showFn Also show properties that are functions (by
* default, functions are omitted).
* @return {string} A string representation of {@code obj}.
*/
goog.debug.deepExpose = function(obj, opt_showFn) {
var str = [];
// Track any objects where deepExpose added a Uid, so they can be cleaned up
// before return. We do this globally, rather than only on ancestors so that
// if the same object appears in the output, you can see it.
var uidsToCleanup = [];
var ancestorUids = {};
var helper = function(obj, space) {
var nestspace = space + ' ';
var indentMultiline = function(str) {
return str.replace(/\n/g, '\n' + space);
};
try {
if (!goog.isDef(obj)) {
str.push('undefined');
} else if (goog.isNull(obj)) {
str.push('NULL');
} else if (goog.isString(obj)) {
str.push('"' + indentMultiline(obj) + '"');
} else if (goog.isFunction(obj)) {
str.push(indentMultiline(String(obj)));
} else if (goog.isObject(obj)) {
// Add a Uid if needed. The struct calls implicitly adds them.
if (!goog.hasUid(obj)) {
uidsToCleanup.push(obj);
}
var uid = goog.getUid(obj);
if (ancestorUids[uid]) {
str.push('*** reference loop detected (id=' + uid + ') ***');
} else {
ancestorUids[uid] = true;
str.push('{');
for (var x in obj) {
if (!opt_showFn && goog.isFunction(obj[x])) {
continue;
}
str.push('\n');
str.push(nestspace);
str.push(x + ' = ');
helper(obj[x], nestspace);
}
str.push('\n' + space + '}');
delete ancestorUids[uid];
}
} else {
str.push(obj);
}
} catch (e) {
str.push('*** ' + e + ' ***');
}
};
helper(obj, '');
// Cleanup any Uids that were added by the deepExpose.
for (var i = 0; i < uidsToCleanup.length; i++) {
goog.removeUid(uidsToCleanup[i]);
}
return str.join('');
};
/**
* Recursively outputs a nested array as a string.
* @param {Array<?>} arr The array.
* @return {string} String representing nested array.
*/
goog.debug.exposeArray = function(arr) {
var str = [];
for (var i = 0; i < arr.length; i++) {
if (goog.isArray(arr[i])) {
str.push(goog.debug.exposeArray(arr[i]));
} else {
str.push(arr[i]);
}
}
return '[ ' + str.join(', ') + ' ]';
};
/**
* Normalizes the error/exception object between browsers.
* @param {*} err Raw error object.
* @return {!{
* message: (?|undefined),
* name: (?|undefined),
* lineNumber: (?|undefined),
* fileName: (?|undefined),
* stack: (?|undefined)
* }} Normalized error object.
*/
goog.debug.normalizeErrorObject = function(err) {
var href = goog.getObjectByName('window.location.href');
if (goog.isString(err)) {
return {
'message': err,
'name': 'Unknown error',
'lineNumber': 'Not available',
'fileName': href,
'stack': 'Not available'
};
}
var lineNumber, fileName;
var threwError = false;
try {
lineNumber = err.lineNumber || err.line || 'Not available';
} catch (e) {
// Firefox 2 sometimes throws an error when accessing 'lineNumber':
// Message: Permission denied to get property UnnamedClass.lineNumber
lineNumber = 'Not available';
threwError = true;
}
try {
fileName = err.fileName || err.filename || err.sourceURL ||
// $googDebugFname may be set before a call to eval to set the filename
// that the eval is supposed to present.
goog.global['$googDebugFname'] || href;
} catch (e) {
// Firefox 2 may also throw an error when accessing 'filename'.
fileName = 'Not available';
threwError = true;
}
// The IE Error object contains only the name and the message.
// The Safari Error object uses the line and sourceURL fields.
if (threwError || !err.lineNumber || !err.fileName || !err.stack ||
!err.message || !err.name) {
return {
'message': err.message || 'Not available',
'name': err.name || 'UnknownError',
'lineNumber': lineNumber,
'fileName': fileName,
'stack': err.stack || 'Not available'
};
}
// Standards error object
// Typed !Object. Should be a subtype of the return type, but it's not.
return /** @type {?} */ (err);
};
/**
* Converts an object to an Error using the object's toString if it's not
* already an Error, adds a stacktrace if there isn't one, and optionally adds
* an extra message.
* @param {*} err The original thrown error, object, or string.
* @param {string=} opt_message optional additional message to add to the
* error.
* @return {!Error} If err is an Error, it is enhanced and returned. Otherwise,
* it is converted to an Error which is enhanced and returned.
*/
goog.debug.enhanceError = function(err, opt_message) {
var error;
if (!(err instanceof Error)) {
error = Error(err);
if (Error.captureStackTrace) {
// Trim this function off the call stack, if we can.
Error.captureStackTrace(error, goog.debug.enhanceError);
}
} else {
error = err;
}
if (!error.stack) {
error.stack = goog.debug.getStacktrace(goog.debug.enhanceError);
}
if (opt_message) {
// find the first unoccupied 'messageX' property
var x = 0;
while (error['message' + x]) {
++x;
}
error['message' + x] = String(opt_message);
}
return error;
};
/**
* Converts an object to an Error using the object's toString if it's not
* already an Error, adds a stacktrace if there isn't one, and optionally adds
* context to the Error, which is reported by the closure error reporter.
* @param {*} err The original thrown error, object, or string.
* @param {!Object<string, string>=} opt_context Key-value context to add to the
* Error.
* @return {!Error} If err is an Error, it is enhanced and returned. Otherwise,
* it is converted to an Error which is enhanced and returned.
*/
goog.debug.enhanceErrorWithContext = function(err, opt_context) {
var error = goog.debug.enhanceError(err);
if (opt_context) {
for (var key in opt_context) {
goog.debug.errorcontext.addErrorContext(error, key, opt_context[key]);
}
}
return error;
};
/**
* Gets the current stack trace. Simple and iterative - doesn't worry about
* catching circular references or getting the args.
* @param {number=} opt_depth Optional maximum depth to trace back to.
* @return {string} A string with the function names of all functions in the
* stack, separated by \n.
* @suppress {es5Strict}
*/
goog.debug.getStacktraceSimple = function(opt_depth) {
if (!goog.debug.FORCE_SLOPPY_STACKS) {
var stack = goog.debug.getNativeStackTrace_(goog.debug.getStacktraceSimple);
if (stack) {
return stack;
}
// NOTE: browsers that have strict mode support also have native "stack"
// properties. Fall-through for legacy browser support.
}
var sb = [];
var fn = arguments.callee.caller;
var depth = 0;
while (fn && (!opt_depth || depth < opt_depth)) {
sb.push(goog.debug.getFunctionName(fn));
sb.push('()\n');
try {
fn = fn.caller;
} catch (e) {
sb.push('[exception trying to get caller]\n');
break;
}
depth++;
if (depth >= goog.debug.MAX_STACK_DEPTH) {
sb.push('[...long stack...]');
break;
}
}
if (opt_depth && depth >= opt_depth) {
sb.push('[...reached max depth limit...]');
} else {
sb.push('[end]');
}
return sb.join('');
};
/**
* Max length of stack to try and output
* @type {number}
*/
goog.debug.MAX_STACK_DEPTH = 50;
/**
* @param {Function} fn The function to start getting the trace from.
* @return {?string}
* @private
*/
goog.debug.getNativeStackTrace_ = function(fn) {
var tempErr = new Error();
if (Error.captureStackTrace) {
Error.captureStackTrace(tempErr, fn);
return String(tempErr.stack);
} else {
// IE10, only adds stack traces when an exception is thrown.
try {
throw tempErr;
} catch (e) {
tempErr = e;
}
var stack = tempErr.stack;
if (stack) {
return String(stack);
}
}
return null;
};
/**
* Gets the current stack trace, either starting from the caller or starting
* from a specified function that's currently on the call stack.
* @param {?Function=} fn If provided, when collecting the stack trace all
* frames above the topmost call to this function, including that call,
* will be left out of the stack trace.
* @return {string} Stack trace.
* @suppress {es5Strict}
*/
goog.debug.getStacktrace = function(fn) {
var stack;
if (!goog.debug.FORCE_SLOPPY_STACKS) {
// Try to get the stack trace from the environment if it is available.
var contextFn = fn || goog.debug.getStacktrace;
stack = goog.debug.getNativeStackTrace_(contextFn);
}
if (!stack) {
// NOTE: browsers that have strict mode support also have native "stack"
// properties. This function will throw in strict mode.
stack = goog.debug.getStacktraceHelper_(fn || arguments.callee.caller, []);
}
return stack;
};
/**
* Private helper for getStacktrace().
* @param {?Function} fn If provided, when collecting the stack trace all
* frames above the topmost call to this function, including that call,
* will be left out of the stack trace.
* @param {Array<!Function>} visited List of functions visited so far.
* @return {string} Stack trace starting from function fn.
* @suppress {es5Strict}
* @private
*/
goog.debug.getStacktraceHelper_ = function(fn, visited) {
var sb = [];
// Circular reference, certain functions like bind seem to cause a recursive
// loop so we need to catch circular references
if (goog.array.contains(visited, fn)) {
sb.push('[...circular reference...]');
// Traverse the call stack until function not found or max depth is reached
} else if (fn && visited.length < goog.debug.MAX_STACK_DEPTH) {
sb.push(goog.debug.getFunctionName(fn) + '(');
var args = fn.arguments;
// Args may be null for some special functions such as host objects or eval.
for (var i = 0; args && i < args.length; i++) {
if (i > 0) {
sb.push(', ');
}
var argDesc;
var arg = args[i];
switch (typeof arg) {
case 'object':
argDesc = arg ? 'object' : 'null';
break;
case 'string':
argDesc = arg;
break;
case 'number':
argDesc = String(arg);
break;
case 'boolean':
argDesc = arg ? 'true' : 'false';
break;
case 'function':
argDesc = goog.debug.getFunctionName(arg);
argDesc = argDesc ? argDesc : '[fn]';
break;
case 'undefined':
default:
argDesc = typeof arg;
break;
}
if (argDesc.length > 40) {
argDesc = argDesc.substr(0, 40) + '...';
}
sb.push(argDesc);
}
visited.push(fn);
sb.push(')\n');
try {
sb.push(goog.debug.getStacktraceHelper_(fn.caller, visited));
} catch (e) {
sb.push('[exception trying to get caller]\n');
}
} else if (fn) {
sb.push('[...long stack...]');
} else {
sb.push('[end]');
}
return sb.join('');
};
/**
* Set a custom function name resolver.
* @param {function(Function): string} resolver Resolves functions to their
* names.
*/
goog.debug.setFunctionResolver = function(resolver) {
goog.debug.fnNameResolver_ = resolver;
};
/**
* Gets a function name
* @param {Function} fn Function to get name of.
* @return {string} Function's name.
*/
goog.debug.getFunctionName = function(fn) {
if (goog.debug.fnNameCache_[fn]) {
return goog.debug.fnNameCache_[fn];
}
if (goog.debug.fnNameResolver_) {
var name = goog.debug.fnNameResolver_(fn);
if (name) {
goog.debug.fnNameCache_[fn] = name;
return name;
}
}
// Heuristically determine function name based on code.
var functionSource = String(fn);
if (!goog.debug.fnNameCache_[functionSource]) {
var matches = /function ([^\(]+)/.exec(functionSource);
if (matches) {
var method = matches[1];
goog.debug.fnNameCache_[functionSource] = method;
} else {
goog.debug.fnNameCache_[functionSource] = '[Anonymous]';
}
}
return goog.debug.fnNameCache_[functionSource];
};
/**
* Makes whitespace visible by replacing it with printable characters.
* This is useful in finding diffrences between the expected and the actual
* output strings of a testcase.
* @param {string} string whose whitespace needs to be made visible.
* @return {string} string whose whitespace is made visible.
*/
goog.debug.makeWhitespaceVisible = function(string) {
return string.replace(/ /g, '[_]')
.replace(/\f/g, '[f]')
.replace(/\n/g, '[n]\n')
.replace(/\r/g, '[r]')
.replace(/\t/g, '[t]');
};
/**
* Returns the type of a value. If a constructor is passed, and a suitable
* string cannot be found, 'unknown type name' will be returned.
*
* <p>Forked rather than moved from {@link goog.asserts.getType_}
* to avoid adding a dependency to goog.asserts.
* @param {*} value A constructor, object, or primitive.
* @return {string} The best display name for the value, or 'unknown type name'.
*/
goog.debug.runtimeType = function(value) {
if (value instanceof Function) {
return value.displayName || value.name || 'unknown type name';
} else if (value instanceof Object) {
return value.constructor.displayName || value.constructor.name ||
Object.prototype.toString.call(value);
} else {
return value === null ? 'null' : typeof value;
}
};
/**
* Hash map for storing function names that have already been looked up.
* @type {Object}
* @private
*/
goog.debug.fnNameCache_ = {};
/**
* Resolves functions to their names. Resolved function names will be cached.
* @type {function(Function):string}
* @private
*/
goog.debug.fnNameResolver_;

View file

@ -0,0 +1,159 @@
// Copyright 2010 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview A global registry for entry points into a program,
* so that they can be instrumented. Each module should register their
* entry points with this registry. Designed to be compiled out
* if no instrumentation is requested.
*
* Entry points may be registered before or after a call to
* goog.debug.entryPointRegistry.monitorAll. If an entry point is registered
* later, the existing monitor will instrument the new entry point.
*
* @author nicksantos@google.com (Nick Santos)
*/
goog.provide('goog.debug.EntryPointMonitor');
goog.provide('goog.debug.entryPointRegistry');
goog.require('goog.asserts');
/**
* @interface
*/
goog.debug.EntryPointMonitor = function() {};
/**
* Instruments a function.
*
* @param {!Function} fn A function to instrument.
* @return {!Function} The instrumented function.
*/
goog.debug.EntryPointMonitor.prototype.wrap;
/**
* Try to remove an instrumentation wrapper created by this monitor.
* If the function passed to unwrap is not a wrapper created by this
* monitor, then we will do nothing.
*
* Notice that some wrappers may not be unwrappable. For example, if other
* monitors have applied their own wrappers, then it will be impossible to
* unwrap them because their wrappers will have captured our wrapper.
*
* So it is important that entry points are unwrapped in the reverse
* order that they were wrapped.
*
* @param {!Function} fn A function to unwrap.
* @return {!Function} The unwrapped function, or {@code fn} if it was not
* a wrapped function created by this monitor.
*/
goog.debug.EntryPointMonitor.prototype.unwrap;
/**
* An array of entry point callbacks.
* @type {!Array<function(!Function)>}
* @private
*/
goog.debug.entryPointRegistry.refList_ = [];
/**
* Monitors that should wrap all the entry points.
* @type {!Array<!goog.debug.EntryPointMonitor>}
* @private
*/
goog.debug.entryPointRegistry.monitors_ = [];
/**
* Whether goog.debug.entryPointRegistry.monitorAll has ever been called.
* Checking this allows the compiler to optimize out the registrations.
* @type {boolean}
* @private
*/
goog.debug.entryPointRegistry.monitorsMayExist_ = false;
/**
* Register an entry point with this module.
*
* The entry point will be instrumented when a monitor is passed to
* goog.debug.entryPointRegistry.monitorAll. If this has already occurred, the
* entry point is instrumented immediately.
*
* @param {function(!Function)} callback A callback function which is called
* with a transforming function to instrument the entry point. The callback
* is responsible for wrapping the relevant entry point with the
* transforming function.
*/
goog.debug.entryPointRegistry.register = function(callback) {
// Don't use push(), so that this can be compiled out.
goog.debug.entryPointRegistry
.refList_[goog.debug.entryPointRegistry.refList_.length] = callback;
// If no one calls monitorAll, this can be compiled out.
if (goog.debug.entryPointRegistry.monitorsMayExist_) {
var monitors = goog.debug.entryPointRegistry.monitors_;
for (var i = 0; i < monitors.length; i++) {
callback(goog.bind(monitors[i].wrap, monitors[i]));
}
}
};
/**
* Configures a monitor to wrap all entry points.
*
* Entry points that have already been registered are immediately wrapped by
* the monitor. When an entry point is registered in the future, it will also
* be wrapped by the monitor when it is registered.
*
* @param {!goog.debug.EntryPointMonitor} monitor An entry point monitor.
*/
goog.debug.entryPointRegistry.monitorAll = function(monitor) {
goog.debug.entryPointRegistry.monitorsMayExist_ = true;
var transformer = goog.bind(monitor.wrap, monitor);
for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
goog.debug.entryPointRegistry.refList_[i](transformer);
}
goog.debug.entryPointRegistry.monitors_.push(monitor);
};
/**
* Try to unmonitor all the entry points that have already been registered. If
* an entry point is registered in the future, it will not be wrapped by the
* monitor when it is registered. Note that this may fail if the entry points
* have additional wrapping.
*
* @param {!goog.debug.EntryPointMonitor} monitor The last monitor to wrap
* the entry points.
* @throws {Error} If the monitor is not the most recently configured monitor.
*/
goog.debug.entryPointRegistry.unmonitorAllIfPossible = function(monitor) {
var monitors = goog.debug.entryPointRegistry.monitors_;
goog.asserts.assert(
monitor == monitors[monitors.length - 1],
'Only the most recent monitor can be unwrapped.');
var transformer = goog.bind(monitor.unwrap, monitor);
for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
goog.debug.entryPointRegistry.refList_[i](transformer);
}
monitors.length--;
};

View file

@ -0,0 +1,63 @@
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Provides a base class for custom Error objects such that the
* stack is correctly maintained.
*
* You should never need to throw goog.debug.Error(msg) directly, Error(msg) is
* sufficient.
*
*/
goog.provide('goog.debug.Error');
/**
* Base class for custom error objects.
* @param {*=} opt_msg The message associated with the error.
* @constructor
* @extends {Error}
*/
goog.debug.Error = function(opt_msg) {
// Attempt to ensure there is a stack trace.
if (Error.captureStackTrace) {
Error.captureStackTrace(this, goog.debug.Error);
} else {
var stack = new Error().stack;
if (stack) {
this.stack = stack;
}
}
if (opt_msg) {
this.message = String(opt_msg);
}
/**
* Whether to report this error to the server. Setting this to false will
* cause the error reporter to not report the error back to the server,
* which can be useful if the client knows that the error has already been
* logged on the server.
* @type {boolean}
*/
this.reportErrorToServer = true;
};
goog.inherits(goog.debug.Error, Error);
/** @override */
goog.debug.Error.prototype.name = 'CustomError';

View file

@ -0,0 +1,49 @@
// Copyright 2017 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Provides methods dealing with context on error objects.
*/
goog.provide('goog.debug.errorcontext');
/**
* Adds key-value context to the error.
* @param {!Error} err The error to add context to.
* @param {string} contextKey Key for the context to be added.
* @param {string} contextValue Value for the context to be added.
*/
goog.debug.errorcontext.addErrorContext = function(
err, contextKey, contextValue) {
if (!err[goog.debug.errorcontext.CONTEXT_KEY_]) {
err[goog.debug.errorcontext.CONTEXT_KEY_] = {};
}
err[goog.debug.errorcontext.CONTEXT_KEY_][contextKey] = contextValue;
};
/**
* @param {!Error} err The error to get context from.
* @return {!Object<string, string>} The context of the provided error.
*/
goog.debug.errorcontext.getErrorContext = function(err) {
return err[goog.debug.errorcontext.CONTEXT_KEY_] || {};
};
// TODO(user): convert this to a Symbol once goog.debug.ErrorReporter is
// able to use ES6.
/** @private @const {string} */
goog.debug.errorcontext.CONTEXT_KEY_ = '__closure__error__context__984382';

View file

@ -0,0 +1,148 @@
// Copyright 2010 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview A buffer for log records. The purpose of this is to improve
* logging performance by re-using old objects when the buffer becomes full and
* to eliminate the need for each app to implement their own log buffer. The
* disadvantage to doing this is that log handlers cannot maintain references to
* log records and expect that they are not overwriten at a later point.
*
* @author agrieve@google.com (Andrew Grieve)
*/
goog.provide('goog.debug.LogBuffer');
goog.require('goog.asserts');
goog.require('goog.debug.LogRecord');
/**
* Creates the log buffer.
* @constructor
* @final
*/
goog.debug.LogBuffer = function() {
goog.asserts.assert(
goog.debug.LogBuffer.isBufferingEnabled(),
'Cannot use goog.debug.LogBuffer without defining ' +
'goog.debug.LogBuffer.CAPACITY.');
this.clear();
};
/**
* A static method that always returns the same instance of LogBuffer.
* @return {!goog.debug.LogBuffer} The LogBuffer singleton instance.
*/
goog.debug.LogBuffer.getInstance = function() {
if (!goog.debug.LogBuffer.instance_) {
// This function is written with the return statement after the assignment
// to avoid the jscompiler StripCode bug described in http://b/2608064.
// After that bug is fixed this can be refactored.
goog.debug.LogBuffer.instance_ = new goog.debug.LogBuffer();
}
return goog.debug.LogBuffer.instance_;
};
/**
* @define {number} The number of log records to buffer. 0 means disable
* buffering.
*/
goog.define('goog.debug.LogBuffer.CAPACITY', 0);
/**
* The array to store the records.
* @type {!Array<!goog.debug.LogRecord|undefined>}
* @private
*/
goog.debug.LogBuffer.prototype.buffer_;
/**
* The index of the most recently added record or -1 if there are no records.
* @type {number}
* @private
*/
goog.debug.LogBuffer.prototype.curIndex_;
/**
* Whether the buffer is at capacity.
* @type {boolean}
* @private
*/
goog.debug.LogBuffer.prototype.isFull_;
/**
* Adds a log record to the buffer, possibly overwriting the oldest record.
* @param {goog.debug.Logger.Level} level One of the level identifiers.
* @param {string} msg The string message.
* @param {string} loggerName The name of the source logger.
* @return {!goog.debug.LogRecord} The log record.
*/
goog.debug.LogBuffer.prototype.addRecord = function(level, msg, loggerName) {
var curIndex = (this.curIndex_ + 1) % goog.debug.LogBuffer.CAPACITY;
this.curIndex_ = curIndex;
if (this.isFull_) {
var ret = this.buffer_[curIndex];
ret.reset(level, msg, loggerName);
return ret;
}
this.isFull_ = curIndex == goog.debug.LogBuffer.CAPACITY - 1;
return this.buffer_[curIndex] =
new goog.debug.LogRecord(level, msg, loggerName);
};
/**
* @return {boolean} Whether the log buffer is enabled.
*/
goog.debug.LogBuffer.isBufferingEnabled = function() {
return goog.debug.LogBuffer.CAPACITY > 0;
};
/**
* Removes all buffered log records.
*/
goog.debug.LogBuffer.prototype.clear = function() {
this.buffer_ = new Array(goog.debug.LogBuffer.CAPACITY);
this.curIndex_ = -1;
this.isFull_ = false;
};
/**
* Calls the given function for each buffered log record, starting with the
* oldest one.
* @param {function(!goog.debug.LogRecord)} func The function to call.
*/
goog.debug.LogBuffer.prototype.forEachRecord = function(func) {
var buffer = this.buffer_;
// Corner case: no records.
if (!buffer[0]) {
return;
}
var curIndex = this.curIndex_;
var i = this.isFull_ ? curIndex : -1;
do {
i = (i + 1) % goog.debug.LogBuffer.CAPACITY;
func(/** @type {!goog.debug.LogRecord} */ (buffer[i]));
} while (i != curIndex);
};

View file

@ -0,0 +1,865 @@
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Definition of the Logger class. Please minimize dependencies
* this file has on other closure classes as any dependency it takes won't be
* able to use the logging infrastructure.
*
* @see ../demos/debug.html
*/
goog.provide('goog.debug.LogManager');
goog.provide('goog.debug.Loggable');
goog.provide('goog.debug.Logger');
goog.provide('goog.debug.Logger.Level');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.debug');
goog.require('goog.debug.LogBuffer');
goog.require('goog.debug.LogRecord');
/**
* A message value that can be handled by a Logger.
*
* Functions are treated like callbacks, but are only called when the event's
* log level is enabled. This is useful for logging messages that are expensive
* to construct.
*
* @typedef {string|function(): string}
*/
goog.debug.Loggable;
/**
* The Logger is an object used for logging debug messages. Loggers are
* normally named, using a hierarchical dot-separated namespace. Logger names
* can be arbitrary strings, but they should normally be based on the package
* name or class name of the logged component, such as goog.net.BrowserChannel.
*
* The Logger object is loosely based on the java class
* java.util.logging.Logger. It supports different levels of filtering for
* different loggers.
*
* The logger object should never be instantiated by application code. It
* should always use the goog.debug.Logger.getLogger function.
*
* @constructor
* @param {string} name The name of the Logger.
* @final
*/
goog.debug.Logger = function(name) {
/**
* Name of the Logger. Generally a dot-separated namespace
* @private {string}
*/
this.name_ = name;
/**
* Parent Logger.
* @private {goog.debug.Logger}
*/
this.parent_ = null;
/**
* Level that this logger only filters above. Null indicates it should
* inherit from the parent.
* @private {goog.debug.Logger.Level}
*/
this.level_ = null;
/**
* Map of children loggers. The keys are the leaf names of the children and
* the values are the child loggers.
* @private {Object}
*/
this.children_ = null;
/**
* Handlers that are listening to this logger.
* @private {Array<Function>}
*/
this.handlers_ = null;
};
/** @const */
goog.debug.Logger.ROOT_LOGGER_NAME = '';
/**
* @define {boolean} Toggles whether loggers other than the root logger can have
* log handlers attached to them and whether they can have their log level
* set. Logging is a bit faster when this is set to false.
*/
goog.define('goog.debug.Logger.ENABLE_HIERARCHY', true);
if (!goog.debug.Logger.ENABLE_HIERARCHY) {
/**
* @type {!Array<Function>}
* @private
*/
goog.debug.Logger.rootHandlers_ = [];
/**
* @type {goog.debug.Logger.Level}
* @private
*/
goog.debug.Logger.rootLevel_;
}
/**
* The Level class defines a set of standard logging levels that
* can be used to control logging output. The logging Level objects
* are ordered and are specified by ordered integers. Enabling logging
* at a given level also enables logging at all higher levels.
* <p>
* Clients should normally use the predefined Level constants such
* as Level.SEVERE.
* <p>
* The levels in descending order are:
* <ul>
* <li>SEVERE (highest value)
* <li>WARNING
* <li>INFO
* <li>CONFIG
* <li>FINE
* <li>FINER
* <li>FINEST (lowest value)
* </ul>
* In addition there is a level OFF that can be used to turn
* off logging, and a level ALL that can be used to enable
* logging of all messages.
*
* @param {string} name The name of the level.
* @param {number} value The numeric value of the level.
* @constructor
* @final
*/
goog.debug.Logger.Level = function(name, value) {
/**
* The name of the level
* @type {string}
*/
this.name = name;
/**
* The numeric value of the level
* @type {number}
*/
this.value = value;
};
/**
* @return {string} String representation of the logger level.
* @override
*/
goog.debug.Logger.Level.prototype.toString = function() {
return this.name;
};
/**
* OFF is a special level that can be used to turn off logging.
* This level is initialized to <CODE>Infinity</CODE>.
* @type {!goog.debug.Logger.Level}
*/
goog.debug.Logger.Level.OFF = new goog.debug.Logger.Level('OFF', Infinity);
/**
* SHOUT is a message level for extra debugging loudness.
* This level is initialized to <CODE>1200</CODE>.
* @type {!goog.debug.Logger.Level}
*/
goog.debug.Logger.Level.SHOUT = new goog.debug.Logger.Level('SHOUT', 1200);
/**
* SEVERE is a message level indicating a serious failure.
* This level is initialized to <CODE>1000</CODE>.
* @type {!goog.debug.Logger.Level}
*/
goog.debug.Logger.Level.SEVERE = new goog.debug.Logger.Level('SEVERE', 1000);
/**
* WARNING is a message level indicating a potential problem.
* This level is initialized to <CODE>900</CODE>.
* @type {!goog.debug.Logger.Level}
*/
goog.debug.Logger.Level.WARNING = new goog.debug.Logger.Level('WARNING', 900);
/**
* INFO is a message level for informational messages.
* This level is initialized to <CODE>800</CODE>.
* @type {!goog.debug.Logger.Level}
*/
goog.debug.Logger.Level.INFO = new goog.debug.Logger.Level('INFO', 800);
/**
* CONFIG is a message level for static configuration messages.
* This level is initialized to <CODE>700</CODE>.
* @type {!goog.debug.Logger.Level}
*/
goog.debug.Logger.Level.CONFIG = new goog.debug.Logger.Level('CONFIG', 700);
/**
* FINE is a message level providing tracing information.
* This level is initialized to <CODE>500</CODE>.
* @type {!goog.debug.Logger.Level}
*/
goog.debug.Logger.Level.FINE = new goog.debug.Logger.Level('FINE', 500);
/**
* FINER indicates a fairly detailed tracing message.
* This level is initialized to <CODE>400</CODE>.
* @type {!goog.debug.Logger.Level}
*/
goog.debug.Logger.Level.FINER = new goog.debug.Logger.Level('FINER', 400);
/**
* FINEST indicates a highly detailed tracing message.
* This level is initialized to <CODE>300</CODE>.
* @type {!goog.debug.Logger.Level}
*/
goog.debug.Logger.Level.FINEST = new goog.debug.Logger.Level('FINEST', 300);
/**
* ALL indicates that all messages should be logged.
* This level is initialized to <CODE>0</CODE>.
* @type {!goog.debug.Logger.Level}
*/
goog.debug.Logger.Level.ALL = new goog.debug.Logger.Level('ALL', 0);
/**
* The predefined levels.
* @type {!Array<!goog.debug.Logger.Level>}
* @final
*/
goog.debug.Logger.Level.PREDEFINED_LEVELS = [
goog.debug.Logger.Level.OFF, goog.debug.Logger.Level.SHOUT,
goog.debug.Logger.Level.SEVERE, goog.debug.Logger.Level.WARNING,
goog.debug.Logger.Level.INFO, goog.debug.Logger.Level.CONFIG,
goog.debug.Logger.Level.FINE, goog.debug.Logger.Level.FINER,
goog.debug.Logger.Level.FINEST, goog.debug.Logger.Level.ALL
];
/**
* A lookup map used to find the level object based on the name or value of
* the level object.
* @type {Object}
* @private
*/
goog.debug.Logger.Level.predefinedLevelsCache_ = null;
/**
* Creates the predefined levels cache and populates it.
* @private
*/
goog.debug.Logger.Level.createPredefinedLevelsCache_ = function() {
goog.debug.Logger.Level.predefinedLevelsCache_ = {};
for (var i = 0, level; level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i];
i++) {
goog.debug.Logger.Level.predefinedLevelsCache_[level.value] = level;
goog.debug.Logger.Level.predefinedLevelsCache_[level.name] = level;
}
};
/**
* Gets the predefined level with the given name.
* @param {string} name The name of the level.
* @return {goog.debug.Logger.Level} The level, or null if none found.
*/
goog.debug.Logger.Level.getPredefinedLevel = function(name) {
if (!goog.debug.Logger.Level.predefinedLevelsCache_) {
goog.debug.Logger.Level.createPredefinedLevelsCache_();
}
return goog.debug.Logger.Level.predefinedLevelsCache_[name] || null;
};
/**
* Gets the highest predefined level <= #value.
* @param {number} value Level value.
* @return {goog.debug.Logger.Level} The level, or null if none found.
*/
goog.debug.Logger.Level.getPredefinedLevelByValue = function(value) {
if (!goog.debug.Logger.Level.predefinedLevelsCache_) {
goog.debug.Logger.Level.createPredefinedLevelsCache_();
}
if (value in /** @type {!Object} */ (
goog.debug.Logger.Level.predefinedLevelsCache_)) {
return goog.debug.Logger.Level.predefinedLevelsCache_[value];
}
for (var i = 0; i < goog.debug.Logger.Level.PREDEFINED_LEVELS.length; ++i) {
var level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i];
if (level.value <= value) {
return level;
}
}
return null;
};
/**
* Finds or creates a logger for a named subsystem. If a logger has already been
* created with the given name it is returned. Otherwise a new logger is
* created. If a new logger is created its log level will be configured based
* on the LogManager configuration and it will configured to also send logging
* output to its parent's handlers. It will be registered in the LogManager
* global namespace.
*
* @param {string} name A name for the logger. This should be a dot-separated
* name and should normally be based on the package name or class name of the
* subsystem, such as goog.net.BrowserChannel.
* @return {!goog.debug.Logger} The named logger.
* @deprecated use {@link goog.log} instead.
*/
goog.debug.Logger.getLogger = function(name) {
return goog.debug.LogManager.getLogger(name);
};
/**
* Logs a message to profiling tools, if available.
* {@see https://developers.google.com/web-toolkit/speedtracer/logging-api}
* {@see http://msdn.microsoft.com/en-us/library/dd433074(VS.85).aspx}
* @param {string} msg The message to log.
*/
goog.debug.Logger.logToProfilers = function(msg) {
// Using goog.global, as loggers might be used in window-less contexts.
var console = goog.global['console'];
if (console && console['timeStamp']) {
// Logs a message to Firebug, Web Inspector, SpeedTracer, etc.
console['timeStamp'](msg);
}
var msWriteProfilerMark = goog.global['msWriteProfilerMark'];
if (msWriteProfilerMark) {
// Logs a message to the Microsoft profiler
msWriteProfilerMark(msg);
}
};
/**
* Gets the name of this logger.
* @return {string} The name of this logger.
*/
goog.debug.Logger.prototype.getName = function() {
return this.name_;
};
/**
* Adds a handler to the logger. This doesn't use the event system because
* we want to be able to add logging to the event system.
* @param {Function} handler Handler function to add.
*/
goog.debug.Logger.prototype.addHandler = function(handler) {
if (goog.debug.LOGGING_ENABLED) {
if (goog.debug.Logger.ENABLE_HIERARCHY) {
if (!this.handlers_) {
this.handlers_ = [];
}
this.handlers_.push(handler);
} else {
goog.asserts.assert(
!this.name_, 'Cannot call addHandler on a non-root logger when ' +
'goog.debug.Logger.ENABLE_HIERARCHY is false.');
goog.debug.Logger.rootHandlers_.push(handler);
}
}
};
/**
* Removes a handler from the logger. This doesn't use the event system because
* we want to be able to add logging to the event system.
* @param {Function} handler Handler function to remove.
* @return {boolean} Whether the handler was removed.
*/
goog.debug.Logger.prototype.removeHandler = function(handler) {
if (goog.debug.LOGGING_ENABLED) {
var handlers = goog.debug.Logger.ENABLE_HIERARCHY ?
this.handlers_ :
goog.debug.Logger.rootHandlers_;
return !!handlers && goog.array.remove(handlers, handler);
} else {
return false;
}
};
/**
* Returns the parent of this logger.
* @return {goog.debug.Logger} The parent logger or null if this is the root.
*/
goog.debug.Logger.prototype.getParent = function() {
return this.parent_;
};
/**
* Returns the children of this logger as a map of the child name to the logger.
* @return {!Object} The map where the keys are the child leaf names and the
* values are the Logger objects.
*/
goog.debug.Logger.prototype.getChildren = function() {
if (!this.children_) {
this.children_ = {};
}
return this.children_;
};
/**
* Set the log level specifying which message levels will be logged by this
* logger. Message levels lower than this value will be discarded.
* The level value Level.OFF can be used to turn off logging. If the new level
* is null, it means that this node should inherit its level from its nearest
* ancestor with a specific (non-null) level value.
*
* @param {goog.debug.Logger.Level} level The new level.
*/
goog.debug.Logger.prototype.setLevel = function(level) {
if (goog.debug.LOGGING_ENABLED) {
if (goog.debug.Logger.ENABLE_HIERARCHY) {
this.level_ = level;
} else {
goog.asserts.assert(
!this.name_, 'Cannot call setLevel() on a non-root logger when ' +
'goog.debug.Logger.ENABLE_HIERARCHY is false.');
goog.debug.Logger.rootLevel_ = level;
}
}
};
/**
* Gets the log level specifying which message levels will be logged by this
* logger. Message levels lower than this value will be discarded.
* The level value Level.OFF can be used to turn off logging. If the level
* is null, it means that this node should inherit its level from its nearest
* ancestor with a specific (non-null) level value.
*
* @return {goog.debug.Logger.Level} The level.
*/
goog.debug.Logger.prototype.getLevel = function() {
return goog.debug.LOGGING_ENABLED ? this.level_ : goog.debug.Logger.Level.OFF;
};
/**
* Returns the effective level of the logger based on its ancestors' levels.
* @return {goog.debug.Logger.Level} The level.
*/
goog.debug.Logger.prototype.getEffectiveLevel = function() {
if (!goog.debug.LOGGING_ENABLED) {
return goog.debug.Logger.Level.OFF;
}
if (!goog.debug.Logger.ENABLE_HIERARCHY) {
return goog.debug.Logger.rootLevel_;
}
if (this.level_) {
return this.level_;
}
if (this.parent_) {
return this.parent_.getEffectiveLevel();
}
goog.asserts.fail('Root logger has no level set.');
return null;
};
/**
* Checks if a message of the given level would actually be logged by this
* logger. This check is based on the Loggers effective level, which may be
* inherited from its parent.
* @param {goog.debug.Logger.Level} level The level to check.
* @return {boolean} Whether the message would be logged.
*/
goog.debug.Logger.prototype.isLoggable = function(level) {
return goog.debug.LOGGING_ENABLED &&
level.value >= this.getEffectiveLevel().value;
};
/**
* Logs a message. If the logger is currently enabled for the
* given message level then the given message is forwarded to all the
* registered output Handler objects.
* @param {goog.debug.Logger.Level} level One of the level identifiers.
* @param {goog.debug.Loggable} msg The message to log.
* @param {Error|Object=} opt_exception An exception associated with the
* message.
*/
goog.debug.Logger.prototype.log = function(level, msg, opt_exception) {
// java caches the effective level, not sure it's necessary here
if (goog.debug.LOGGING_ENABLED && this.isLoggable(level)) {
// Message callbacks can be useful when a log message is expensive to build.
if (goog.isFunction(msg)) {
msg = msg();
}
this.doLogRecord_(this.getLogRecord(level, msg, opt_exception));
}
};
/**
* Creates a new log record and adds the exception (if present) to it.
* @param {goog.debug.Logger.Level} level One of the level identifiers.
* @param {string} msg The string message.
* @param {Error|Object=} opt_exception An exception associated with the
* message.
* @return {!goog.debug.LogRecord} A log record.
* @suppress {es5Strict}
*/
goog.debug.Logger.prototype.getLogRecord = function(level, msg, opt_exception) {
if (goog.debug.LogBuffer.isBufferingEnabled()) {
var logRecord =
goog.debug.LogBuffer.getInstance().addRecord(level, msg, this.name_);
} else {
logRecord = new goog.debug.LogRecord(level, String(msg), this.name_);
}
if (opt_exception) {
logRecord.setException(opt_exception);
}
return logRecord;
};
/**
* Logs a message at the Logger.Level.SHOUT level.
* If the logger is currently enabled for the given message level then the
* given message is forwarded to all the registered output Handler objects.
* @param {goog.debug.Loggable} msg The message to log.
* @param {Error=} opt_exception An exception associated with the message.
*/
goog.debug.Logger.prototype.shout = function(msg, opt_exception) {
if (goog.debug.LOGGING_ENABLED) {
this.log(goog.debug.Logger.Level.SHOUT, msg, opt_exception);
}
};
/**
* Logs a message at the Logger.Level.SEVERE level.
* If the logger is currently enabled for the given message level then the
* given message is forwarded to all the registered output Handler objects.
* @param {goog.debug.Loggable} msg The message to log.
* @param {Error=} opt_exception An exception associated with the message.
*/
goog.debug.Logger.prototype.severe = function(msg, opt_exception) {
if (goog.debug.LOGGING_ENABLED) {
this.log(goog.debug.Logger.Level.SEVERE, msg, opt_exception);
}
};
/**
* Logs a message at the Logger.Level.WARNING level.
* If the logger is currently enabled for the given message level then the
* given message is forwarded to all the registered output Handler objects.
* @param {goog.debug.Loggable} msg The message to log.
* @param {Error=} opt_exception An exception associated with the message.
*/
goog.debug.Logger.prototype.warning = function(msg, opt_exception) {
if (goog.debug.LOGGING_ENABLED) {
this.log(goog.debug.Logger.Level.WARNING, msg, opt_exception);
}
};
/**
* Logs a message at the Logger.Level.INFO level.
* If the logger is currently enabled for the given message level then the
* given message is forwarded to all the registered output Handler objects.
* @param {goog.debug.Loggable} msg The message to log.
* @param {Error=} opt_exception An exception associated with the message.
*/
goog.debug.Logger.prototype.info = function(msg, opt_exception) {
if (goog.debug.LOGGING_ENABLED) {
this.log(goog.debug.Logger.Level.INFO, msg, opt_exception);
}
};
/**
* Logs a message at the Logger.Level.CONFIG level.
* If the logger is currently enabled for the given message level then the
* given message is forwarded to all the registered output Handler objects.
* @param {goog.debug.Loggable} msg The message to log.
* @param {Error=} opt_exception An exception associated with the message.
*/
goog.debug.Logger.prototype.config = function(msg, opt_exception) {
if (goog.debug.LOGGING_ENABLED) {
this.log(goog.debug.Logger.Level.CONFIG, msg, opt_exception);
}
};
/**
* Logs a message at the Logger.Level.FINE level.
* If the logger is currently enabled for the given message level then the
* given message is forwarded to all the registered output Handler objects.
* @param {goog.debug.Loggable} msg The message to log.
* @param {Error=} opt_exception An exception associated with the message.
*/
goog.debug.Logger.prototype.fine = function(msg, opt_exception) {
if (goog.debug.LOGGING_ENABLED) {
this.log(goog.debug.Logger.Level.FINE, msg, opt_exception);
}
};
/**
* Logs a message at the Logger.Level.FINER level.
* If the logger is currently enabled for the given message level then the
* given message is forwarded to all the registered output Handler objects.
* @param {goog.debug.Loggable} msg The message to log.
* @param {Error=} opt_exception An exception associated with the message.
*/
goog.debug.Logger.prototype.finer = function(msg, opt_exception) {
if (goog.debug.LOGGING_ENABLED) {
this.log(goog.debug.Logger.Level.FINER, msg, opt_exception);
}
};
/**
* Logs a message at the Logger.Level.FINEST level.
* If the logger is currently enabled for the given message level then the
* given message is forwarded to all the registered output Handler objects.
* @param {goog.debug.Loggable} msg The message to log.
* @param {Error=} opt_exception An exception associated with the message.
*/
goog.debug.Logger.prototype.finest = function(msg, opt_exception) {
if (goog.debug.LOGGING_ENABLED) {
this.log(goog.debug.Logger.Level.FINEST, msg, opt_exception);
}
};
/**
* Logs a LogRecord. If the logger is currently enabled for the
* given message level then the given message is forwarded to all the
* registered output Handler objects.
* @param {goog.debug.LogRecord} logRecord A log record to log.
*/
goog.debug.Logger.prototype.logRecord = function(logRecord) {
if (goog.debug.LOGGING_ENABLED && this.isLoggable(logRecord.getLevel())) {
this.doLogRecord_(logRecord);
}
};
/**
* Logs a LogRecord.
* @param {goog.debug.LogRecord} logRecord A log record to log.
* @private
*/
goog.debug.Logger.prototype.doLogRecord_ = function(logRecord) {
goog.debug.Logger.logToProfilers('log:' + logRecord.getMessage());
if (goog.debug.Logger.ENABLE_HIERARCHY) {
var target = this;
while (target) {
target.callPublish_(logRecord);
target = target.getParent();
}
} else {
for (var i = 0, handler; handler = goog.debug.Logger.rootHandlers_[i++];) {
handler(logRecord);
}
}
};
/**
* Calls the handlers for publish.
* @param {goog.debug.LogRecord} logRecord The log record to publish.
* @private
*/
goog.debug.Logger.prototype.callPublish_ = function(logRecord) {
if (this.handlers_) {
for (var i = 0, handler; handler = this.handlers_[i]; i++) {
handler(logRecord);
}
}
};
/**
* Sets the parent of this logger. This is used for setting up the logger tree.
* @param {goog.debug.Logger} parent The parent logger.
* @private
*/
goog.debug.Logger.prototype.setParent_ = function(parent) {
this.parent_ = parent;
};
/**
* Adds a child to this logger. This is used for setting up the logger tree.
* @param {string} name The leaf name of the child.
* @param {goog.debug.Logger} logger The child logger.
* @private
*/
goog.debug.Logger.prototype.addChild_ = function(name, logger) {
this.getChildren()[name] = logger;
};
/**
* There is a single global LogManager object that is used to maintain a set of
* shared state about Loggers and log services. This is loosely based on the
* java class java.util.logging.LogManager.
* @const
*/
goog.debug.LogManager = {};
/**
* Map of logger names to logger objects.
*
* @type {!Object<string, !goog.debug.Logger>}
* @private
*/
goog.debug.LogManager.loggers_ = {};
/**
* The root logger which is the root of the logger tree.
* @type {goog.debug.Logger}
* @private
*/
goog.debug.LogManager.rootLogger_ = null;
/**
* Initializes the LogManager if not already initialized.
*/
goog.debug.LogManager.initialize = function() {
if (!goog.debug.LogManager.rootLogger_) {
goog.debug.LogManager.rootLogger_ =
new goog.debug.Logger(goog.debug.Logger.ROOT_LOGGER_NAME);
goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME] =
goog.debug.LogManager.rootLogger_;
goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG);
}
};
/**
* Returns all the loggers.
* @return {!Object<string, !goog.debug.Logger>} Map of logger names to logger
* objects.
*/
goog.debug.LogManager.getLoggers = function() {
return goog.debug.LogManager.loggers_;
};
/**
* Returns the root of the logger tree namespace, the logger with the empty
* string as its name.
*
* @return {!goog.debug.Logger} The root logger.
*/
goog.debug.LogManager.getRoot = function() {
goog.debug.LogManager.initialize();
return /** @type {!goog.debug.Logger} */ (goog.debug.LogManager.rootLogger_);
};
/**
* Finds a named logger.
*
* @param {string} name A name for the logger. This should be a dot-separated
* name and should normally be based on the package name or class name of the
* subsystem, such as goog.net.BrowserChannel.
* @return {!goog.debug.Logger} The named logger.
*/
goog.debug.LogManager.getLogger = function(name) {
goog.debug.LogManager.initialize();
var ret = goog.debug.LogManager.loggers_[name];
return ret || goog.debug.LogManager.createLogger_(name);
};
/**
* Creates a function that can be passed to goog.debug.catchErrors. The function
* will log all reported errors using the given logger.
* @param {goog.debug.Logger=} opt_logger The logger to log the errors to.
* Defaults to the root logger.
* @return {function(Object)} The created function.
*/
goog.debug.LogManager.createFunctionForCatchErrors = function(opt_logger) {
return function(info) {
var logger = opt_logger || goog.debug.LogManager.getRoot();
logger.severe(
'Error: ' + info.message + ' (' + info.fileName + ' @ Line: ' +
info.line + ')');
};
};
/**
* Creates the named logger. Will also create the parents of the named logger
* if they don't yet exist.
* @param {string} name The name of the logger.
* @return {!goog.debug.Logger} The named logger.
* @private
*/
goog.debug.LogManager.createLogger_ = function(name) {
// find parent logger
var logger = new goog.debug.Logger(name);
if (goog.debug.Logger.ENABLE_HIERARCHY) {
var lastDotIndex = name.lastIndexOf('.');
var parentName = name.substr(0, lastDotIndex);
var leafName = name.substr(lastDotIndex + 1);
var parentLogger = goog.debug.LogManager.getLogger(parentName);
// tell the parent about the child and the child about the parent
parentLogger.addChild_(leafName, logger);
logger.setParent_(parentLogger);
}
goog.debug.LogManager.loggers_[name] = logger;
return logger;
};

View file

@ -0,0 +1,242 @@
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Definition of the LogRecord class. Please minimize
* dependencies this file has on other closure classes as any dependency it
* takes won't be able to use the logging infrastructure.
*
*/
goog.provide('goog.debug.LogRecord');
/**
* LogRecord objects are used to pass logging requests between
* the logging framework and individual log Handlers.
* @constructor
* @param {goog.debug.Logger.Level} level One of the level identifiers.
* @param {string} msg The string message.
* @param {string} loggerName The name of the source logger.
* @param {number=} opt_time Time this log record was created if other than now.
* If 0, we use #goog.now.
* @param {number=} opt_sequenceNumber Sequence number of this log record. This
* should only be passed in when restoring a log record from persistence.
*/
goog.debug.LogRecord = function(
level, msg, loggerName, opt_time, opt_sequenceNumber) {
this.reset(level, msg, loggerName, opt_time, opt_sequenceNumber);
};
/**
* Time the LogRecord was created.
* @type {number}
* @private
*/
goog.debug.LogRecord.prototype.time_;
/**
* Level of the LogRecord
* @type {goog.debug.Logger.Level}
* @private
*/
goog.debug.LogRecord.prototype.level_;
/**
* Message associated with the record
* @type {string}
* @private
*/
goog.debug.LogRecord.prototype.msg_;
/**
* Name of the logger that created the record.
* @type {string}
* @private
*/
goog.debug.LogRecord.prototype.loggerName_;
/**
* Sequence number for the LogRecord. Each record has a unique sequence number
* that is greater than all log records created before it.
* @type {number}
* @private
*/
goog.debug.LogRecord.prototype.sequenceNumber_ = 0;
/**
* Exception associated with the record
* @type {Object}
* @private
*/
goog.debug.LogRecord.prototype.exception_ = null;
/**
* @define {boolean} Whether to enable log sequence numbers.
*/
goog.define('goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS', true);
/**
* A sequence counter for assigning increasing sequence numbers to LogRecord
* objects.
* @type {number}
* @private
*/
goog.debug.LogRecord.nextSequenceNumber_ = 0;
/**
* Sets all fields of the log record.
* @param {goog.debug.Logger.Level} level One of the level identifiers.
* @param {string} msg The string message.
* @param {string} loggerName The name of the source logger.
* @param {number=} opt_time Time this log record was created if other than now.
* If 0, we use #goog.now.
* @param {number=} opt_sequenceNumber Sequence number of this log record. This
* should only be passed in when restoring a log record from persistence.
*/
goog.debug.LogRecord.prototype.reset = function(
level, msg, loggerName, opt_time, opt_sequenceNumber) {
if (goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS) {
this.sequenceNumber_ = typeof opt_sequenceNumber == 'number' ?
opt_sequenceNumber :
goog.debug.LogRecord.nextSequenceNumber_++;
}
this.time_ = opt_time || goog.now();
this.level_ = level;
this.msg_ = msg;
this.loggerName_ = loggerName;
delete this.exception_;
};
/**
* Get the source Logger's name.
*
* @return {string} source logger name (may be null).
*/
goog.debug.LogRecord.prototype.getLoggerName = function() {
return this.loggerName_;
};
/**
* Get the exception that is part of the log record.
*
* @return {Object} the exception.
*/
goog.debug.LogRecord.prototype.getException = function() {
return this.exception_;
};
/**
* Set the exception that is part of the log record.
*
* @param {Object} exception the exception.
*/
goog.debug.LogRecord.prototype.setException = function(exception) {
this.exception_ = exception;
};
/**
* Get the source Logger's name.
*
* @param {string} loggerName source logger name (may be null).
*/
goog.debug.LogRecord.prototype.setLoggerName = function(loggerName) {
this.loggerName_ = loggerName;
};
/**
* Get the logging message level, for example Level.SEVERE.
* @return {goog.debug.Logger.Level} the logging message level.
*/
goog.debug.LogRecord.prototype.getLevel = function() {
return this.level_;
};
/**
* Set the logging message level, for example Level.SEVERE.
* @param {goog.debug.Logger.Level} level the logging message level.
*/
goog.debug.LogRecord.prototype.setLevel = function(level) {
this.level_ = level;
};
/**
* Get the "raw" log message, before localization or formatting.
*
* @return {string} the raw message string.
*/
goog.debug.LogRecord.prototype.getMessage = function() {
return this.msg_;
};
/**
* Set the "raw" log message, before localization or formatting.
*
* @param {string} msg the raw message string.
*/
goog.debug.LogRecord.prototype.setMessage = function(msg) {
this.msg_ = msg;
};
/**
* Get event time in milliseconds since 1970.
*
* @return {number} event time in millis since 1970.
*/
goog.debug.LogRecord.prototype.getMillis = function() {
return this.time_;
};
/**
* Set event time in milliseconds since 1970.
*
* @param {number} time event time in millis since 1970.
*/
goog.debug.LogRecord.prototype.setMillis = function(time) {
this.time_ = time;
};
/**
* Get the sequence number.
* <p>
* Sequence numbers are normally assigned in the LogRecord
* constructor, which assigns unique sequence numbers to
* each new LogRecord in increasing order.
* @return {number} the sequence number.
*/
goog.debug.LogRecord.prototype.getSequenceNumber = function() {
return this.sequenceNumber_;
};