logging.js
272 lines
| 8.3 KiB
| application/javascript
|
JavascriptLexer
r1 | /** | |||
* LOGGING CONFIG | ||||
* | ||||
* | ||||
Usage: | ||||
Logger.debug("I'm a debug message!"); | ||||
Logger.info("OMG! Check this window out!", window); | ||||
Logger.warn("Purple Alert! Purple Alert!"); | ||||
Logger.error("HOLY SHI... no carrier."); | ||||
// Only log WARN and ERROR messages. | ||||
Logger.setLevel(Logger.WARN); | ||||
Logger.debug("Donut machine is out of pink ones"); // Not a peep. | ||||
Logger.warn("Asteroid detected!"); // yes show | ||||
// Retrieve a named logger and store it for use. | ||||
var myLogger = Logger.get('ModuleA'); | ||||
myLogger.info("FizzWozz starting up"); | ||||
// This logger instance can be configured independent of | ||||
// all others (including the global one). | ||||
myLogger.setLevel(Logger.WARN); | ||||
// As it's the same instance being returned each time, you | ||||
// don't have to store a reference: | ||||
Logger.get('ModuleA').warn('FizzWozz combombulated!"); | ||||
*/ | ||||
/*! | ||||
* js-logger - http://github.com/jonnyreeves/js-logger | ||||
* Jonny Reeves, http://jonnyreeves.co.uk/ | ||||
* js-logger may be freely distributed under the MIT license. | ||||
*/ | ||||
(function (global) { | ||||
"use strict"; | ||||
// Top level module for the global, static logger instance. | ||||
var Logger = { }; | ||||
// For those that are at home that are keeping score. | ||||
Logger.VERSION = "1.0.0"; | ||||
// Function which handles all incoming log messages. | ||||
var logHandler; | ||||
// Map of ContextualLogger instances by name; used by Logger.get() to return the same named instance. | ||||
var contextualLoggersByNameMap = {}; | ||||
// Polyfill for ES5's Function.bind. | ||||
var bind = function(scope, func) { | ||||
return function() { | ||||
return func.apply(scope, arguments); | ||||
}; | ||||
}; | ||||
// Super exciting object merger-matron 9000 adding another 100 bytes to your download. | ||||
var merge = function () { | ||||
var args = arguments, target = args[0], key, i; | ||||
for (i = 1; i < args.length; i++) { | ||||
for (key in args[i]) { | ||||
if (!(key in target) && args[i].hasOwnProperty(key)) { | ||||
target[key] = args[i][key]; | ||||
} | ||||
} | ||||
} | ||||
return target; | ||||
}; | ||||
// Helper to define a logging level object; helps with optimisation. | ||||
var defineLogLevel = function(value, name) { | ||||
return { value: value, name: name }; | ||||
}; | ||||
// Predefined logging levels. | ||||
Logger.DEBUG = defineLogLevel(1, 'DEBUG'); | ||||
Logger.INFO = defineLogLevel(2, 'INFO'); | ||||
Logger.TIME = defineLogLevel(3, 'TIME'); | ||||
Logger.WARN = defineLogLevel(4, 'WARN'); | ||||
Logger.ERROR = defineLogLevel(8, 'ERROR'); | ||||
Logger.OFF = defineLogLevel(99, 'OFF'); | ||||
// Inner class which performs the bulk of the work; ContextualLogger instances can be configured independently | ||||
// of each other. | ||||
var ContextualLogger = function(defaultContext) { | ||||
this.context = defaultContext; | ||||
this.setLevel(defaultContext.filterLevel); | ||||
this.log = this.info; // Convenience alias. | ||||
}; | ||||
ContextualLogger.prototype = { | ||||
// Changes the current logging level for the logging instance. | ||||
setLevel: function (newLevel) { | ||||
// Ensure the supplied Level object looks valid. | ||||
if (newLevel && "value" in newLevel) { | ||||
this.context.filterLevel = newLevel; | ||||
} | ||||
}, | ||||
// Is the logger configured to output messages at the supplied level? | ||||
enabledFor: function (lvl) { | ||||
var filterLevel = this.context.filterLevel; | ||||
return lvl.value >= filterLevel.value; | ||||
}, | ||||
debug: function () { | ||||
this.invoke(Logger.DEBUG, arguments); | ||||
}, | ||||
info: function () { | ||||
this.invoke(Logger.INFO, arguments); | ||||
}, | ||||
warn: function () { | ||||
this.invoke(Logger.WARN, arguments); | ||||
}, | ||||
error: function () { | ||||
this.invoke(Logger.ERROR, arguments); | ||||
}, | ||||
time: function (label) { | ||||
if (typeof label === 'string' && label.length > 0) { | ||||
this.invoke(Logger.TIME, [ label, 'start' ]); | ||||
} | ||||
}, | ||||
timeEnd: function (label) { | ||||
if (typeof label === 'string' && label.length > 0) { | ||||
this.invoke(Logger.TIME, [ label, 'end' ]); | ||||
} | ||||
}, | ||||
// Invokes the logger callback if it's not being filtered. | ||||
invoke: function (level, msgArgs) { | ||||
if (logHandler && this.enabledFor(level)) { | ||||
logHandler(msgArgs, merge({ level: level }, this.context)); | ||||
} | ||||
} | ||||
}; | ||||
// Protected instance which all calls to the to level `Logger` module will be routed through. | ||||
var globalLogger = new ContextualLogger({ filterLevel: Logger.OFF }); | ||||
// Configure the global Logger instance. | ||||
(function() { | ||||
// Shortcut for optimisers. | ||||
var L = Logger; | ||||
L.enabledFor = bind(globalLogger, globalLogger.enabledFor); | ||||
L.debug = bind(globalLogger, globalLogger.debug); | ||||
L.time = bind(globalLogger, globalLogger.time); | ||||
L.timeEnd = bind(globalLogger, globalLogger.timeEnd); | ||||
L.info = bind(globalLogger, globalLogger.info); | ||||
L.warn = bind(globalLogger, globalLogger.warn); | ||||
L.error = bind(globalLogger, globalLogger.error); | ||||
// Don't forget the convenience alias! | ||||
L.log = L.info; | ||||
}()); | ||||
// Set the global logging handler. The supplied function should expect two arguments, the first being an arguments | ||||
// object with the supplied log messages and the second being a context object which contains a hash of stateful | ||||
// parameters which the logging function can consume. | ||||
Logger.setHandler = function (func) { | ||||
logHandler = func; | ||||
}; | ||||
// Sets the global logging filter level which applies to *all* previously registered, and future Logger instances. | ||||
// (note that named loggers (retrieved via `Logger.get`) can be configured independently if required). | ||||
Logger.setLevel = function(level) { | ||||
// Set the globalLogger's level. | ||||
globalLogger.setLevel(level); | ||||
// Apply this level to all registered contextual loggers. | ||||
for (var key in contextualLoggersByNameMap) { | ||||
if (contextualLoggersByNameMap.hasOwnProperty(key)) { | ||||
contextualLoggersByNameMap[key].setLevel(level); | ||||
} | ||||
} | ||||
}; | ||||
// Retrieve a ContextualLogger instance. Note that named loggers automatically inherit the global logger's level, | ||||
// default context and log handler. | ||||
Logger.get = function (name) { | ||||
// All logger instances are cached so they can be configured ahead of use. | ||||
return contextualLoggersByNameMap[name] || | ||||
(contextualLoggersByNameMap[name] = new ContextualLogger(merge({ name: name }, globalLogger.context))); | ||||
}; | ||||
// Configure and example a Default implementation which writes to the `window.console` (if present). | ||||
Logger.useDefaults = function(defaultLevel) { | ||||
// Check for the presence of a logger. | ||||
if (typeof console === "undefined") { | ||||
return; | ||||
} | ||||
// Map of timestamps by timer labels used to track `#time` and `#timeEnd()` invocations in environments | ||||
// that don't offer a native console method. | ||||
var timerStartTimeByLabelMap = {}; | ||||
// Support for IE8+ (and other, slightly more sane environments) | ||||
var invokeConsoleMethod = function (hdlr, messages) { | ||||
Function.prototype.apply.call(hdlr, console, messages); | ||||
}; | ||||
Logger.setLevel(defaultLevel || Logger.DEBUG); | ||||
Logger.setHandler(function(messages, context) { | ||||
var hdlr = console.log; | ||||
// append INFO/DEBUG etc into the messages | ||||
var levelPrefix = ((context.level.name+" ").toUpperCase()).substr(0,6); | ||||
messages[0] = levelPrefix + messages[0]; | ||||
// Prepend the logger's name to the log message for easy identification. | ||||
if (context.name) { | ||||
messages[0] = "[" + context.name + "] " + messages[0]; | ||||
} | ||||
if (context.level === Logger.TIME) { | ||||
if (messages[1] === 'start') { | ||||
if (console.time) { | ||||
console.time(messages[0]); | ||||
} | ||||
else { | ||||
timerStartTimeByLabelMap[messages[0]] = new Date().getTime(); | ||||
} | ||||
} | ||||
else { | ||||
if (console.timeEnd) { | ||||
console.timeEnd(messages[0]); | ||||
} | ||||
else { | ||||
invokeConsoleMethod(hdlr, [ messages[0] + ': ' + | ||||
(new Date().getTime() - timerStartTimeByLabelMap[messages[0]]) + 'ms' ]); | ||||
} | ||||
} | ||||
} | ||||
else { | ||||
// Delegate through to custom warn/error loggers if present on the console. | ||||
if (context.level === Logger.WARN && console.warn) { | ||||
hdlr = console.warn; | ||||
} else if (context.level === Logger.ERROR && console.error) { | ||||
hdlr = console.error; | ||||
} else if (context.level === Logger.INFO && console.info) { | ||||
hdlr = console.info; | ||||
} | ||||
invokeConsoleMethod(hdlr, messages); | ||||
} | ||||
}); | ||||
}; | ||||
// Export to popular environments boilerplate. | ||||
if (typeof define === 'function' && define.amd) { | ||||
define(Logger); | ||||
} | ||||
else if (typeof module !== 'undefined' && module.exports) { | ||||
module.exports = Logger; | ||||
} | ||||
else { | ||||
Logger._prevLogger = global.Logger; | ||||
Logger.noConflict = function () { | ||||
global.Logger = Logger._prevLogger; | ||||
return Logger; | ||||
}; | ||||
global.Logger = Logger; | ||||
} | ||||
}(this)); | ||||
// init defaults | ||||
Logger.useDefaults(); | ||||