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