log4js.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. "use strict";
  2. /*
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. /**
  16. * @fileoverview log4js is a library to log in JavaScript in similar manner
  17. * than in log4j for Java. The API should be nearly the same.
  18. *
  19. * <h3>Example:</h3>
  20. * <pre>
  21. * var logging = require('log4js');
  22. * //add an appender that logs all messages to stdout.
  23. * logging.addAppender(logging.consoleAppender());
  24. * //add an appender that logs "some-category" to a file
  25. * logging.addAppender(logging.fileAppender("file.log"), "some-category");
  26. * //get a logger
  27. * var log = logging.getLogger("some-category");
  28. * log.setLevel(logging.levels.TRACE); //set the Level
  29. *
  30. * ...
  31. *
  32. * //call the log
  33. * log.trace("trace me" );
  34. * </pre>
  35. *
  36. * NOTE: the authors below are the original browser-based log4js authors
  37. * don't try to contact them about bugs in this version :)
  38. * @version 1.0
  39. * @author Stephan Strittmatter - http://jroller.com/page/stritti
  40. * @author Seth Chisamore - http://www.chisamore.com
  41. * @since 2005-05-20
  42. * @static
  43. * Website: http://log4js.berlios.de
  44. */
  45. var events = require('events')
  46. , fs = require('fs')
  47. , path = require('path')
  48. , util = require('util')
  49. , layouts = require('./layouts')
  50. , levels = require('./levels')
  51. , LoggingEvent = require('./logger').LoggingEvent
  52. , Logger = require('./logger').Logger
  53. , ALL_CATEGORIES = '[all]'
  54. , appenders = {}
  55. , loggers = {}
  56. , appenderMakers = {}
  57. , defaultConfig = {
  58. appenders: [
  59. { type: "console" }
  60. ],
  61. replaceConsole: false
  62. };
  63. /**
  64. * Get a logger instance. Instance is cached on categoryName level.
  65. * @param {String} categoryName name of category to log to.
  66. * @return {Logger} instance of logger for the category
  67. * @static
  68. */
  69. function getLogger (categoryName) {
  70. // Use default logger if categoryName is not specified or invalid
  71. if (typeof categoryName !== "string") {
  72. categoryName = Logger.DEFAULT_CATEGORY;
  73. }
  74. var appenderList;
  75. if (!loggers[categoryName]) {
  76. // Create the logger for this name if it doesn't already exist
  77. loggers[categoryName] = new Logger(categoryName);
  78. if (appenders[categoryName]) {
  79. appenderList = appenders[categoryName];
  80. appenderList.forEach(function(appender) {
  81. loggers[categoryName].addListener("log", appender);
  82. });
  83. }
  84. if (appenders[ALL_CATEGORIES]) {
  85. appenderList = appenders[ALL_CATEGORIES];
  86. appenderList.forEach(function(appender) {
  87. loggers[categoryName].addListener("log", appender);
  88. });
  89. }
  90. }
  91. return loggers[categoryName];
  92. }
  93. /**
  94. * args are appender, then zero or more categories
  95. */
  96. function addAppender () {
  97. var args = Array.prototype.slice.call(arguments);
  98. var appender = args.shift();
  99. if (args.length === 0 || args[0] === undefined) {
  100. args = [ ALL_CATEGORIES ];
  101. }
  102. //argument may already be an array
  103. if (Array.isArray(args[0])) {
  104. args = args[0];
  105. }
  106. args.forEach(function(category) {
  107. addAppenderToCategory(appender, category);
  108. if (category === ALL_CATEGORIES) {
  109. addAppenderToAllLoggers(appender);
  110. } else if (loggers[category]) {
  111. loggers[category].addListener("log", appender);
  112. }
  113. });
  114. }
  115. function addAppenderToAllLoggers(appender) {
  116. for (var logger in loggers) {
  117. if (loggers.hasOwnProperty(logger)) {
  118. loggers[logger].addListener("log", appender);
  119. }
  120. }
  121. }
  122. function addAppenderToCategory(appender, category) {
  123. if (!appenders[category]) {
  124. appenders[category] = [];
  125. }
  126. appenders[category].push(appender);
  127. }
  128. function clearAppenders () {
  129. appenders = {};
  130. for (var logger in loggers) {
  131. if (loggers.hasOwnProperty(logger)) {
  132. loggers[logger].removeAllListeners("log");
  133. }
  134. }
  135. }
  136. function configureAppenders(appenderList, options) {
  137. clearAppenders();
  138. if (appenderList) {
  139. appenderList.forEach(function(appenderConfig) {
  140. loadAppender(appenderConfig.type);
  141. var appender;
  142. appenderConfig.makers = appenderMakers;
  143. try {
  144. appender = appenderMakers[appenderConfig.type](appenderConfig, options);
  145. addAppender(appender, appenderConfig.category);
  146. } catch(e) {
  147. throw new Error("log4js configuration problem for " + util.inspect(appenderConfig), e);
  148. }
  149. });
  150. }
  151. }
  152. function configureLevels(levels) {
  153. if (levels) {
  154. for (var category in levels) {
  155. if (levels.hasOwnProperty(category)) {
  156. getLogger(category).setLevel(levels[category]);
  157. }
  158. }
  159. }
  160. }
  161. function setGlobalLogLevel(level) {
  162. Logger.prototype.level = levels.toLevel(level, levels.TRACE);
  163. }
  164. /**
  165. * Get the default logger instance.
  166. * @return {Logger} instance of default logger
  167. * @static
  168. */
  169. function getDefaultLogger () {
  170. return getLogger(Logger.DEFAULT_CATEGORY);
  171. }
  172. var configState = {};
  173. function loadConfigurationFile(filename) {
  174. if (filename) {
  175. return JSON.parse(fs.readFileSync(filename, "utf8"));
  176. }
  177. return undefined;
  178. }
  179. function configureOnceOff(config, options) {
  180. if (config) {
  181. try {
  182. configureAppenders(config.appenders, options);
  183. configureLevels(config.levels);
  184. if (config.replaceConsole) {
  185. replaceConsole();
  186. } else {
  187. restoreConsole();
  188. }
  189. } catch (e) {
  190. throw new Error(
  191. "Problem reading log4js config " + util.inspect(config) +
  192. ". Error was \"" + e.message + "\" (" + e.stack + ")"
  193. );
  194. }
  195. }
  196. }
  197. function reloadConfiguration() {
  198. var mtime = getMTime(configState.filename);
  199. if (!mtime) return;
  200. if (configState.lastMTime && (mtime.getTime() > configState.lastMTime.getTime())) {
  201. configureOnceOff(loadConfigurationFile(configState.filename));
  202. }
  203. configState.lastMTime = mtime;
  204. }
  205. function getMTime(filename) {
  206. var mtime;
  207. try {
  208. mtime = fs.statSync(configState.filename).mtime;
  209. } catch (e) {
  210. getLogger('log4js').warn('Failed to load configuration file ' + filename);
  211. }
  212. return mtime;
  213. }
  214. function initReloadConfiguration(filename, options) {
  215. if (configState.timerId) {
  216. clearInterval(configState.timerId);
  217. delete configState.timerId;
  218. }
  219. configState.filename = filename;
  220. configState.lastMTime = getMTime(filename);
  221. configState.timerId = setInterval(reloadConfiguration, options.reloadSecs*1000);
  222. }
  223. function configure(configurationFileOrObject, options) {
  224. var config = configurationFileOrObject;
  225. config = config || process.env.LOG4JS_CONFIG;
  226. options = options || {};
  227. if (config === undefined || config === null || typeof(config) === 'string') {
  228. if (options.reloadSecs) {
  229. initReloadConfiguration(config, options);
  230. }
  231. config = loadConfigurationFile(config) || defaultConfig;
  232. } else {
  233. if (options.reloadSecs) {
  234. getLogger('log4js').warn(
  235. 'Ignoring configuration reload parameter for "object" configuration.'
  236. );
  237. }
  238. }
  239. configureOnceOff(config, options);
  240. }
  241. var originalConsoleFunctions = {
  242. log: console.log,
  243. debug: console.debug,
  244. info: console.info,
  245. warn: console.warn,
  246. error: console.error
  247. };
  248. function replaceConsole(logger) {
  249. function replaceWith(fn) {
  250. return function() {
  251. fn.apply(logger, arguments);
  252. };
  253. }
  254. logger = logger || getLogger("console");
  255. ['log','debug','info','warn','error'].forEach(function (item) {
  256. console[item] = replaceWith(item === 'log' ? logger.info : logger[item]);
  257. });
  258. }
  259. function restoreConsole() {
  260. ['log', 'debug', 'info', 'warn', 'error'].forEach(function (item) {
  261. console[item] = originalConsoleFunctions[item];
  262. });
  263. }
  264. function loadAppender(appender) {
  265. var appenderModule;
  266. try {
  267. appenderModule = require('./appenders/' + appender);
  268. } catch (e) {
  269. appenderModule = require(appender);
  270. }
  271. module.exports.appenders[appender] = appenderModule.appender.bind(appenderModule);
  272. appenderMakers[appender] = appenderModule.configure.bind(appenderModule);
  273. }
  274. module.exports = {
  275. getLogger: getLogger,
  276. getDefaultLogger: getDefaultLogger,
  277. addAppender: addAppender,
  278. loadAppender: loadAppender,
  279. clearAppenders: clearAppenders,
  280. configure: configure,
  281. replaceConsole: replaceConsole,
  282. restoreConsole: restoreConsole,
  283. levels: levels,
  284. setGlobalLogLevel: setGlobalLogLevel,
  285. layouts: layouts,
  286. appenders: {},
  287. appenderMakers: appenderMakers,
  288. connectLogger: require('./connect-logger').connectLogger
  289. };
  290. //set ourselves up
  291. configure();