##// END OF EJS Templates
js: added log.warning support
marcink -
r4335:049df98d default
parent child Browse files
Show More
@@ -1,272 +1,277 b''
1 /**
1 /**
2 * LOGGING CONFIG
2 * LOGGING CONFIG
3 *
3 *
4 *
4 *
5 Usage:
5 Usage:
6 Logger.debug("I'm a debug message!");
6 Logger.debug("I'm a debug message!");
7 Logger.info("OMG! Check this window out!", window);
7 Logger.info("OMG! Check this window out!", window);
8 Logger.warn("Purple Alert! Purple Alert!");
8 Logger.warn("Purple Alert! Purple Alert!");
9 Logger.error("HOLY SHI... no carrier.");
9 Logger.error("HOLY SHI... no carrier.");
10
10
11 // Only log WARN and ERROR messages.
11 // Only log WARN and ERROR messages.
12 Logger.setLevel(Logger.WARN);
12 Logger.setLevel(Logger.WARN);
13 Logger.debug("Donut machine is out of pink ones"); // Not a peep.
13 Logger.debug("Donut machine is out of pink ones"); // Not a peep.
14 Logger.warn("Asteroid detected!"); // yes show
14 Logger.warn("Asteroid detected!"); // yes show
15 // Retrieve a named logger and store it for use.
15 // Retrieve a named logger and store it for use.
16 var myLogger = Logger.get('ModuleA');
16 var myLogger = Logger.get('ModuleA');
17 myLogger.info("FizzWozz starting up");
17 myLogger.info("FizzWozz starting up");
18
18
19 // This logger instance can be configured independent of
19 // This logger instance can be configured independent of
20 // all others (including the global one).
20 // all others (including the global one).
21 myLogger.setLevel(Logger.WARN);
21 myLogger.setLevel(Logger.WARN);
22
22
23 // As it's the same instance being returned each time, you
23 // As it's the same instance being returned each time, you
24 // don't have to store a reference:
24 // don't have to store a reference:
25 Logger.get('ModuleA').warn('FizzWozz combombulated!");
25 Logger.get('ModuleA').warn('FizzWozz combombulated!");
26
26
27 */
27 */
28 /*!
28 /*!
29 * js-logger - http://github.com/jonnyreeves/js-logger
29 * js-logger - http://github.com/jonnyreeves/js-logger
30 * Jonny Reeves, http://jonnyreeves.co.uk/
30 * Jonny Reeves, http://jonnyreeves.co.uk/
31 * js-logger may be freely distributed under the MIT license.
31 * js-logger may be freely distributed under the MIT license.
32 */
32 */
33 (function (global) {
33 (function (global) {
34 "use strict";
34 "use strict";
35
35
36 // Top level module for the global, static logger instance.
36 // Top level module for the global, static logger instance.
37 var Logger = { };
37 var Logger = { };
38
38
39 // For those that are at home that are keeping score.
39 // For those that are at home that are keeping score.
40 Logger.VERSION = "1.0.0";
40 Logger.VERSION = "1.0.0";
41
41
42 // Function which handles all incoming log messages.
42 // Function which handles all incoming log messages.
43 var logHandler;
43 var logHandler;
44
44
45 // Map of ContextualLogger instances by name; used by Logger.get() to return the same named instance.
45 // Map of ContextualLogger instances by name; used by Logger.get() to return the same named instance.
46 var contextualLoggersByNameMap = {};
46 var contextualLoggersByNameMap = {};
47
47
48 // Polyfill for ES5's Function.bind.
48 // Polyfill for ES5's Function.bind.
49 var bind = function(scope, func) {
49 var bind = function(scope, func) {
50 return function() {
50 return function() {
51 return func.apply(scope, arguments);
51 return func.apply(scope, arguments);
52 };
52 };
53 };
53 };
54
54
55 // Super exciting object merger-matron 9000 adding another 100 bytes to your download.
55 // Super exciting object merger-matron 9000 adding another 100 bytes to your download.
56 var merge = function () {
56 var merge = function () {
57 var args = arguments, target = args[0], key, i;
57 var args = arguments, target = args[0], key, i;
58 for (i = 1; i < args.length; i++) {
58 for (i = 1; i < args.length; i++) {
59 for (key in args[i]) {
59 for (key in args[i]) {
60 if (!(key in target) && args[i].hasOwnProperty(key)) {
60 if (!(key in target) && args[i].hasOwnProperty(key)) {
61 target[key] = args[i][key];
61 target[key] = args[i][key];
62 }
62 }
63 }
63 }
64 }
64 }
65 return target;
65 return target;
66 };
66 };
67
67
68 // Helper to define a logging level object; helps with optimisation.
68 // Helper to define a logging level object; helps with optimisation.
69 var defineLogLevel = function(value, name) {
69 var defineLogLevel = function(value, name) {
70 return { value: value, name: name };
70 return { value: value, name: name };
71 };
71 };
72
72
73 // Predefined logging levels.
73 // Predefined logging levels.
74 Logger.DEBUG = defineLogLevel(1, 'DEBUG');
74 Logger.DEBUG = defineLogLevel(1, 'DEBUG');
75 Logger.INFO = defineLogLevel(2, 'INFO');
75 Logger.INFO = defineLogLevel(2, 'INFO');
76 Logger.TIME = defineLogLevel(3, 'TIME');
76 Logger.TIME = defineLogLevel(3, 'TIME');
77 Logger.WARN = defineLogLevel(4, 'WARN');
77 Logger.WARN = defineLogLevel(4, 'WARN');
78 Logger.ERROR = defineLogLevel(8, 'ERROR');
78 Logger.ERROR = defineLogLevel(8, 'ERROR');
79 Logger.OFF = defineLogLevel(99, 'OFF');
79 Logger.OFF = defineLogLevel(99, 'OFF');
80
80
81 // Inner class which performs the bulk of the work; ContextualLogger instances can be configured independently
81 // Inner class which performs the bulk of the work; ContextualLogger instances can be configured independently
82 // of each other.
82 // of each other.
83 var ContextualLogger = function(defaultContext) {
83 var ContextualLogger = function(defaultContext) {
84 this.context = defaultContext;
84 this.context = defaultContext;
85 this.setLevel(defaultContext.filterLevel);
85 this.setLevel(defaultContext.filterLevel);
86 this.log = this.info; // Convenience alias.
86 this.log = this.info; // Convenience alias.
87 };
87 };
88
88
89 ContextualLogger.prototype = {
89 ContextualLogger.prototype = {
90 // Changes the current logging level for the logging instance.
90 // Changes the current logging level for the logging instance.
91 setLevel: function (newLevel) {
91 setLevel: function (newLevel) {
92 // Ensure the supplied Level object looks valid.
92 // Ensure the supplied Level object looks valid.
93 if (newLevel && "value" in newLevel) {
93 if (newLevel && "value" in newLevel) {
94 this.context.filterLevel = newLevel;
94 this.context.filterLevel = newLevel;
95 }
95 }
96 },
96 },
97
97
98 // Is the logger configured to output messages at the supplied level?
98 // Is the logger configured to output messages at the supplied level?
99 enabledFor: function (lvl) {
99 enabledFor: function (lvl) {
100 var filterLevel = this.context.filterLevel;
100 var filterLevel = this.context.filterLevel;
101 return lvl.value >= filterLevel.value;
101 return lvl.value >= filterLevel.value;
102 },
102 },
103
103
104 debug: function () {
104 debug: function () {
105 this.invoke(Logger.DEBUG, arguments);
105 this.invoke(Logger.DEBUG, arguments);
106 },
106 },
107
107
108 info: function () {
108 info: function () {
109 this.invoke(Logger.INFO, arguments);
109 this.invoke(Logger.INFO, arguments);
110 },
110 },
111
111
112 warn: function () {
112 warn: function () {
113 this.invoke(Logger.WARN, arguments);
113 this.invoke(Logger.WARN, arguments);
114 },
114 },
115
115
116 warning: function () {
117 this.invoke(Logger.WARN, arguments);
118 },
119
116 error: function () {
120 error: function () {
117 this.invoke(Logger.ERROR, arguments);
121 this.invoke(Logger.ERROR, arguments);
118 },
122 },
119
123
120 time: function (label) {
124 time: function (label) {
121 if (typeof label === 'string' && label.length > 0) {
125 if (typeof label === 'string' && label.length > 0) {
122 this.invoke(Logger.TIME, [ label, 'start' ]);
126 this.invoke(Logger.TIME, [ label, 'start' ]);
123 }
127 }
124 },
128 },
125
129
126 timeEnd: function (label) {
130 timeEnd: function (label) {
127 if (typeof label === 'string' && label.length > 0) {
131 if (typeof label === 'string' && label.length > 0) {
128 this.invoke(Logger.TIME, [ label, 'end' ]);
132 this.invoke(Logger.TIME, [ label, 'end' ]);
129 }
133 }
130 },
134 },
131
135
132 // Invokes the logger callback if it's not being filtered.
136 // Invokes the logger callback if it's not being filtered.
133 invoke: function (level, msgArgs) {
137 invoke: function (level, msgArgs) {
134 if (logHandler && this.enabledFor(level)) {
138 if (logHandler && this.enabledFor(level)) {
135 logHandler(msgArgs, merge({ level: level }, this.context));
139 logHandler(msgArgs, merge({ level: level }, this.context));
136 }
140 }
137 }
141 }
138 };
142 };
139
143
140 // Protected instance which all calls to the to level `Logger` module will be routed through.
144 // Protected instance which all calls to the to level `Logger` module will be routed through.
141 var globalLogger = new ContextualLogger({ filterLevel: Logger.OFF });
145 var globalLogger = new ContextualLogger({ filterLevel: Logger.OFF });
142
146
143 // Configure the global Logger instance.
147 // Configure the global Logger instance.
144 (function() {
148 (function() {
145 // Shortcut for optimisers.
149 // Shortcut for optimisers.
146 var L = Logger;
150 var L = Logger;
147
151
148 L.enabledFor = bind(globalLogger, globalLogger.enabledFor);
152 L.enabledFor = bind(globalLogger, globalLogger.enabledFor);
149 L.debug = bind(globalLogger, globalLogger.debug);
153 L.debug = bind(globalLogger, globalLogger.debug);
150 L.time = bind(globalLogger, globalLogger.time);
154 L.time = bind(globalLogger, globalLogger.time);
151 L.timeEnd = bind(globalLogger, globalLogger.timeEnd);
155 L.timeEnd = bind(globalLogger, globalLogger.timeEnd);
152 L.info = bind(globalLogger, globalLogger.info);
156 L.info = bind(globalLogger, globalLogger.info);
153 L.warn = bind(globalLogger, globalLogger.warn);
157 L.warn = bind(globalLogger, globalLogger.warn);
158 L.warning = bind(globalLogger, globalLogger.warning);
154 L.error = bind(globalLogger, globalLogger.error);
159 L.error = bind(globalLogger, globalLogger.error);
155
160
156 // Don't forget the convenience alias!
161 // Don't forget the convenience alias!
157 L.log = L.info;
162 L.log = L.info;
158 }());
163 }());
159
164
160 // Set the global logging handler. The supplied function should expect two arguments, the first being an arguments
165 // Set the global logging handler. The supplied function should expect two arguments, the first being an arguments
161 // object with the supplied log messages and the second being a context object which contains a hash of stateful
166 // object with the supplied log messages and the second being a context object which contains a hash of stateful
162 // parameters which the logging function can consume.
167 // parameters which the logging function can consume.
163 Logger.setHandler = function (func) {
168 Logger.setHandler = function (func) {
164 logHandler = func;
169 logHandler = func;
165 };
170 };
166
171
167 // Sets the global logging filter level which applies to *all* previously registered, and future Logger instances.
172 // Sets the global logging filter level which applies to *all* previously registered, and future Logger instances.
168 // (note that named loggers (retrieved via `Logger.get`) can be configured independently if required).
173 // (note that named loggers (retrieved via `Logger.get`) can be configured independently if required).
169 Logger.setLevel = function(level) {
174 Logger.setLevel = function(level) {
170 // Set the globalLogger's level.
175 // Set the globalLogger's level.
171 globalLogger.setLevel(level);
176 globalLogger.setLevel(level);
172
177
173 // Apply this level to all registered contextual loggers.
178 // Apply this level to all registered contextual loggers.
174 for (var key in contextualLoggersByNameMap) {
179 for (var key in contextualLoggersByNameMap) {
175 if (contextualLoggersByNameMap.hasOwnProperty(key)) {
180 if (contextualLoggersByNameMap.hasOwnProperty(key)) {
176 contextualLoggersByNameMap[key].setLevel(level);
181 contextualLoggersByNameMap[key].setLevel(level);
177 }
182 }
178 }
183 }
179 };
184 };
180
185
181 // Retrieve a ContextualLogger instance. Note that named loggers automatically inherit the global logger's level,
186 // Retrieve a ContextualLogger instance. Note that named loggers automatically inherit the global logger's level,
182 // default context and log handler.
187 // default context and log handler.
183 Logger.get = function (name) {
188 Logger.get = function (name) {
184 // All logger instances are cached so they can be configured ahead of use.
189 // All logger instances are cached so they can be configured ahead of use.
185 return contextualLoggersByNameMap[name] ||
190 return contextualLoggersByNameMap[name] ||
186 (contextualLoggersByNameMap[name] = new ContextualLogger(merge({ name: name }, globalLogger.context)));
191 (contextualLoggersByNameMap[name] = new ContextualLogger(merge({ name: name }, globalLogger.context)));
187 };
192 };
188
193
189 // Configure and example a Default implementation which writes to the `window.console` (if present).
194 // Configure and example a Default implementation which writes to the `window.console` (if present).
190 Logger.useDefaults = function(defaultLevel) {
195 Logger.useDefaults = function(defaultLevel) {
191 // Check for the presence of a logger.
196 // Check for the presence of a logger.
192 if (typeof console === "undefined") {
197 if (typeof console === "undefined") {
193 return;
198 return;
194 }
199 }
195
200
196 // Map of timestamps by timer labels used to track `#time` and `#timeEnd()` invocations in environments
201 // Map of timestamps by timer labels used to track `#time` and `#timeEnd()` invocations in environments
197 // that don't offer a native console method.
202 // that don't offer a native console method.
198 var timerStartTimeByLabelMap = {};
203 var timerStartTimeByLabelMap = {};
199
204
200 // Support for IE8+ (and other, slightly more sane environments)
205 // Support for IE8+ (and other, slightly more sane environments)
201 var invokeConsoleMethod = function (hdlr, messages) {
206 var invokeConsoleMethod = function (hdlr, messages) {
202 Function.prototype.apply.call(hdlr, console, messages);
207 Function.prototype.apply.call(hdlr, console, messages);
203 };
208 };
204
209
205 Logger.setLevel(defaultLevel || Logger.DEBUG);
210 Logger.setLevel(defaultLevel || Logger.DEBUG);
206 Logger.setHandler(function(messages, context) {
211 Logger.setHandler(function(messages, context) {
207 var hdlr = console.log;
212 var hdlr = console.log;
208
213
209 // append INFO/DEBUG etc into the messages
214 // append INFO/DEBUG etc into the messages
210 var levelPrefix = ((context.level.name+" ").toUpperCase()).substr(0,6);
215 var levelPrefix = ((context.level.name+" ").toUpperCase()).substr(0,6);
211 messages[0] = levelPrefix + messages[0];
216 messages[0] = levelPrefix + messages[0];
212
217
213 // Prepend the logger's name to the log message for easy identification.
218 // Prepend the logger's name to the log message for easy identification.
214 if (context.name) {
219 if (context.name) {
215 messages[0] = "[" + context.name + "] " + messages[0];
220 messages[0] = "[" + context.name + "] " + messages[0];
216 }
221 }
217
222
218
223
219 if (context.level === Logger.TIME) {
224 if (context.level === Logger.TIME) {
220 if (messages[1] === 'start') {
225 if (messages[1] === 'start') {
221 if (console.time) {
226 if (console.time) {
222 console.time(messages[0]);
227 console.time(messages[0]);
223 }
228 }
224 else {
229 else {
225 timerStartTimeByLabelMap[messages[0]] = new Date().getTime();
230 timerStartTimeByLabelMap[messages[0]] = new Date().getTime();
226 }
231 }
227 }
232 }
228 else {
233 else {
229 if (console.timeEnd) {
234 if (console.timeEnd) {
230 console.timeEnd(messages[0]);
235 console.timeEnd(messages[0]);
231 }
236 }
232 else {
237 else {
233 invokeConsoleMethod(hdlr, [ messages[0] + ': ' +
238 invokeConsoleMethod(hdlr, [ messages[0] + ': ' +
234 (new Date().getTime() - timerStartTimeByLabelMap[messages[0]]) + 'ms' ]);
239 (new Date().getTime() - timerStartTimeByLabelMap[messages[0]]) + 'ms' ]);
235 }
240 }
236 }
241 }
237 }
242 }
238 else {
243 else {
239 // Delegate through to custom warn/error loggers if present on the console.
244 // Delegate through to custom warn/error loggers if present on the console.
240 if (context.level === Logger.WARN && console.warn) {
245 if (context.level === Logger.WARN && console.warn) {
241 hdlr = console.warn;
246 hdlr = console.warn;
242 } else if (context.level === Logger.ERROR && console.error) {
247 } else if (context.level === Logger.ERROR && console.error) {
243 hdlr = console.error;
248 hdlr = console.error;
244 } else if (context.level === Logger.INFO && console.info) {
249 } else if (context.level === Logger.INFO && console.info) {
245 hdlr = console.info;
250 hdlr = console.info;
246 }
251 }
247
252
248 invokeConsoleMethod(hdlr, messages);
253 invokeConsoleMethod(hdlr, messages);
249 }
254 }
250 });
255 });
251 };
256 };
252
257
253 // Export to popular environments boilerplate.
258 // Export to popular environments boilerplate.
254 if (typeof define === 'function' && define.amd) {
259 if (typeof define === 'function' && define.amd) {
255 define(Logger);
260 define(Logger);
256 }
261 }
257 else if (typeof module !== 'undefined' && module.exports) {
262 else if (typeof module !== 'undefined' && module.exports) {
258 module.exports = Logger;
263 module.exports = Logger;
259 }
264 }
260 else {
265 else {
261 Logger._prevLogger = global.Logger;
266 Logger._prevLogger = global.Logger;
262
267
263 Logger.noConflict = function () {
268 Logger.noConflict = function () {
264 global.Logger = Logger._prevLogger;
269 global.Logger = Logger._prevLogger;
265 return Logger;
270 return Logger;
266 };
271 };
267
272
268 global.Logger = Logger;
273 global.Logger = Logger;
269 }
274 }
270 }(this));
275 }(this));
271 // init defaults
276 // init defaults
272 Logger.useDefaults();
277 Logger.useDefaults();
General Comments 0
You need to be logged in to leave comments. Login now