loglevel.js 7.7 KB

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