loglevel.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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. // Slightly dubious tricks to cut down minimized file size
  19. var noop = function() {};
  20. var undefinedType = "undefined";
  21. var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && (
  22. /Trident\/|MSIE /.test(window.navigator.userAgent)
  23. );
  24. var logMethods = [
  25. "trace",
  26. "debug",
  27. "info",
  28. "warn",
  29. "error"
  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. // Trace() doesn't print the message in IE, so for that case we need to wrap it
  48. function traceForIE() {
  49. if (console.log) {
  50. if (console.log.apply) {
  51. console.log.apply(console, arguments);
  52. } else {
  53. // In old IE, native console methods themselves don't have apply().
  54. Function.prototype.apply.apply(console.log, [console, arguments]);
  55. }
  56. }
  57. if (console.trace) console.trace();
  58. }
  59. // Build the best logging method possible for this env
  60. // Wherever possible we want to bind, not wrap, to preserve stack traces
  61. function realMethod(methodName) {
  62. if (methodName === 'debug') {
  63. methodName = 'log';
  64. }
  65. if (typeof console === undefinedType) {
  66. return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives
  67. } else if (methodName === 'trace' && isIE) {
  68. return traceForIE;
  69. } else if (console[methodName] !== undefined) {
  70. return bindMethod(console, methodName);
  71. } else if (console.log !== undefined) {
  72. return bindMethod(console, 'log');
  73. } else {
  74. return noop;
  75. }
  76. }
  77. // These private functions always need `this` to be set properly
  78. function replaceLoggingMethods(level, loggerName) {
  79. /*jshint validthis:true */
  80. for (var i = 0; i < logMethods.length; i++) {
  81. var methodName = logMethods[i];
  82. this[methodName] = (i < level) ?
  83. noop :
  84. this.methodFactory(methodName, level, loggerName);
  85. }
  86. // Define log.log as an alias for log.debug
  87. this.log = this.debug;
  88. }
  89. // In old IE versions, the console isn't present until you first open it.
  90. // We build realMethod() replacements here that regenerate logging methods
  91. function enableLoggingWhenConsoleArrives(methodName, level, loggerName) {
  92. return function () {
  93. if (typeof console !== undefinedType) {
  94. replaceLoggingMethods.call(this, level, loggerName);
  95. this[methodName].apply(this, arguments);
  96. }
  97. };
  98. }
  99. // By default, we use closely bound real methods wherever possible, and
  100. // otherwise we wait for a console to appear, and then try again.
  101. function defaultMethodFactory(methodName, level, loggerName) {
  102. /*jshint validthis:true */
  103. return realMethod(methodName) ||
  104. enableLoggingWhenConsoleArrives.apply(this, arguments);
  105. }
  106. function Logger(name, defaultLevel, factory) {
  107. var self = this;
  108. var currentLevel;
  109. defaultLevel = defaultLevel == null ? "WARN" : defaultLevel;
  110. var storageKey = "loglevel";
  111. if (typeof name === "string") {
  112. storageKey += ":" + name;
  113. } else if (typeof name === "symbol") {
  114. storageKey = undefined;
  115. }
  116. function persistLevelIfPossible(levelNum) {
  117. var levelName = (logMethods[levelNum] || 'silent').toUpperCase();
  118. if (typeof window === undefinedType || !storageKey) return;
  119. // Use localStorage if available
  120. try {
  121. window.localStorage[storageKey] = levelName;
  122. return;
  123. } catch (ignore) {}
  124. // Use session cookie as fallback
  125. try {
  126. window.document.cookie =
  127. encodeURIComponent(storageKey) + "=" + levelName + ";";
  128. } catch (ignore) {}
  129. }
  130. function getPersistedLevel() {
  131. var storedLevel;
  132. if (typeof window === undefinedType || !storageKey) return;
  133. try {
  134. storedLevel = window.localStorage[storageKey];
  135. } catch (ignore) {}
  136. // Fallback to cookies if local storage gives us nothing
  137. if (typeof storedLevel === undefinedType) {
  138. try {
  139. var cookie = window.document.cookie;
  140. var location = cookie.indexOf(
  141. encodeURIComponent(storageKey) + "=");
  142. if (location !== -1) {
  143. storedLevel = /^([^;]+)/.exec(cookie.slice(location))[1];
  144. }
  145. } catch (ignore) {}
  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. return storedLevel;
  152. }
  153. function clearPersistedLevel() {
  154. if (typeof window === undefinedType || !storageKey) return;
  155. // Use localStorage if available
  156. try {
  157. window.localStorage.removeItem(storageKey);
  158. return;
  159. } catch (ignore) {}
  160. // Use session cookie as fallback
  161. try {
  162. window.document.cookie =
  163. encodeURIComponent(storageKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC";
  164. } catch (ignore) {}
  165. }
  166. /*
  167. *
  168. * Public logger API - see https://github.com/pimterry/loglevel for details
  169. *
  170. */
  171. self.name = name;
  172. self.levels = { "TRACE": 0, "DEBUG": 1, "INFO": 2, "WARN": 3,
  173. "ERROR": 4, "SILENT": 5};
  174. self.methodFactory = factory || defaultMethodFactory;
  175. self.getLevel = function () {
  176. return currentLevel;
  177. };
  178. self.setLevel = function (level, persist) {
  179. if (typeof level === "string" && self.levels[level.toUpperCase()] !== undefined) {
  180. level = self.levels[level.toUpperCase()];
  181. }
  182. if (typeof level === "number" && level >= 0 && level <= self.levels.SILENT) {
  183. currentLevel = level;
  184. if (persist !== false) { // defaults to true
  185. persistLevelIfPossible(level);
  186. }
  187. replaceLoggingMethods.call(self, level, name);
  188. if (typeof console === undefinedType && level < self.levels.SILENT) {
  189. return "No console available for logging";
  190. }
  191. } else {
  192. throw "log.setLevel() called with invalid level: " + level;
  193. }
  194. };
  195. self.setDefaultLevel = function (level) {
  196. defaultLevel = level;
  197. if (!getPersistedLevel()) {
  198. self.setLevel(level, false);
  199. }
  200. };
  201. self.resetLevel = function () {
  202. self.setLevel(defaultLevel, false);
  203. clearPersistedLevel();
  204. };
  205. self.enableAll = function(persist) {
  206. self.setLevel(self.levels.TRACE, persist);
  207. };
  208. self.disableAll = function(persist) {
  209. self.setLevel(self.levels.SILENT, persist);
  210. };
  211. // Initialize with the right level
  212. var initialLevel = getPersistedLevel();
  213. if (initialLevel == null) {
  214. initialLevel = defaultLevel;
  215. }
  216. self.setLevel(initialLevel, false);
  217. }
  218. /*
  219. *
  220. * Top-level API
  221. *
  222. */
  223. var defaultLogger = new Logger();
  224. var _loggersByName = {};
  225. defaultLogger.getLogger = function getLogger(name) {
  226. if ((typeof name !== "symbol" && typeof name !== "string") || name === "") {
  227. throw new TypeError("You must supply a name when creating a logger.");
  228. }
  229. var logger = _loggersByName[name];
  230. if (!logger) {
  231. logger = _loggersByName[name] = new Logger(
  232. name, defaultLogger.getLevel(), defaultLogger.methodFactory);
  233. }
  234. return logger;
  235. };
  236. // Grab the current global log variable in case of overwrite
  237. var _log = (typeof window !== undefinedType) ? window.log : undefined;
  238. defaultLogger.noConflict = function() {
  239. if (typeof window !== undefinedType &&
  240. window.log === defaultLogger) {
  241. window.log = _log;
  242. }
  243. return defaultLogger;
  244. };
  245. defaultLogger.getLoggers = function getLoggers() {
  246. return _loggersByName;
  247. };
  248. // ES6 default export, for compatibility
  249. defaultLogger['default'] = defaultLogger;
  250. return defaultLogger;
  251. }));