logger.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. var log4js = require('log4js');
  2. var fs = require('fs');
  3. var util = require('util');
  4. var funcs = {
  5. 'env': doEnv,
  6. 'args': doArgs,
  7. 'opts': doOpts
  8. };
  9. function getLogger(categoryName) {
  10. var args = arguments;
  11. var prefix = "";
  12. for (var i = 1; i < args.length; i++) {
  13. if(i !== args.length-1)
  14. prefix = prefix + args[i] + "] [";
  15. else
  16. prefix = prefix + args[i];
  17. }
  18. if (typeof categoryName === 'string') {
  19. // category name is __filename then cut the prefix path
  20. categoryName = categoryName.replace(process.cwd(), '');
  21. }
  22. var logger = log4js.getLogger(categoryName);
  23. var pLogger = {};
  24. for (var key in logger) {
  25. pLogger[key] = logger[key];
  26. }
  27. ['log', 'debug', 'info', 'warn', 'error', 'trace', 'fatal'].forEach(function(item) {
  28. pLogger[item] = function() {
  29. var p = "";
  30. if (args.length > 1) {
  31. p = "[" + prefix + "] ";
  32. }
  33. if(args.length && process.env.LOGGER_LINE) {
  34. p = getLine() + ": " + p;
  35. }
  36. p = colorize(p, colours[item]);
  37. if(args.length) {
  38. arguments[0] = p + arguments[0];
  39. }
  40. logger[item].apply(logger, arguments);
  41. }
  42. });
  43. return pLogger;
  44. };
  45. var configState = {};
  46. function initReloadConfiguration(filename, reloadSecs) {
  47. if (configState.timerId) {
  48. clearInterval(configState.timerId);
  49. delete configState.timerId;
  50. }
  51. configState.filename = filename;
  52. configState.lastMTime = getMTime(filename);
  53. configState.timerId = setInterval(reloadConfiguration, reloadSecs * 1000);
  54. };
  55. function getMTime(filename) {
  56. var mtime;
  57. try {
  58. mtime = fs.statSync(filename).mtime;
  59. } catch (e) {
  60. throw new Error("Cannot find file with given path: " + filename);
  61. }
  62. return mtime;
  63. };
  64. function loadConfigurationFile(filename) {
  65. if (filename) {
  66. return JSON.parse(fs.readFileSync(filename, "utf8"));
  67. }
  68. return undefined;
  69. };
  70. function reloadConfiguration() {
  71. var mtime = getMTime(configState.filename);
  72. if (!mtime) {
  73. return;
  74. }
  75. if (configState.lastMTime && (mtime.getTime() > configState.lastMTime.getTime())) {
  76. configureOnceOff(loadConfigurationFile(configState.filename));
  77. }
  78. configState.lastMTime = mtime;
  79. };
  80. function configureOnceOff(config) {
  81. if (config) {
  82. try {
  83. configureLevels(config.levels);
  84. if (config.replaceConsole) {
  85. log4js.replaceConsole();
  86. } else {
  87. log4js.restoreConsole();
  88. }
  89. } catch (e) {
  90. throw new Error(
  91. "Problem reading log4js config " + util.inspect(config) +
  92. ". Error was \"" + e.message + "\" (" + e.stack + ")"
  93. );
  94. }
  95. }
  96. };
  97. function configureLevels(levels) {
  98. if (levels) {
  99. for (var category in levels) {
  100. if (levels.hasOwnProperty(category)) {
  101. log4js.getLogger(category).setLevel(levels[category]);
  102. }
  103. }
  104. }
  105. };
  106. /**
  107. * Configure the logger.
  108. * Configure file just like log4js.json. And support ${scope:arg-name} format property setting.
  109. * It can replace the placeholder in runtime.
  110. * scope can be:
  111. * env: environment variables, such as: env:PATH
  112. * args: command line arguments, such as: args:1
  113. * opts: key/value from opts argument of configure function
  114. *
  115. * @param {String|Object} config configure file name or configure object
  116. * @param {Object} opts options
  117. * @return {Void}
  118. */
  119. function configure(config, opts) {
  120. var filename = config;
  121. config = config || process.env.LOG4JS_CONFIG;
  122. opts = opts || {};
  123. if (typeof config === 'string') {
  124. config = JSON.parse(fs.readFileSync(config, "utf8"));
  125. }
  126. if (config) {
  127. config = replaceProperties(config, opts);
  128. }
  129. if(config && config.lineDebug) {
  130. process.env.LOGGER_LINE = true;
  131. }
  132. if(filename && config && config.reloadSecs) {
  133. initReloadConfiguration(filename, config.reloadSecs);
  134. }
  135. // config object could not turn on the auto reload configure file in log4js
  136. log4js.configure(config, opts);
  137. };
  138. function replaceProperties(configObj, opts) {
  139. if (configObj instanceof Array) {
  140. for (var i = 0, l = configObj.length; i < l; i++) {
  141. configObj[i] = replaceProperties(configObj[i], opts);
  142. }
  143. } else if (typeof configObj === 'object') {
  144. var field;
  145. for (var f in configObj) {
  146. if (!configObj.hasOwnProperty(f)) {
  147. continue;
  148. }
  149. field = configObj[f];
  150. if (typeof field === 'string') {
  151. configObj[f] = doReplace(field, opts);
  152. } else if (typeof field === 'object') {
  153. configObj[f] = replaceProperties(field, opts);
  154. }
  155. }
  156. }
  157. return configObj;
  158. }
  159. function doReplace(src, opts) {
  160. if (!src) {
  161. return src;
  162. }
  163. var ptn = /\$\{(.*?)\}/g;
  164. var m, pro, ts, scope, name, defaultValue, func, res = '',
  165. lastIndex = 0;
  166. while ((m = ptn.exec(src))) {
  167. pro = m[1];
  168. ts = pro.split(':');
  169. if (ts.length !== 2 && ts.length !== 3) {
  170. res += pro;
  171. continue;
  172. }
  173. scope = ts[0];
  174. name = ts[1];
  175. if (ts.length === 3) {
  176. defaultValue = ts[2];
  177. }
  178. func = funcs[scope];
  179. if (!func && typeof func !== 'function') {
  180. res += pro;
  181. continue;
  182. }
  183. res += src.substring(lastIndex, m.index);
  184. lastIndex = ptn.lastIndex;
  185. res += (func(name, opts) || defaultValue);
  186. }
  187. if (lastIndex < src.length) {
  188. res += src.substring(lastIndex);
  189. }
  190. return res;
  191. }
  192. function doEnv(name) {
  193. return process.env[name];
  194. }
  195. function doArgs(name) {
  196. return process.argv[name];
  197. }
  198. function doOpts(name, opts) {
  199. return opts ? opts[name] : undefined;
  200. }
  201. function getLine() {
  202. var e = new Error();
  203. // now magic will happen: get line number from callstack
  204. var line = e.stack.split('\n')[3].split(':')[1];
  205. return line;
  206. }
  207. function colorizeStart(style) {
  208. return style ? '\x1B[' + styles[style][0] + 'm' : '';
  209. }
  210. function colorizeEnd(style) {
  211. return style ? '\x1B[' + styles[style][1] + 'm' : '';
  212. }
  213. /**
  214. * Taken from masylum's fork (https://github.com/masylum/log4js-node)
  215. */
  216. function colorize (str, style) {
  217. return colorizeStart(style) + str + colorizeEnd(style);
  218. }
  219. var styles = {
  220. //styles
  221. 'bold' : [1, 22],
  222. 'italic' : [3, 23],
  223. 'underline' : [4, 24],
  224. 'inverse' : [7, 27],
  225. //grayscale
  226. 'white' : [37, 39],
  227. 'grey' : [90, 39],
  228. 'black' : [90, 39],
  229. //colors
  230. 'blue' : [34, 39],
  231. 'cyan' : [36, 39],
  232. 'green' : [32, 39],
  233. 'magenta' : [35, 39],
  234. 'red' : [31, 39],
  235. 'yellow' : [33, 39]
  236. };
  237. var colours = {
  238. 'all': "grey",
  239. 'trace': "blue",
  240. 'debug': "cyan",
  241. 'info': "green",
  242. 'warn': "yellow",
  243. 'error': "red",
  244. 'fatal': "magenta",
  245. 'off': "grey"
  246. };
  247. module.exports = {
  248. getLogger: getLogger,
  249. getDefaultLogger: log4js.getDefaultLogger,
  250. addAppender: log4js.addAppender,
  251. loadAppender: log4js.loadAppender,
  252. clearAppenders: log4js.clearAppenders,
  253. configure: configure,
  254. replaceConsole: log4js.replaceConsole,
  255. restoreConsole: log4js.restoreConsole,
  256. levels: log4js.levels,
  257. setGlobalLogLevel: log4js.setGlobalLogLevel,
  258. layouts: log4js.layouts,
  259. appenders: log4js.appenders
  260. };