UNPKG

11.3 kBJavaScriptView Raw
1/*! loglevel - v1.9.1 - https://github.com/pimterry/loglevel - (c) 2024 Tim Perry - licensed MIT */
2(function (root, definition) {
3 "use strict";
4 if (typeof define === 'function' && define.amd) {
5 define(definition);
6 } else if (typeof module === 'object' && module.exports) {
7 module.exports = definition();
8 } else {
9 root.log = definition();
10 }
11}(this, function () {
12 "use strict";
13
14 // Slightly dubious tricks to cut down minimized file size
15 var noop = function() {};
16 var undefinedType = "undefined";
17 var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && (
18 /Trident\/|MSIE /.test(window.navigator.userAgent)
19 );
20
21 var logMethods = [
22 "trace",
23 "debug",
24 "info",
25 "warn",
26 "error"
27 ];
28
29 var _loggersByName = {};
30 var defaultLogger = null;
31
32 // Cross-browser bind equivalent that works at least back to IE6
33 function bindMethod(obj, methodName) {
34 var method = obj[methodName];
35 if (typeof method.bind === 'function') {
36 return method.bind(obj);
37 } else {
38 try {
39 return Function.prototype.bind.call(method, obj);
40 } catch (e) {
41 // Missing bind shim or IE8 + Modernizr, fallback to wrapping
42 return function() {
43 return Function.prototype.apply.apply(method, [obj, arguments]);
44 };
45 }
46 }
47 }
48
49 // Trace() doesn't print the message in IE, so for that case we need to wrap it
50 function traceForIE() {
51 if (console.log) {
52 if (console.log.apply) {
53 console.log.apply(console, arguments);
54 } else {
55 // In old IE, native console methods themselves don't have apply().
56 Function.prototype.apply.apply(console.log, [console, arguments]);
57 }
58 }
59 if (console.trace) console.trace();
60 }
61
62 // Build the best logging method possible for this env
63 // Wherever possible we want to bind, not wrap, to preserve stack traces
64 function realMethod(methodName) {
65 if (methodName === 'debug') {
66 methodName = 'log';
67 }
68
69 if (typeof console === undefinedType) {
70 return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives
71 } else if (methodName === 'trace' && isIE) {
72 return traceForIE;
73 } else if (console[methodName] !== undefined) {
74 return bindMethod(console, methodName);
75 } else if (console.log !== undefined) {
76 return bindMethod(console, 'log');
77 } else {
78 return noop;
79 }
80 }
81
82 // These private functions always need `this` to be set properly
83
84 function replaceLoggingMethods() {
85 /*jshint validthis:true */
86 var level = this.getLevel();
87
88 // Replace the actual methods.
89 for (var i = 0; i < logMethods.length; i++) {
90 var methodName = logMethods[i];
91 this[methodName] = (i < level) ?
92 noop :
93 this.methodFactory(methodName, level, this.name);
94 }
95
96 // Define log.log as an alias for log.debug
97 this.log = this.debug;
98
99 // Return any important warnings.
100 if (typeof console === undefinedType && level < this.levels.SILENT) {
101 return "No console available for logging";
102 }
103 }
104
105 // In old IE versions, the console isn't present until you first open it.
106 // We build realMethod() replacements here that regenerate logging methods
107 function enableLoggingWhenConsoleArrives(methodName) {
108 return function () {
109 if (typeof console !== undefinedType) {
110 replaceLoggingMethods.call(this);
111 this[methodName].apply(this, arguments);
112 }
113 };
114 }
115
116 // By default, we use closely bound real methods wherever possible, and
117 // otherwise we wait for a console to appear, and then try again.
118 function defaultMethodFactory(methodName, _level, _loggerName) {
119 /*jshint validthis:true */
120 return realMethod(methodName) ||
121 enableLoggingWhenConsoleArrives.apply(this, arguments);
122 }
123
124 function Logger(name, factory) {
125 // Private instance variables.
126 var self = this;
127 /**
128 * The level inherited from a parent logger (or a global default). We
129 * cache this here rather than delegating to the parent so that it stays
130 * in sync with the actual logging methods that we have installed (the
131 * parent could change levels but we might not have rebuilt the loggers
132 * in this child yet).
133 * @type {number}
134 */
135 var inheritedLevel;
136 /**
137 * The default level for this logger, if any. If set, this overrides
138 * `inheritedLevel`.
139 * @type {number|null}
140 */
141 var defaultLevel;
142 /**
143 * A user-specific level for this logger. If set, this overrides
144 * `defaultLevel`.
145 * @type {number|null}
146 */
147 var userLevel;
148
149 var storageKey = "loglevel";
150 if (typeof name === "string") {
151 storageKey += ":" + name;
152 } else if (typeof name === "symbol") {
153 storageKey = undefined;
154 }
155
156 function persistLevelIfPossible(levelNum) {
157 var levelName = (logMethods[levelNum] || 'silent').toUpperCase();
158
159 if (typeof window === undefinedType || !storageKey) return;
160
161 // Use localStorage if available
162 try {
163 window.localStorage[storageKey] = levelName;
164 return;
165 } catch (ignore) {}
166
167 // Use session cookie as fallback
168 try {
169 window.document.cookie =
170 encodeURIComponent(storageKey) + "=" + levelName + ";";
171 } catch (ignore) {}
172 }
173
174 function getPersistedLevel() {
175 var storedLevel;
176
177 if (typeof window === undefinedType || !storageKey) return;
178
179 try {
180 storedLevel = window.localStorage[storageKey];
181 } catch (ignore) {}
182
183 // Fallback to cookies if local storage gives us nothing
184 if (typeof storedLevel === undefinedType) {
185 try {
186 var cookie = window.document.cookie;
187 var cookieName = encodeURIComponent(storageKey);
188 var location = cookie.indexOf(cookieName + "=");
189 if (location !== -1) {
190 storedLevel = /^([^;]+)/.exec(
191 cookie.slice(location + cookieName.length + 1)
192 )[1];
193 }
194 } catch (ignore) {}
195 }
196
197 // If the stored level is not valid, treat it as if nothing was stored.
198 if (self.levels[storedLevel] === undefined) {
199 storedLevel = undefined;
200 }
201
202 return storedLevel;
203 }
204
205 function clearPersistedLevel() {
206 if (typeof window === undefinedType || !storageKey) return;
207
208 // Use localStorage if available
209 try {
210 window.localStorage.removeItem(storageKey);
211 } catch (ignore) {}
212
213 // Use session cookie as fallback
214 try {
215 window.document.cookie =
216 encodeURIComponent(storageKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC";
217 } catch (ignore) {}
218 }
219
220 function normalizeLevel(input) {
221 var level = input;
222 if (typeof level === "string" && self.levels[level.toUpperCase()] !== undefined) {
223 level = self.levels[level.toUpperCase()];
224 }
225 if (typeof level === "number" && level >= 0 && level <= self.levels.SILENT) {
226 return level;
227 } else {
228 throw new TypeError("log.setLevel() called with invalid level: " + input);
229 }
230 }
231
232 /*
233 *
234 * Public logger API - see https://github.com/pimterry/loglevel for details
235 *
236 */
237
238 self.name = name;
239
240 self.levels = { "TRACE": 0, "DEBUG": 1, "INFO": 2, "WARN": 3,
241 "ERROR": 4, "SILENT": 5};
242
243 self.methodFactory = factory || defaultMethodFactory;
244
245 self.getLevel = function () {
246 if (userLevel != null) {
247 return userLevel;
248 } else if (defaultLevel != null) {
249 return defaultLevel;
250 } else {
251 return inheritedLevel;
252 }
253 };
254
255 self.setLevel = function (level, persist) {
256 userLevel = normalizeLevel(level);
257 if (persist !== false) { // defaults to true
258 persistLevelIfPossible(userLevel);
259 }
260
261 // NOTE: in v2, this should call rebuild(), which updates children.
262 return replaceLoggingMethods.call(self);
263 };
264
265 self.setDefaultLevel = function (level) {
266 defaultLevel = normalizeLevel(level);
267 if (!getPersistedLevel()) {
268 self.setLevel(level, false);
269 }
270 };
271
272 self.resetLevel = function () {
273 userLevel = null;
274 clearPersistedLevel();
275 replaceLoggingMethods.call(self);
276 };
277
278 self.enableAll = function(persist) {
279 self.setLevel(self.levels.TRACE, persist);
280 };
281
282 self.disableAll = function(persist) {
283 self.setLevel(self.levels.SILENT, persist);
284 };
285
286 self.rebuild = function () {
287 if (defaultLogger !== self) {
288 inheritedLevel = normalizeLevel(defaultLogger.getLevel());
289 }
290 replaceLoggingMethods.call(self);
291
292 if (defaultLogger === self) {
293 for (var childName in _loggersByName) {
294 _loggersByName[childName].rebuild();
295 }
296 }
297 };
298
299 // Initialize all the internal levels.
300 inheritedLevel = normalizeLevel(
301 defaultLogger ? defaultLogger.getLevel() : "WARN"
302 );
303 var initialLevel = getPersistedLevel();
304 if (initialLevel != null) {
305 userLevel = normalizeLevel(initialLevel);
306 }
307 replaceLoggingMethods.call(self);
308 }
309
310 /*
311 *
312 * Top-level API
313 *
314 */
315
316 defaultLogger = new Logger();
317
318 defaultLogger.getLogger = function getLogger(name) {
319 if ((typeof name !== "symbol" && typeof name !== "string") || name === "") {
320 throw new TypeError("You must supply a name when creating a logger.");
321 }
322
323 var logger = _loggersByName[name];
324 if (!logger) {
325 logger = _loggersByName[name] = new Logger(
326 name,
327 defaultLogger.methodFactory
328 );
329 }
330 return logger;
331 };
332
333 // Grab the current global log variable in case of overwrite
334 var _log = (typeof window !== undefinedType) ? window.log : undefined;
335 defaultLogger.noConflict = function() {
336 if (typeof window !== undefinedType &&
337 window.log === defaultLogger) {
338 window.log = _log;
339 }
340
341 return defaultLogger;
342 };
343
344 defaultLogger.getLoggers = function getLoggers() {
345 return _loggersByName;
346 };
347
348 // ES6 default export, for compatibility
349 defaultLogger['default'] = defaultLogger;
350
351 return defaultLogger;
352}));