Daniel@0
|
1 /*!
|
Daniel@0
|
2 * js-logger - http://github.com/jonnyreeves/js-logger
|
Daniel@0
|
3 * Jonny Reeves, http://jonnyreeves.co.uk/
|
Daniel@0
|
4 * js-logger may be freely distributed under the MIT license.
|
Daniel@0
|
5 */
|
Daniel@0
|
6
|
Daniel@0
|
7 /*jshint sub:true*/
|
Daniel@0
|
8 /*global console:true,define:true, module:true*/
|
Daniel@0
|
9 (function (global) {
|
Daniel@0
|
10 "use strict";
|
Daniel@0
|
11
|
Daniel@0
|
12 // Top level module for the global, static logger instance.
|
Daniel@0
|
13 var Logger = { };
|
Daniel@0
|
14
|
Daniel@0
|
15 // For those that are at home that are keeping score.
|
Daniel@0
|
16 Logger.VERSION = "0.9.14";
|
Daniel@0
|
17
|
Daniel@0
|
18 // Function which handles all incoming log messages.
|
Daniel@0
|
19 var logHandler;
|
Daniel@0
|
20
|
Daniel@0
|
21 // Map of ContextualLogger instances by name; used by Logger.get() to return the same named instance.
|
Daniel@0
|
22 var contextualLoggersByNameMap = {};
|
Daniel@0
|
23
|
Daniel@0
|
24 // Polyfill for ES5's Function.bind.
|
Daniel@0
|
25 var bind = function(scope, func) {
|
Daniel@0
|
26 return function() {
|
Daniel@0
|
27 return func.apply(scope, arguments);
|
Daniel@0
|
28 };
|
Daniel@0
|
29 };
|
Daniel@0
|
30
|
Daniel@0
|
31 // Super exciting object merger-matron 9000 adding another 100 bytes to your download.
|
Daniel@0
|
32 var merge = function () {
|
Daniel@0
|
33 var args = arguments, target = args[0], key, i;
|
Daniel@0
|
34 for (i = 1; i < args.length; i++) {
|
Daniel@0
|
35 for (key in args[i]) {
|
Daniel@0
|
36 if (!(key in target) && args[i].hasOwnProperty(key)) {
|
Daniel@0
|
37 target[key] = args[i][key];
|
Daniel@0
|
38 }
|
Daniel@0
|
39 }
|
Daniel@0
|
40 }
|
Daniel@0
|
41 return target;
|
Daniel@0
|
42 };
|
Daniel@0
|
43
|
Daniel@0
|
44 // Helper to define a logging level object; helps with optimisation.
|
Daniel@0
|
45 var defineLogLevel = function(value, name) {
|
Daniel@0
|
46 return { value: value, name: name };
|
Daniel@0
|
47 };
|
Daniel@0
|
48
|
Daniel@0
|
49 // Predefined logging levels.
|
Daniel@0
|
50 Logger.DEBUG = defineLogLevel(1, 'DEBUG');
|
Daniel@0
|
51 Logger.INFO = defineLogLevel(2, 'INFO');
|
Daniel@0
|
52 Logger.WARN = defineLogLevel(4, 'WARN');
|
Daniel@0
|
53 Logger.ERROR = defineLogLevel(8, 'ERROR');
|
Daniel@0
|
54 Logger.OFF = defineLogLevel(99, 'OFF');
|
Daniel@0
|
55
|
Daniel@0
|
56 // Inner class which performs the bulk of the work; ContextualLogger instances can be configured independently
|
Daniel@0
|
57 // of each other.
|
Daniel@0
|
58 var ContextualLogger = function(defaultContext) {
|
Daniel@0
|
59 this.context = defaultContext;
|
Daniel@0
|
60 this.setLevel(defaultContext.filterLevel);
|
Daniel@0
|
61 this.log = this.info; // Convenience alias.
|
Daniel@0
|
62 };
|
Daniel@0
|
63
|
Daniel@0
|
64 ContextualLogger.prototype = {
|
Daniel@0
|
65 // Changes the current logging level for the logging instance.
|
Daniel@0
|
66 setLevel: function (newLevel) {
|
Daniel@0
|
67 // Ensure the supplied Level object looks valid.
|
Daniel@0
|
68 if (newLevel && "value" in newLevel) {
|
Daniel@0
|
69 this.context.filterLevel = newLevel;
|
Daniel@0
|
70 }
|
Daniel@0
|
71 },
|
Daniel@0
|
72
|
Daniel@0
|
73 // Is the logger configured to output messages at the supplied level?
|
Daniel@0
|
74 enabledFor: function (lvl) {
|
Daniel@0
|
75 var filterLevel = this.context.filterLevel;
|
Daniel@0
|
76 return lvl.value >= filterLevel.value;
|
Daniel@0
|
77 },
|
Daniel@0
|
78
|
Daniel@0
|
79 debug: function () {
|
Daniel@0
|
80 this.invoke(Logger.DEBUG, arguments);
|
Daniel@0
|
81 },
|
Daniel@0
|
82
|
Daniel@0
|
83 info: function () {
|
Daniel@0
|
84 this.invoke(Logger.INFO, arguments);
|
Daniel@0
|
85 },
|
Daniel@0
|
86
|
Daniel@0
|
87 warn: function () {
|
Daniel@0
|
88 this.invoke(Logger.WARN, arguments);
|
Daniel@0
|
89 },
|
Daniel@0
|
90
|
Daniel@0
|
91 error: function () {
|
Daniel@0
|
92 this.invoke(Logger.ERROR, arguments);
|
Daniel@0
|
93 },
|
Daniel@0
|
94
|
Daniel@0
|
95 // Invokes the logger callback if it's not being filtered.
|
Daniel@0
|
96 invoke: function (level, msgArgs) {
|
Daniel@0
|
97 if (logHandler && this.enabledFor(level)) {
|
Daniel@0
|
98 logHandler(msgArgs, merge({ level: level }, this.context));
|
Daniel@0
|
99 }
|
Daniel@0
|
100 }
|
Daniel@0
|
101 };
|
Daniel@0
|
102
|
Daniel@0
|
103 // Protected instance which all calls to the to level `Logger` module will be routed through.
|
Daniel@0
|
104 var globalLogger = new ContextualLogger({ filterLevel: Logger.OFF });
|
Daniel@0
|
105
|
Daniel@0
|
106 // Configure the global Logger instance.
|
Daniel@0
|
107 (function() {
|
Daniel@0
|
108 // Shortcut for optimisers.
|
Daniel@0
|
109 var L = Logger;
|
Daniel@0
|
110
|
Daniel@0
|
111 L.enabledFor = bind(globalLogger, globalLogger.enabledFor);
|
Daniel@0
|
112 L.debug = bind(globalLogger, globalLogger.debug);
|
Daniel@0
|
113 L.info = bind(globalLogger, globalLogger.info);
|
Daniel@0
|
114 L.warn = bind(globalLogger, globalLogger.warn);
|
Daniel@0
|
115 L.error = bind(globalLogger, globalLogger.error);
|
Daniel@0
|
116
|
Daniel@0
|
117 // Don't forget the convenience alias!
|
Daniel@0
|
118 L.log = L.info;
|
Daniel@0
|
119 }());
|
Daniel@0
|
120
|
Daniel@0
|
121 // Set the global logging handler. The supplied function should expect two arguments, the first being an arguments
|
Daniel@0
|
122 // object with the supplied log messages and the second being a context object which contains a hash of stateful
|
Daniel@0
|
123 // parameters which the logging function can consume.
|
Daniel@0
|
124 Logger.setHandler = function (func) {
|
Daniel@0
|
125 logHandler = func;
|
Daniel@0
|
126 };
|
Daniel@0
|
127
|
Daniel@0
|
128 // Sets the global logging filter level which applies to *all* previously registered, and future Logger instances.
|
Daniel@0
|
129 // (note that named loggers (retrieved via `Logger.get`) can be configured independently if required).
|
Daniel@0
|
130 Logger.setLevel = function(level) {
|
Daniel@0
|
131 // Set the globalLogger's level.
|
Daniel@0
|
132 globalLogger.setLevel(level);
|
Daniel@0
|
133
|
Daniel@0
|
134 // Apply this level to all registered contextual loggers.
|
Daniel@0
|
135 for (var key in contextualLoggersByNameMap) {
|
Daniel@0
|
136 if (contextualLoggersByNameMap.hasOwnProperty(key)) {
|
Daniel@0
|
137 contextualLoggersByNameMap[key].setLevel(level);
|
Daniel@0
|
138 }
|
Daniel@0
|
139 }
|
Daniel@0
|
140 };
|
Daniel@0
|
141
|
Daniel@0
|
142 // Retrieve a ContextualLogger instance. Note that named loggers automatically inherit the global logger's level,
|
Daniel@0
|
143 // default context and log handler.
|
Daniel@0
|
144 Logger.get = function (name) {
|
Daniel@0
|
145 // All logger instances are cached so they can be configured ahead of use.
|
Daniel@0
|
146 return contextualLoggersByNameMap[name] ||
|
Daniel@0
|
147 (contextualLoggersByNameMap[name] = new ContextualLogger(merge({ name: name }, globalLogger.context)));
|
Daniel@0
|
148 };
|
Daniel@0
|
149
|
Daniel@0
|
150 // Configure and example a Default implementation which writes to the `window.console` (if present).
|
Daniel@0
|
151 Logger.useDefaults = function(defaultLevel) {
|
Daniel@0
|
152 // Check for the presence of a logger.
|
Daniel@0
|
153 if (typeof console === "undefined") {
|
Daniel@0
|
154 return;
|
Daniel@0
|
155 }
|
Daniel@0
|
156
|
Daniel@0
|
157 Logger.setLevel(defaultLevel || Logger.DEBUG);
|
Daniel@0
|
158 Logger.setHandler(function(messages, context) {
|
Daniel@0
|
159 var hdlr = console.log;
|
Daniel@0
|
160
|
Daniel@0
|
161 // Prepend the logger's name to the log message for easy identification.
|
Daniel@0
|
162 if (context.name) {
|
Daniel@0
|
163 messages[0] = "[" + context.name + "] " + messages[0];
|
Daniel@0
|
164 }
|
Daniel@0
|
165
|
Daniel@0
|
166 // Delegate through to custom warn/error loggers if present on the console.
|
Daniel@0
|
167 if (context.level === Logger.WARN && console.warn) {
|
Daniel@0
|
168 hdlr = console.warn;
|
Daniel@0
|
169 } else if (context.level === Logger.ERROR && console.error) {
|
Daniel@0
|
170 hdlr = console.error;
|
Daniel@0
|
171 } else if (context.level === Logger.INFO && console.info) {
|
Daniel@0
|
172 hdlr = console.info;
|
Daniel@0
|
173 }
|
Daniel@0
|
174
|
Daniel@0
|
175 // Support for IE8+ (and other, slightly more sane environments)
|
Daniel@0
|
176 Function.prototype.apply.call(hdlr, console, messages);
|
Daniel@0
|
177 });
|
Daniel@0
|
178 };
|
Daniel@0
|
179
|
Daniel@0
|
180 // Export to popular environments boilerplate.
|
Daniel@0
|
181 if (typeof define === 'function' && define.amd) {
|
Daniel@0
|
182 define(Logger);
|
Daniel@0
|
183 }
|
Daniel@0
|
184 else if (typeof module !== 'undefined' && module.exports) {
|
Daniel@0
|
185 module.exports = Logger;
|
Daniel@0
|
186 }
|
Daniel@0
|
187 else {
|
Daniel@0
|
188 Logger._prevLogger = global.Logger;
|
Daniel@0
|
189
|
Daniel@0
|
190 Logger.noConflict = function () {
|
Daniel@0
|
191 global.Logger = Logger._prevLogger;
|
Daniel@0
|
192 return Logger;
|
Daniel@0
|
193 };
|
Daniel@0
|
194
|
Daniel@0
|
195 global.Logger = Logger;
|
Daniel@0
|
196 }
|
Daniel@0
|
197 }(this)); |