logger.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /* eslint no-underscore-dangle: ["error", { "allow": ["_log"] }] */
  2. const debug = require("debug")("log4js:logger");
  3. const LoggingEvent = require("./LoggingEvent");
  4. const levels = require("./levels");
  5. const clustering = require("./clustering");
  6. const categories = require("./categories");
  7. const configuration = require("./configuration");
  8. const stackReg = /at (?:(.+)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/;
  9. function defaultParseCallStack(data, skipIdx = 4) {
  10. try {
  11. const stacklines = data.stack.split("\n").slice(skipIdx);
  12. const lineMatch = stackReg.exec(stacklines[0]);
  13. /* istanbul ignore else: failsafe */
  14. if (lineMatch && lineMatch.length === 6) {
  15. return {
  16. functionName: lineMatch[1],
  17. fileName: lineMatch[2],
  18. lineNumber: parseInt(lineMatch[3], 10),
  19. columnNumber: parseInt(lineMatch[4], 10),
  20. callStack: stacklines.join("\n")
  21. };
  22. } else { // eslint-disable-line no-else-return
  23. // will never get here unless nodejs has changes to Error
  24. console.error('log4js.logger - defaultParseCallStack error'); // eslint-disable-line no-console
  25. }
  26. }
  27. catch (err) {
  28. // will never get error unless nodejs has breaking changes to Error
  29. console.error('log4js.logger - defaultParseCallStack error', err); // eslint-disable-line no-console
  30. }
  31. return null;
  32. }
  33. /**
  34. * Logger to log messages.
  35. * use {@see log4js#getLogger(String)} to get an instance.
  36. *
  37. * @name Logger
  38. * @namespace Log4js
  39. * @param name name of category to log to
  40. * @param level - the loglevel for the category
  41. * @param dispatch - the function which will receive the logevents
  42. *
  43. * @author Stephan Strittmatter
  44. */
  45. class Logger {
  46. constructor(name) {
  47. if (!name) {
  48. throw new Error("No category provided.");
  49. }
  50. this.category = name;
  51. this.context = {};
  52. this.parseCallStack = defaultParseCallStack;
  53. debug(`Logger created (${this.category}, ${this.level})`);
  54. }
  55. get level() {
  56. return levels.getLevel(
  57. categories.getLevelForCategory(this.category),
  58. levels.OFF
  59. );
  60. }
  61. set level(level) {
  62. categories.setLevelForCategory(
  63. this.category,
  64. levels.getLevel(level, this.level)
  65. );
  66. }
  67. get useCallStack() {
  68. return categories.getEnableCallStackForCategory(this.category);
  69. }
  70. set useCallStack(bool) {
  71. categories.setEnableCallStackForCategory(this.category, bool === true);
  72. }
  73. log(level, ...args) {
  74. let logLevel = levels.getLevel(level);
  75. if (!logLevel) {
  76. // allow LOG to be synonym of INFO
  77. if ((level && level.trim().indexOf(" ") !== -1) || args.length === 0) {
  78. args = [level, ...args];
  79. } else {
  80. this._log(levels.WARN, ['log4js:logger.log: invalid value for log-level as first parameter given:', level]);
  81. args = [`[${level}]`, ...args];
  82. }
  83. // fallback to INFO
  84. logLevel = levels.INFO;
  85. }
  86. if (this.isLevelEnabled(logLevel)) {
  87. this._log(logLevel, args);
  88. }
  89. }
  90. isLevelEnabled(otherLevel) {
  91. return this.level.isLessThanOrEqualTo(otherLevel);
  92. }
  93. _log(level, data) {
  94. debug(`sending log data (${level}) to appenders`);
  95. const loggingEvent = new LoggingEvent(
  96. this.category,
  97. level,
  98. data,
  99. this.context,
  100. this.useCallStack && this.parseCallStack(new Error())
  101. );
  102. clustering.send(loggingEvent);
  103. }
  104. addContext(key, value) {
  105. this.context[key] = value;
  106. }
  107. removeContext(key) {
  108. delete this.context[key];
  109. }
  110. clearContext() {
  111. this.context = {};
  112. }
  113. setParseCallStackFunction(parseFunction) {
  114. this.parseCallStack = parseFunction;
  115. }
  116. }
  117. function addLevelMethods(target) {
  118. const level = levels.getLevel(target);
  119. const levelStrLower = level.toString().toLowerCase();
  120. const levelMethod = levelStrLower.replace(/_([a-z])/g, g =>
  121. g[1].toUpperCase()
  122. );
  123. const isLevelMethod = levelMethod[0].toUpperCase() + levelMethod.slice(1);
  124. Logger.prototype[`is${isLevelMethod}Enabled`] = function () {
  125. return this.isLevelEnabled(level);
  126. };
  127. Logger.prototype[levelMethod] = function (...args) {
  128. this.log(level, ...args);
  129. };
  130. }
  131. levels.levels.forEach(addLevelMethods);
  132. configuration.addListener(() => {
  133. levels.levels.forEach(addLevelMethods);
  134. });
  135. module.exports = Logger;