log4js.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /**
  2. * @fileoverview log4js is a library to log in JavaScript in similar manner
  3. * than in log4j for Java (but not really).
  4. *
  5. * <h3>Example:</h3>
  6. * <pre>
  7. * const logging = require('log4js');
  8. * const log = logging.getLogger('some-category');
  9. *
  10. * //call the log
  11. * log.trace('trace me' );
  12. * </pre>
  13. *
  14. * NOTE: the authors below are the original browser-based log4js authors
  15. * don't try to contact them about bugs in this version :)
  16. * @author Stephan Strittmatter - http://jroller.com/page/stritti
  17. * @author Seth Chisamore - http://www.chisamore.com
  18. * @since 2005-05-20
  19. * Website: http://log4js.berlios.de
  20. */
  21. const debug = require("debug")("log4js:main");
  22. const fs = require("fs");
  23. const deepClone = require("rfdc")({ proto: true });
  24. const configuration = require("./configuration");
  25. const layouts = require("./layouts");
  26. const levels = require("./levels");
  27. const appenders = require("./appenders");
  28. const categories = require("./categories");
  29. const Logger = require("./logger");
  30. const clustering = require("./clustering");
  31. const connectLogger = require("./connect-logger");
  32. let enabled = false;
  33. function sendLogEventToAppender(logEvent) {
  34. if (!enabled) return;
  35. debug("Received log event ", logEvent);
  36. const categoryAppenders = categories.appendersForCategory(
  37. logEvent.categoryName
  38. );
  39. categoryAppenders.forEach(appender => {
  40. appender(logEvent);
  41. });
  42. }
  43. function loadConfigurationFile(filename) {
  44. debug(`Loading configuration from ${filename}`);
  45. try {
  46. return JSON.parse(fs.readFileSync(filename, "utf8"));
  47. } catch (e) {
  48. throw new Error(
  49. `Problem reading config from file "${filename}". Error was ${e.message}`,
  50. e
  51. );
  52. }
  53. }
  54. function configure(configurationFileOrObject) {
  55. let configObject = configurationFileOrObject;
  56. if (typeof configObject === "string") {
  57. configObject = loadConfigurationFile(configurationFileOrObject);
  58. }
  59. debug(`Configuration is ${configObject}`);
  60. configuration.configure(deepClone(configObject));
  61. clustering.onMessage(sendLogEventToAppender);
  62. enabled = true;
  63. // eslint-disable-next-line no-use-before-define
  64. return log4js;
  65. }
  66. /**
  67. * Shutdown all log appenders. This will first disable all writing to appenders
  68. * and then call the shutdown function each appender.
  69. *
  70. * @params {Function} cb - The callback to be invoked once all appenders have
  71. * shutdown. If an error occurs, the callback will be given the error object
  72. * as the first argument.
  73. */
  74. function shutdown(cb) {
  75. debug("Shutdown called. Disabling all log writing.");
  76. // First, disable all writing to appenders. This prevents appenders from
  77. // not being able to be drained because of run-away log writes.
  78. enabled = false;
  79. // Call each of the shutdown functions in parallel
  80. const appendersToCheck = Array.from(appenders.values());
  81. const shutdownFunctions = appendersToCheck.reduceRight(
  82. (accum, next) => (next.shutdown ? accum + 1 : accum),
  83. 0
  84. );
  85. let completed = 0;
  86. let error;
  87. debug(`Found ${shutdownFunctions} appenders with shutdown functions.`);
  88. function complete(err) {
  89. error = error || err;
  90. completed += 1;
  91. debug(`Appender shutdowns complete: ${completed} / ${shutdownFunctions}`);
  92. if (completed >= shutdownFunctions) {
  93. debug("All shutdown functions completed.");
  94. if (cb) {
  95. cb(error);
  96. }
  97. }
  98. }
  99. if (shutdownFunctions === 0) {
  100. debug("No appenders with shutdown functions found.");
  101. return cb !== undefined && cb();
  102. }
  103. appendersToCheck.filter(a => a.shutdown).forEach(a => a.shutdown(complete));
  104. return null;
  105. }
  106. /**
  107. * Get a logger instance.
  108. * @static
  109. * @param loggerCategoryName
  110. * @return {Logger} instance of logger for the category
  111. */
  112. function getLogger(category) {
  113. if (!enabled) {
  114. configure(
  115. process.env.LOG4JS_CONFIG || {
  116. appenders: { out: { type: "stdout" } },
  117. categories: { default: { appenders: ["out"], level: "OFF" } }
  118. }
  119. );
  120. }
  121. return new Logger(category || "default");
  122. }
  123. /**
  124. * @name log4js
  125. * @namespace Log4js
  126. * @property getLogger
  127. * @property configure
  128. * @property shutdown
  129. */
  130. const log4js = {
  131. getLogger,
  132. configure,
  133. shutdown,
  134. connectLogger,
  135. levels,
  136. addLayout: layouts.addLayout
  137. };
  138. module.exports = log4js;