createConsoleLogger.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { LogType } = require("./Logger");
  7. /** @typedef {import("../../declarations/WebpackOptions").FilterItemTypes} FilterItemTypes */
  8. /** @typedef {import("../../declarations/WebpackOptions").FilterTypes} FilterTypes */
  9. /** @typedef {import("./Logger").LogTypeEnum} LogTypeEnum */
  10. /** @typedef {function(string): boolean} FilterFunction */
  11. /**
  12. * @typedef {Object} LoggerConsole
  13. * @property {function(): void} clear
  14. * @property {function(): void} trace
  15. * @property {(...args: any[]) => void} info
  16. * @property {(...args: any[]) => void} log
  17. * @property {(...args: any[]) => void} warn
  18. * @property {(...args: any[]) => void} error
  19. * @property {(...args: any[]) => void=} debug
  20. * @property {(...args: any[]) => void=} group
  21. * @property {(...args: any[]) => void=} groupCollapsed
  22. * @property {(...args: any[]) => void=} groupEnd
  23. * @property {(...args: any[]) => void=} status
  24. * @property {(...args: any[]) => void=} profile
  25. * @property {(...args: any[]) => void=} profileEnd
  26. * @property {(...args: any[]) => void=} logTime
  27. */
  28. /**
  29. * @typedef {Object} LoggerOptions
  30. * @property {false|true|"none"|"error"|"warn"|"info"|"log"|"verbose"} level loglevel
  31. * @property {FilterTypes|boolean} debug filter for debug logging
  32. * @property {LoggerConsole} console the console to log to
  33. */
  34. /**
  35. * @param {FilterItemTypes} item an input item
  36. * @returns {FilterFunction} filter function
  37. */
  38. const filterToFunction = item => {
  39. if (typeof item === "string") {
  40. const regExp = new RegExp(
  41. `[\\\\/]${item.replace(
  42. // eslint-disable-next-line no-useless-escape
  43. /[-[\]{}()*+?.\\^$|]/g,
  44. "\\$&"
  45. )}([\\\\/]|$|!|\\?)`
  46. );
  47. return ident => regExp.test(ident);
  48. }
  49. if (item && typeof item === "object" && typeof item.test === "function") {
  50. return ident => item.test(ident);
  51. }
  52. if (typeof item === "function") {
  53. return item;
  54. }
  55. if (typeof item === "boolean") {
  56. return () => item;
  57. }
  58. };
  59. /**
  60. * @enum {number}
  61. */
  62. const LogLevel = {
  63. none: 6,
  64. false: 6,
  65. error: 5,
  66. warn: 4,
  67. info: 3,
  68. log: 2,
  69. true: 2,
  70. verbose: 1
  71. };
  72. /**
  73. * @param {LoggerOptions} options options object
  74. * @returns {function(string, LogTypeEnum, any[]): void} logging function
  75. */
  76. module.exports = ({ level = "info", debug = false, console }) => {
  77. const debugFilters =
  78. typeof debug === "boolean"
  79. ? [() => debug]
  80. : /** @type {FilterItemTypes[]} */ ([])
  81. .concat(debug)
  82. .map(filterToFunction);
  83. /** @type {number} */
  84. const loglevel = LogLevel[`${level}`] || 0;
  85. /**
  86. * @param {string} name name of the logger
  87. * @param {LogTypeEnum} type type of the log entry
  88. * @param {any[]} args arguments of the log entry
  89. * @returns {void}
  90. */
  91. const logger = (name, type, args) => {
  92. const labeledArgs = () => {
  93. if (Array.isArray(args)) {
  94. if (args.length > 0 && typeof args[0] === "string") {
  95. return [`[${name}] ${args[0]}`, ...args.slice(1)];
  96. } else {
  97. return [`[${name}]`, ...args];
  98. }
  99. } else {
  100. return [];
  101. }
  102. };
  103. const debug = debugFilters.some(f => f(name));
  104. switch (type) {
  105. case LogType.debug:
  106. if (!debug) return;
  107. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  108. if (typeof console.debug === "function") {
  109. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  110. console.debug(...labeledArgs());
  111. } else {
  112. console.log(...labeledArgs());
  113. }
  114. break;
  115. case LogType.log:
  116. if (!debug && loglevel > LogLevel.log) return;
  117. console.log(...labeledArgs());
  118. break;
  119. case LogType.info:
  120. if (!debug && loglevel > LogLevel.info) return;
  121. console.info(...labeledArgs());
  122. break;
  123. case LogType.warn:
  124. if (!debug && loglevel > LogLevel.warn) return;
  125. console.warn(...labeledArgs());
  126. break;
  127. case LogType.error:
  128. if (!debug && loglevel > LogLevel.error) return;
  129. console.error(...labeledArgs());
  130. break;
  131. case LogType.trace:
  132. if (!debug) return;
  133. console.trace();
  134. break;
  135. case LogType.groupCollapsed:
  136. if (!debug && loglevel > LogLevel.log) return;
  137. if (!debug && loglevel > LogLevel.verbose) {
  138. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  139. if (typeof console.groupCollapsed === "function") {
  140. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  141. console.groupCollapsed(...labeledArgs());
  142. } else {
  143. console.log(...labeledArgs());
  144. }
  145. break;
  146. }
  147. // falls through
  148. case LogType.group:
  149. if (!debug && loglevel > LogLevel.log) return;
  150. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  151. if (typeof console.group === "function") {
  152. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  153. console.group(...labeledArgs());
  154. } else {
  155. console.log(...labeledArgs());
  156. }
  157. break;
  158. case LogType.groupEnd:
  159. if (!debug && loglevel > LogLevel.log) return;
  160. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  161. if (typeof console.groupEnd === "function") {
  162. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  163. console.groupEnd();
  164. }
  165. break;
  166. case LogType.time: {
  167. if (!debug && loglevel > LogLevel.log) return;
  168. const ms = args[1] * 1000 + args[2] / 1000000;
  169. const msg = `[${name}] ${args[0]}: ${ms} ms`;
  170. if (typeof console.logTime === "function") {
  171. console.logTime(msg);
  172. } else {
  173. console.log(msg);
  174. }
  175. break;
  176. }
  177. case LogType.profile:
  178. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  179. if (typeof console.profile === "function") {
  180. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  181. console.profile(...labeledArgs());
  182. }
  183. break;
  184. case LogType.profileEnd:
  185. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  186. if (typeof console.profileEnd === "function") {
  187. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  188. console.profileEnd(...labeledArgs());
  189. }
  190. break;
  191. case LogType.clear:
  192. if (!debug && loglevel > LogLevel.log) return;
  193. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  194. if (typeof console.clear === "function") {
  195. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  196. console.clear();
  197. }
  198. break;
  199. case LogType.status:
  200. if (!debug && loglevel > LogLevel.info) return;
  201. if (typeof console.status === "function") {
  202. if (args.length === 0) {
  203. console.status();
  204. } else {
  205. console.status(...labeledArgs());
  206. }
  207. } else {
  208. if (args.length !== 0) {
  209. console.info(...labeledArgs());
  210. }
  211. }
  212. break;
  213. default:
  214. throw new Error(`Unexpected LogType ${type}`);
  215. }
  216. };
  217. return logger;
  218. };