logger.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. 'use strict';
  2. const util = require('util');
  3. const utils = require('./utils');
  4. const depd = require('depd')('egg-logger');
  5. /**
  6. * Base class for all sub Logger class.
  7. * It extends Map, and can contains multi {@link Transport}
  8. *
  9. * @example
  10. * ```js
  11. * const logger = new Logger();
  12. * logger.set('file', new FileTransport({
  13. * file: '/path/to/log',
  14. * level: 'INFO',
  15. * }));
  16. * logger.set('console', new ConsoleTransport({
  17. * level: 'INFO',
  18. * }));
  19. * logger.info('foo');
  20. * ```
  21. */
  22. class Logger extends Map {
  23. /**
  24. * @param {Object} options - assign with `defaults` propery
  25. */
  26. constructor(options) {
  27. super();
  28. this.options = utils.assign(this.defaults, options);
  29. this.transports = {};
  30. this.name = this.constructor.name;
  31. this.redirectLoggers = new Map();
  32. this.duplicateLoggers = new Map();
  33. }
  34. /**
  35. * disable a transport
  36. * @param {String} name - transport name
  37. */
  38. disable(name) {
  39. const transport = this.get(name);
  40. if (transport) transport.disable();
  41. }
  42. /**
  43. * enable a transport
  44. * @param {String} name - transport name
  45. */
  46. enable(name) {
  47. const transport = this.get(name);
  48. if (transport) transport.enable();
  49. }
  50. /**
  51. * Send log to all transports.
  52. * It's proxy to {@link Transport}'s log method.
  53. * @param {String} level - log level
  54. * @param {Array} args - log arguments
  55. * @param {Object} meta - log meta
  56. */
  57. log(level, args, meta) {
  58. let excludes;
  59. let { logger, options } = this.duplicateLoggers.get(level) || {};
  60. if (logger) {
  61. excludes = options.excludes;
  62. logger.log(level, args, meta);
  63. } else {
  64. logger = this.redirectLoggers.get(level);
  65. if (logger) {
  66. logger.log(level, args, meta);
  67. return;
  68. }
  69. }
  70. for (const [ key, transport ] of this.entries()) {
  71. if (transport.shouldLog(level) && !(excludes && excludes.includes(key))) {
  72. transport.log(level, args, meta);
  73. }
  74. }
  75. }
  76. /**
  77. * write raw log to all transports
  78. * @param {String} msg - log message
  79. */
  80. write(msg) {
  81. // support util.format
  82. if (arguments.length > 1) msg = util.format.apply(util, arguments);
  83. // `NONE` is the top level
  84. this.log('NONE', [ msg ], { raw: true });
  85. }
  86. /**
  87. * Redirect specify level log to the other logger
  88. * @param {String} level - log level
  89. * @param {Logger} logger - target logger instance
  90. */
  91. redirect(level, logger) {
  92. level = level.toUpperCase();
  93. if (!this.redirectLoggers.has(level) && logger instanceof Logger) {
  94. this.redirectLoggers.set(level, logger);
  95. }
  96. }
  97. /**
  98. * Un-redirect specify level log
  99. * @param {String} level - log level
  100. */
  101. unredirect(level) {
  102. level = level.toUpperCase();
  103. this.redirectLoggers.delete(level);
  104. }
  105. /**
  106. * Duplicate specify level log to the other logger
  107. * @param {String} level - log level
  108. * @param {Logger} logger - target logger instance
  109. * @param {Object} [options] - { excludes: [] }
  110. */
  111. duplicate(level, logger, options = {}) {
  112. level = level.toUpperCase();
  113. if (!this.duplicateLoggers.has(level) && logger instanceof Logger) {
  114. this.duplicateLoggers.set(level, { logger, options });
  115. }
  116. }
  117. /**
  118. * Un-duplicate specify level log
  119. * @param {String} level - log level
  120. */
  121. unduplicate(level) {
  122. level = level.toUpperCase();
  123. this.duplicateLoggers.delete(level);
  124. }
  125. /**
  126. * Reload all transports
  127. */
  128. reload() {
  129. for (const transport of this.values()) {
  130. transport.reload();
  131. }
  132. }
  133. /**
  134. * End all transports
  135. */
  136. close() {
  137. for (const transport of this.values()) {
  138. transport.close();
  139. }
  140. }
  141. /**
  142. * @deprecated
  143. */
  144. end() {
  145. depd('logger.end() is deprecated, use logger.close()');
  146. this.close();
  147. }
  148. }
  149. [ 'error', 'warn', 'info', 'debug' ].forEach(level => {
  150. const LEVEL = level.toUpperCase();
  151. Logger.prototype[level] = function() {
  152. this.log(LEVEL, arguments);
  153. };
  154. });
  155. module.exports = Logger;