UNPKG

7.86 kBJavaScriptView Raw
1/*
2* loglevel - https://github.com/pimterry/loglevel
3*
4* Copyright (c) 2013 Tim Perry
5* Licensed under the MIT license.
6*/
7(function (root, definition) {
8 "use strict";
9 if (typeof define === 'function' && define.amd) {
10 define(definition);
11 } else if (typeof module === 'object' && module.exports) {
12 module.exports = definition();
13 } else {
14 root.log = definition();
15 }
16}(this, function () {
17 "use strict";
18
19 // Slightly dubious tricks to cut down minimized file size
20 var noop = function() {};
21 var undefinedType = "undefined";
22
23 var logMethods = [
24 "trace",
25 "debug",
26 "info",
27 "warn",
28 "error"
29 ];
30
31 // Cross-browser bind equivalent that works at least back to IE6
32 function bindMethod(obj, methodName) {
33 var method = obj[methodName];
34 if (typeof method.bind === 'function') {
35 return method.bind(obj);
36 } else {
37 try {
38 return Function.prototype.bind.call(method, obj);
39 } catch (e) {
40 // Missing bind shim or IE8 + Modernizr, fallback to wrapping
41 return function() {
42 return Function.prototype.apply.apply(method, [obj, arguments]);
43 };
44 }
45 }
46 }
47
48 // Build the best logging method possible for this env
49 // Wherever possible we want to bind, not wrap, to preserve stack traces
50 function realMethod(methodName) {
51 if (methodName === 'debug') {
52 methodName = 'log';
53 }
54
55 if (typeof console === undefinedType) {
56 return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives
57 } else if (console[methodName] !== undefined) {
58 return bindMethod(console, methodName);
59 } else if (console.log !== undefined) {
60 return bindMethod(console, 'log');
61 } else {
62 return noop;
63 }
64 }
65
66 // These private functions always need `this` to be set properly
67
68 function replaceLoggingMethods(level, loggerName) {
69 /*jshint validthis:true */
70 for (var i = 0; i < logMethods.length; i++) {
71 var methodName = logMethods[i];
72 this[methodName] = (i < level) ?
73 noop :
74 this.methodFactory(methodName, level, loggerName);
75 }
76
77 // Define log.log as an alias for log.debug
78 this.log = this.debug;
79 }
80
81 // In old IE versions, the console isn't present until you first open it.
82 // We build realMethod() replacements here that regenerate logging methods
83 function enableLoggingWhenConsoleArrives(methodName, level, loggerName) {
84 return function () {
85 if (typeof console !== undefinedType) {
86 replaceLoggingMethods.call(this, level, loggerName);
87 this[methodName].apply(this, arguments);
88 }
89 };
90 }
91
92 // By default, we use closely bound real methods wherever possible, and
93 // otherwise we wait for a console to appear, and then try again.
94 function defaultMethodFactory(methodName, level, loggerName) {
95 /*jshint validthis:true */
96 return realMethod(methodName) ||
97 enableLoggingWhenConsoleArrives.apply(this, arguments);
98 }
99
100 function Logger(name, defaultLevel, factory) {
101 var self = this;
102 var currentLevel;
103 var storageKey = "loglevel";
104 if (name) {
105 storageKey += ":" + name;
106 }
107
108 function persistLevelIfPossible(levelNum) {
109 var levelName = (logMethods[levelNum] || 'silent').toUpperCase();
110
111 if (typeof window === undefinedType) return;
112
113 // Use localStorage if available
114 try {
115 window.localStorage[storageKey] = levelName;
116 return;
117 } catch (ignore) {}
118
119 // Use session cookie as fallback
120 try {
121 window.document.cookie =
122 encodeURIComponent(storageKey) + "=" + levelName + ";";
123 } catch (ignore) {}
124 }
125
126 function getPersistedLevel() {
127 var storedLevel;
128
129 if (typeof window === undefinedType) return;
130
131 try {
132 storedLevel = window.localStorage[storageKey];
133 } catch (ignore) {}
134
135 // Fallback to cookies if local storage gives us nothing
136 if (typeof storedLevel === undefinedType) {
137 try {
138 var cookie = window.document.cookie;
139 var location = cookie.indexOf(
140 encodeURIComponent(storageKey) + "=");
141 if (location !== -1) {
142 storedLevel = /^([^;]+)/.exec(cookie.slice(location))[1];
143 }
144 } catch (ignore) {}
145 }
146
147 // If the stored level is not valid, treat it as if nothing was stored.
148 if (self.levels[storedLevel] === undefined) {
149 storedLevel = undefined;
150 }
151
152 return storedLevel;
153 }
154
155 /*
156 *
157 * Public logger API - see https://github.com/pimterry/loglevel for details
158 *
159 */
160
161 self.name = name;
162
163 self.levels = { "TRACE": 0, "DEBUG": 1, "INFO": 2, "WARN": 3,
164 "ERROR": 4, "SILENT": 5};
165
166 self.methodFactory = factory || defaultMethodFactory;
167
168 self.getLevel = function () {
169 return currentLevel;
170 };
171
172 self.setLevel = function (level, persist) {
173 if (typeof level === "string" && self.levels[level.toUpperCase()] !== undefined) {
174 level = self.levels[level.toUpperCase()];
175 }
176 if (typeof level === "number" && level >= 0 && level <= self.levels.SILENT) {
177 currentLevel = level;
178 if (persist !== false) { // defaults to true
179 persistLevelIfPossible(level);
180 }
181 replaceLoggingMethods.call(self, level, name);
182 if (typeof console === undefinedType && level < self.levels.SILENT) {
183 return "No console available for logging";
184 }
185 } else {
186 throw "log.setLevel() called with invalid level: " + level;
187 }
188 };
189
190 self.setDefaultLevel = function (level) {
191 if (!getPersistedLevel()) {
192 self.setLevel(level, false);
193 }
194 };
195
196 self.enableAll = function(persist) {
197 self.setLevel(self.levels.TRACE, persist);
198 };
199
200 self.disableAll = function(persist) {
201 self.setLevel(self.levels.SILENT, persist);
202 };
203
204 // Initialize with the right level
205 var initialLevel = getPersistedLevel();
206 if (initialLevel == null) {
207 initialLevel = defaultLevel == null ? "WARN" : defaultLevel;
208 }
209 self.setLevel(initialLevel, false);
210 }
211
212 /*
213 *
214 * Top-level API
215 *
216 */
217
218 var defaultLogger = new Logger();
219
220 var _loggersByName = {};
221 defaultLogger.getLogger = function getLogger(name) {
222 if (typeof name !== "string" || name === "") {
223 throw new TypeError("You must supply a name when creating a logger.");
224 }
225
226 var logger = _loggersByName[name];
227 if (!logger) {
228 logger = _loggersByName[name] = new Logger(
229 name, defaultLogger.getLevel(), defaultLogger.methodFactory);
230 }
231 return logger;
232 };
233
234 // Grab the current global log variable in case of overwrite
235 var _log = (typeof window !== undefinedType) ? window.log : undefined;
236 defaultLogger.noConflict = function() {
237 if (typeof window !== undefinedType &&
238 window.log === defaultLogger) {
239 window.log = _log;
240 }
241
242 return defaultLogger;
243 };
244
245 defaultLogger.getLoggers = function getLoggers() {
246 return _loggersByName;
247 };
248
249 return defaultLogger;
250}));