loglevel.js 7.7 KB

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