coverage.out 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994
  1. Could not delete date-file-test.log { [Error: ENOENT, unlink '/Users/garethjones/log4js-node/.bob/instrumented/test/date-file-test.log']
  2. errno: 34,
  3. code: 'ENOENT',
  4. path: '/Users/garethjones/log4js-node/.bob/instrumented/test/date-file-test.log' }
  5. levels.js:
  6. [ hits: 28, misses: 0, sloc: 28, coverage: 100.00% ]
  7. 82 | "use strict";
  8. |
  9. 82 | function Level(level, levelStr) {
  10. 656 | this.level = level;
  11. 656 | this.levelStr = levelStr;
  12. | }
  13. |
  14. | /**
  15. | * converts given String to corresponding Level
  16. | * @param {String} sArg String value of Level OR Log4js.Level
  17. | * @param {Log4js.Level} defaultLevel default Level, if no String representation
  18. | * @return Level object
  19. | * @type Log4js.Level
  20. | */
  21. 82 | function toLevel(sArg, defaultLevel) {
  22. |
  23. 1726 | if (!sArg) {
  24. 16 | return defaultLevel;
  25. | }
  26. |
  27. 1710 | if (typeof sArg == "string") {
  28. 1636 | var s = sArg.toUpperCase();
  29. 1636 | if (module.exports[s]) {
  30. 1632 | return module.exports[s];
  31. | } else {
  32. 4 | return defaultLevel;
  33. | }
  34. | }
  35. |
  36. 74 | return toLevel(sArg.toString());
  37. | }
  38. |
  39. 82 | Level.prototype.toString = function() {
  40. 556 | return this.levelStr;
  41. | };
  42. |
  43. 82 | Level.prototype.isLessThanOrEqualTo = function(otherLevel) {
  44. 1086 | if (typeof otherLevel === "string") {
  45. 151 | otherLevel = toLevel(otherLevel);
  46. | }
  47. 1086 | return this.level <= otherLevel.level;
  48. | };
  49. |
  50. 82 | Level.prototype.isGreaterThanOrEqualTo = function(otherLevel) {
  51. 103 | if (typeof otherLevel === "string") {
  52. 7 | otherLevel = toLevel(otherLevel);
  53. | }
  54. 103 | return this.level >= otherLevel.level;
  55. | };
  56. |
  57. 82 | Level.prototype.isEqualTo = function(otherLevel) {
  58. 78 | if (typeof otherLevel == "string") {
  59. 3 | otherLevel = toLevel(otherLevel);
  60. | }
  61. 78 | return this.level === otherLevel.level;
  62. | };
  63. |
  64. 82 | module.exports = {
  65. | ALL: new Level(Number.MIN_VALUE, "ALL"),
  66. | TRACE: new Level(5000, "TRACE"),
  67. | DEBUG: new Level(10000, "DEBUG"),
  68. | INFO: new Level(20000, "INFO"),
  69. | WARN: new Level(30000, "WARN"),
  70. | ERROR: new Level(40000, "ERROR"),
  71. | FATAL: new Level(50000, "FATAL"),
  72. | OFF: new Level(Number.MAX_VALUE, "OFF"),
  73. | toLevel: toLevel
  74. | };
  75. layouts.js:
  76. [ hits: 115, misses: 0, sloc: 115, coverage: 100.00% ]
  77. 45 | "use strict";
  78. 45 | var dateFormat = require('./date_format')
  79. | , os = require('os')
  80. | , eol = os.EOL || '\n'
  81. | , util = require('util')
  82. | , replacementRegExp = /%[sdj]/g
  83. | , layoutMakers = {
  84. 7 | "messagePassThrough": function() { return messagePassThroughLayout; },
  85. 1 | "basic": function() { return basicLayout; },
  86. 1 | "colored": function() { return colouredLayout; },
  87. 1 | "coloured": function() { return colouredLayout; },
  88. | "pattern": function (config) {
  89. 1 | return patternLayout(config && config.pattern, config && config.tokens);
  90. | }
  91. | }
  92. | , colours = {
  93. | ALL: "grey",
  94. | TRACE: "blue",
  95. | DEBUG: "cyan",
  96. | INFO: "green",
  97. | WARN: "yellow",
  98. | ERROR: "red",
  99. | FATAL: "magenta",
  100. | OFF: "grey"
  101. | };
  102. |
  103. 45 | function wrapErrorsWithInspect(items) {
  104. 81 | return items.map(function(item) {
  105. 155 | if ((item instanceof Error) && item.stack) {
  106. 6 | return { inspect: function() { return util.format(item) + '\n' + item.stack; } };
  107. | } else {
  108. 152 | return item;
  109. | }
  110. | });
  111. | }
  112. |
  113. 45 | function formatLogData(logData) {
  114. 81 | var data = Array.isArray(logData) ? logData : Array.prototype.slice.call(arguments);
  115. 81 | return util.format.apply(util, wrapErrorsWithInspect(data));
  116. | }
  117. |
  118. 45 | var styles = {
  119. | //styles
  120. | 'bold' : [1, 22],
  121. | 'italic' : [3, 23],
  122. | 'underline' : [4, 24],
  123. | 'inverse' : [7, 27],
  124. | //grayscale
  125. | 'white' : [37, 39],
  126. | 'grey' : [90, 39],
  127. | 'black' : [90, 39],
  128. | //colors
  129. | 'blue' : [34, 39],
  130. | 'cyan' : [36, 39],
  131. | 'green' : [32, 39],
  132. | 'magenta' : [35, 39],
  133. | 'red' : [31, 39],
  134. | 'yellow' : [33, 39]
  135. | };
  136. |
  137. 45 | function colorizeStart(style) {
  138. 24 | return style ? '\x1B[' + styles[style][0] + 'm' : '';
  139. | }
  140. 45 | function colorizeEnd(style) {
  141. 24 | return style ? '\x1B[' + styles[style][1] + 'm' : '';
  142. | }
  143. | /**
  144. | * Taken from masylum's fork (https://github.com/masylum/log4js-node)
  145. | */
  146. 45 | function colorize (str, style) {
  147. 23 | return colorizeStart(style) + str + colorizeEnd(style);
  148. | }
  149. |
  150. 45 | function timestampLevelAndCategory(loggingEvent, colour) {
  151. 23 | var output = colorize(
  152. | formatLogData(
  153. | '[%s] [%s] %s - '
  154. | , dateFormat.asString(loggingEvent.startTime)
  155. | , loggingEvent.level
  156. | , loggingEvent.categoryName
  157. | )
  158. | , colour
  159. | );
  160. 23 | return output;
  161. | }
  162. |
  163. | /**
  164. | * BasicLayout is a simple layout for storing the logs. The logs are stored
  165. | * in following format:
  166. | * <pre>
  167. | * [startTime] [logLevel] categoryName - message\n
  168. | * </pre>
  169. | *
  170. | * @author Stephan Strittmatter
  171. | */
  172. 45 | function basicLayout (loggingEvent) {
  173. 21 | return timestampLevelAndCategory(loggingEvent) + formatLogData(loggingEvent.data);
  174. | }
  175. |
  176. | /**
  177. | * colouredLayout - taken from masylum's fork.
  178. | * same as basicLayout, but with colours.
  179. | */
  180. 45 | function colouredLayout (loggingEvent) {
  181. 2 | return timestampLevelAndCategory(
  182. | loggingEvent,
  183. | colours[loggingEvent.level.toString()]
  184. | ) + formatLogData(loggingEvent.data);
  185. | }
  186. |
  187. 45 | function messagePassThroughLayout (loggingEvent) {
  188. 27 | return formatLogData(loggingEvent.data);
  189. | }
  190. |
  191. | /**
  192. | * PatternLayout
  193. | * Format for specifiers is %[padding].[truncation][field]{[format]}
  194. | * e.g. %5.10p - left pad the log level by 5 characters, up to a max of 10
  195. | * Fields can be any of:
  196. | * - %r time in toLocaleTimeString format
  197. | * - %p log level
  198. | * - %c log category
  199. | * - %m log data
  200. | * - %d date in various formats
  201. | * - %% %
  202. | * - %n newline
  203. | * - %x{<tokenname>} add dynamic tokens to your log. Tokens are specified in the tokens parameter
  204. | * You can use %[ and %] to define a colored block.
  205. | *
  206. | * Tokens are specified as simple key:value objects.
  207. | * The key represents the token name whereas the value can be a string or function
  208. | * which is called to extract the value to put in the log message. If token is not
  209. | * found, it doesn't replace the field.
  210. | *
  211. | * A sample token would be: { "pid" : function() { return process.pid; } }
  212. | *
  213. | * Takes a pattern string, array of tokens and returns a layout function.
  214. | * @param {String} Log format pattern String
  215. | * @param {object} map object of different tokens
  216. | * @return {Function}
  217. | * @author Stephan Strittmatter
  218. | * @author Jan Schmidle
  219. | */
  220. 45 | function patternLayout (pattern, tokens) {
  221. 42 | var TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";
  222. 42 | var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([\[\]cdmnprx%])(\{([^\}]+)\})?|([^%]+)/;
  223. |
  224. 42 | pattern = pattern || TTCC_CONVERSION_PATTERN;
  225. |
  226. 42 | function categoryName(loggingEvent, specifier) {
  227. 9 | var loggerName = loggingEvent.categoryName;
  228. 9 | if (specifier) {
  229. 7 | var precision = parseInt(specifier, 10);
  230. 7 | var loggerNameBits = loggerName.split(".");
  231. 7 | if (precision < loggerNameBits.length) {
  232. 4 | loggerName = loggerNameBits.slice(loggerNameBits.length - precision).join(".");
  233. | }
  234. | }
  235. 9 | return loggerName;
  236. | }
  237. |
  238. 42 | function formatAsDate(loggingEvent, specifier) {
  239. 7 | var format = dateFormat.ISO8601_FORMAT;
  240. 7 | if (specifier) {
  241. 6 | format = specifier;
  242. | // Pick up special cases
  243. 6 | if (format == "ISO8601") {
  244. 1 | format = dateFormat.ISO8601_FORMAT;
  245. 5 | } else if (format == "ABSOLUTE") {
  246. 2 | format = dateFormat.ABSOLUTETIME_FORMAT;
  247. 3 | } else if (format == "DATE") {
  248. 1 | format = dateFormat.DATETIME_FORMAT;
  249. | }
  250. | }
  251. | // Format the date
  252. 7 | return dateFormat.asString(format, loggingEvent.startTime);
  253. | }
  254. |
  255. 42 | function formatMessage(loggingEvent) {
  256. 8 | return formatLogData(loggingEvent.data);
  257. | }
  258. |
  259. 42 | function endOfLine() {
  260. 4 | return eol;
  261. | }
  262. |
  263. 42 | function logLevel(loggingEvent) {
  264. 11 | return loggingEvent.level.toString();
  265. | }
  266. |
  267. 42 | function startTime(loggingEvent) {
  268. 3 | return "" + loggingEvent.startTime.toLocaleTimeString();
  269. | }
  270. |
  271. 42 | function startColour(loggingEvent) {
  272. 1 | return colorizeStart(colours[loggingEvent.level.toString()]);
  273. | }
  274. |
  275. 42 | function endColour(loggingEvent) {
  276. 1 | return colorizeEnd(colours[loggingEvent.level.toString()]);
  277. | }
  278. |
  279. 42 | function percent() {
  280. 1 | return '%';
  281. | }
  282. |
  283. 42 | function userDefined(loggingEvent, specifier) {
  284. 5 | if (typeof(tokens[specifier]) !== 'undefined') {
  285. 3 | if (typeof(tokens[specifier]) === 'function') {
  286. 2 | return tokens[specifier](loggingEvent);
  287. | } else {
  288. 1 | return tokens[specifier];
  289. | }
  290. | }
  291. 2 | return null;
  292. | }
  293. |
  294. 42 | var replacers = {
  295. | 'c': categoryName,
  296. | 'd': formatAsDate,
  297. | 'm': formatMessage,
  298. | 'n': endOfLine,
  299. | 'p': logLevel,
  300. | 'r': startTime,
  301. | '[': startColour,
  302. | ']': endColour,
  303. | '%': percent,
  304. | 'x': userDefined
  305. | };
  306. |
  307. 42 | function replaceToken(conversionCharacter, loggingEvent, specifier) {
  308. 50 | return replacers[conversionCharacter](loggingEvent, specifier);
  309. | }
  310. |
  311. 42 | function truncate(truncation, toTruncate) {
  312. 50 | var len;
  313. 50 | if (truncation) {
  314. 5 | len = parseInt(truncation.substr(1), 10);
  315. 5 | return toTruncate.substring(0, len);
  316. | }
  317. |
  318. 45 | return toTruncate;
  319. | }
  320. |
  321. 42 | function pad(padding, toPad) {
  322. 50 | var len;
  323. 50 | if (padding) {
  324. 8 | if (padding.charAt(0) == "-") {
  325. 4 | len = parseInt(padding.substr(1), 10);
  326. | // Right pad with spaces
  327. 4 | while (toPad.length < len) {
  328. 9 | toPad += " ";
  329. | }
  330. | } else {
  331. 4 | len = parseInt(padding, 10);
  332. | // Left pad with spaces
  333. 4 | while (toPad.length < len) {
  334. 9 | toPad = " " + toPad;
  335. | }
  336. | }
  337. | }
  338. 50 | return toPad;
  339. | }
  340. |
  341. 42 | return function(loggingEvent) {
  342. 41 | var formattedString = "";
  343. 41 | var result;
  344. 41 | var searchString = pattern;
  345. |
  346. 41 | while ((result = regex.exec(searchString))) {
  347. 58 | var matchedString = result[0];
  348. 58 | var padding = result[1];
  349. 58 | var truncation = result[2];
  350. 58 | var conversionCharacter = result[3];
  351. 58 | var specifier = result[5];
  352. 58 | var text = result[6];
  353. |
  354. | // Check if the pattern matched was just normal text
  355. 58 | if (text) {
  356. 8 | formattedString += "" + text;
  357. | } else {
  358. | // Create a raw replacement string based on the conversion
  359. | // character and specifier
  360. 50 | var replacement =
  361. | replaceToken(conversionCharacter, loggingEvent, specifier) ||
  362. | matchedString;
  363. |
  364. | // Format the replacement according to any padding or
  365. | // truncation specified
  366. 50 | replacement = truncate(truncation, replacement);
  367. 50 | replacement = pad(padding, replacement);
  368. 50 | formattedString += replacement;
  369. | }
  370. 58 | searchString = searchString.substr(result.index + result[0].length);
  371. | }
  372. 41 | return formattedString;
  373. | };
  374. |
  375. | }
  376. |
  377. 45 | module.exports = {
  378. | basicLayout: basicLayout,
  379. | messagePassThroughLayout: messagePassThroughLayout,
  380. | patternLayout: patternLayout,
  381. | colouredLayout: colouredLayout,
  382. | coloredLayout: colouredLayout,
  383. | layout: function(name, config) {
  384. 11 | return layoutMakers[name] && layoutMakers[name](config);
  385. | }
  386. | };
  387. date_format.js:
  388. [ hits: 38, misses: 0, sloc: 38, coverage: 100.00% ]
  389. 45 | "use strict";
  390. 45 | exports.ISO8601_FORMAT = "yyyy-MM-dd hh:mm:ss.SSS";
  391. 45 | exports.ISO8601_WITH_TZ_OFFSET_FORMAT = "yyyy-MM-ddThh:mm:ssO";
  392. 45 | exports.DATETIME_FORMAT = "dd MM yyyy hh:mm:ss.SSS";
  393. 45 | exports.ABSOLUTETIME_FORMAT = "hh:mm:ss.SSS";
  394. |
  395. 45 | function padWithZeros(vNumber, width) {
  396. 456 | var numAsString = vNumber + "";
  397. 456 | while (numAsString.length < width) {
  398. 184 | numAsString = "0" + numAsString;
  399. | }
  400. 456 | return numAsString;
  401. | }
  402. |
  403. 45 | function addZero(vNumber) {
  404. 399 | return padWithZeros(vNumber, 2);
  405. | }
  406. |
  407. | /**
  408. | * Formats the TimeOffest
  409. | * Thanks to http://www.svendtofte.com/code/date_format/
  410. | * @private
  411. | */
  412. 45 | function offset(date) {
  413. | // Difference to Greenwich time (GMT) in hours
  414. 57 | var os = Math.abs(date.getTimezoneOffset());
  415. 57 | var h = String(Math.floor(os/60));
  416. 57 | var m = String(os%60);
  417. 57 | if (h.length == 1) {
  418. 2 | h = "0" + h;
  419. | }
  420. 57 | if (m.length == 1) {
  421. 57 | m = "0" + m;
  422. | }
  423. 57 | return date.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m;
  424. | }
  425. |
  426. 45 | exports.asString = function(/*format,*/ date) {
  427. 57 | var format = exports.ISO8601_FORMAT;
  428. 57 | if (typeof(date) === "string") {
  429. 33 | format = arguments[0];
  430. 33 | date = arguments[1];
  431. | }
  432. |
  433. 57 | var vDay = addZero(date.getDate());
  434. 57 | var vMonth = addZero(date.getMonth()+1);
  435. 57 | var vYearLong = addZero(date.getFullYear());
  436. 57 | var vYearShort = addZero(date.getFullYear().toString().substring(3,4));
  437. 57 | var vYear = (format.indexOf("yyyy") > -1 ? vYearLong : vYearShort);
  438. 57 | var vHour = addZero(date.getHours());
  439. 57 | var vMinute = addZero(date.getMinutes());
  440. 57 | var vSecond = addZero(date.getSeconds());
  441. 57 | var vMillisecond = padWithZeros(date.getMilliseconds(), 3);
  442. 57 | var vTimeZone = offset(date);
  443. 57 | var formatted = format
  444. | .replace(/dd/g, vDay)
  445. | .replace(/MM/g, vMonth)
  446. | .replace(/y{1,4}/g, vYear)
  447. | .replace(/hh/g, vHour)
  448. | .replace(/mm/g, vMinute)
  449. | .replace(/ss/g, vSecond)
  450. | .replace(/SSS/g, vMillisecond)
  451. | .replace(/O/g, vTimeZone);
  452. 57 | return formatted;
  453. |
  454. | };
  455. log4js.js:
  456. [ hits: 127, misses: 0, sloc: 127, coverage: 100.00% ]
  457. 24 | "use strict";
  458. | /*
  459. | * Licensed under the Apache License, Version 2.0 (the "License");
  460. | * you may not use this file except in compliance with the License.
  461. | * You may obtain a copy of the License at
  462. | *
  463. | * http://www.apache.org/licenses/LICENSE-2.0
  464. | *
  465. | * Unless required by applicable law or agreed to in writing, software
  466. | * distributed under the License is distributed on an "AS IS" BASIS,
  467. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  468. | * See the License for the specific language governing permissions and
  469. | * limitations under the License.
  470. | */
  471. |
  472. | /**
  473. | * @fileoverview log4js is a library to log in JavaScript in similar manner
  474. | * than in log4j for Java. The API should be nearly the same.
  475. | *
  476. | * <h3>Example:</h3>
  477. | * <pre>
  478. | * var logging = require('log4js');
  479. | * //add an appender that logs all messages to stdout.
  480. | * logging.addAppender(logging.consoleAppender());
  481. | * //add an appender that logs "some-category" to a file
  482. | * logging.addAppender(logging.fileAppender("file.log"), "some-category");
  483. | * //get a logger
  484. | * var log = logging.getLogger("some-category");
  485. | * log.setLevel(logging.levels.TRACE); //set the Level
  486. | *
  487. | * ...
  488. | *
  489. | * //call the log
  490. | * log.trace("trace me" );
  491. | * </pre>
  492. | *
  493. | * NOTE: the authors below are the original browser-based log4js authors
  494. | * don't try to contact them about bugs in this version :)
  495. | * @version 1.0
  496. | * @author Stephan Strittmatter - http://jroller.com/page/stritti
  497. | * @author Seth Chisamore - http://www.chisamore.com
  498. | * @since 2005-05-20
  499. | * @static
  500. | * Website: http://log4js.berlios.de
  501. | */
  502. 24 | var events = require('events')
  503. | , fs = require('fs')
  504. | , path = require('path')
  505. | , util = require('util')
  506. | , layouts = require('./layouts')
  507. | , levels = require('./levels')
  508. | , LoggingEvent = require('./logger').LoggingEvent
  509. | , Logger = require('./logger').Logger
  510. | , ALL_CATEGORIES = '[all]'
  511. | , appenders = {}
  512. | , loggers = {}
  513. | , appenderMakers = {}
  514. | , defaultConfig = {
  515. | appenders: [
  516. | { type: "console" }
  517. | ],
  518. | replaceConsole: false
  519. | };
  520. |
  521. | /**
  522. | * Get a logger instance. Instance is cached on categoryName level.
  523. | * @param {String} categoryName name of category to log to.
  524. | * @return {Logger} instance of logger for the category
  525. | * @static
  526. | */
  527. 24 | function getLogger (categoryName) {
  528. |
  529. | // Use default logger if categoryName is not specified or invalid
  530. 445 | if (typeof categoryName !== "string") {
  531. 1 | categoryName = Logger.DEFAULT_CATEGORY;
  532. | }
  533. |
  534. 445 | var appenderList;
  535. 445 | if (!loggers[categoryName]) {
  536. | // Create the logger for this name if it doesn't already exist
  537. 39 | loggers[categoryName] = new Logger(categoryName);
  538. 39 | if (appenders[categoryName]) {
  539. 12 | appenderList = appenders[categoryName];
  540. 12 | appenderList.forEach(function(appender) {
  541. 12 | loggers[categoryName].addListener("log", appender);
  542. | });
  543. | }
  544. 39 | if (appenders[ALL_CATEGORIES]) {
  545. 23 | appenderList = appenders[ALL_CATEGORIES];
  546. 23 | appenderList.forEach(function(appender) {
  547. 33 | loggers[categoryName].addListener("log", appender);
  548. | });
  549. | }
  550. | }
  551. |
  552. 445 | return loggers[categoryName];
  553. | }
  554. |
  555. | /**
  556. | * args are appender, then zero or more categories
  557. | */
  558. 24 | function addAppender () {
  559. 78 | var args = Array.prototype.slice.call(arguments);
  560. 78 | var appender = args.shift();
  561. 78 | if (args.length === 0 || args[0] === undefined) {
  562. 46 | args = [ ALL_CATEGORIES ];
  563. | }
  564. | //argument may already be an array
  565. 78 | if (Array.isArray(args[0])) {
  566. 1 | args = args[0];
  567. | }
  568. |
  569. 78 | args.forEach(function(category) {
  570. 80 | addAppenderToCategory(appender, category);
  571. |
  572. 80 | if (category === ALL_CATEGORIES) {
  573. 46 | addAppenderToAllLoggers(appender);
  574. 34 | } else if (loggers[category]) {
  575. 22 | loggers[category].addListener("log", appender);
  576. | }
  577. | });
  578. | }
  579. |
  580. 24 | function addAppenderToAllLoggers(appender) {
  581. 46 | for (var logger in loggers) {
  582. 58 | if (loggers.hasOwnProperty(logger)) {
  583. 58 | loggers[logger].addListener("log", appender);
  584. | }
  585. | }
  586. | }
  587. |
  588. 24 | function addAppenderToCategory(appender, category) {
  589. 80 | if (!appenders[category]) {
  590. 66 | appenders[category] = [];
  591. | }
  592. 80 | appenders[category].push(appender);
  593. | }
  594. |
  595. 24 | function clearAppenders () {
  596. 71 | appenders = {};
  597. 71 | for (var logger in loggers) {
  598. 202 | if (loggers.hasOwnProperty(logger)) {
  599. 202 | loggers[logger].removeAllListeners("log");
  600. | }
  601. | }
  602. | }
  603. |
  604. 24 | function configureAppenders(appenderList, options) {
  605. 50 | clearAppenders();
  606. 50 | if (appenderList) {
  607. 39 | appenderList.forEach(function(appenderConfig) {
  608. 40 | loadAppender(appenderConfig.type);
  609. 40 | var appender;
  610. 40 | appenderConfig.makers = appenderMakers;
  611. 40 | try {
  612. 40 | appender = appenderMakers[appenderConfig.type](appenderConfig, options);
  613. 39 | addAppender(appender, appenderConfig.category);
  614. | } catch(e) {
  615. 1 | throw new Error("log4js configuration problem for " + util.inspect(appenderConfig), e);
  616. | }
  617. | });
  618. | }
  619. | }
  620. |
  621. 24 | function configureLevels(levels) {
  622. 49 | if (levels) {
  623. 11 | for (var category in levels) {
  624. 10 | if (levels.hasOwnProperty(category)) {
  625. 10 | getLogger(category).setLevel(levels[category]);
  626. | }
  627. | }
  628. | }
  629. | }
  630. |
  631. 24 | function setGlobalLogLevel(level) {
  632. 2 | Logger.prototype.level = levels.toLevel(level, levels.TRACE);
  633. | }
  634. |
  635. | /**
  636. | * Get the default logger instance.
  637. | * @return {Logger} instance of default logger
  638. | * @static
  639. | */
  640. 24 | function getDefaultLogger () {
  641. 1 | return getLogger(Logger.DEFAULT_CATEGORY);
  642. | }
  643. |
  644. 24 | var configState = {};
  645. |
  646. 24 | function loadConfigurationFile(filename) {
  647. 36 | if (filename) {
  648. 11 | return JSON.parse(fs.readFileSync(filename, "utf8"));
  649. | }
  650. 25 | return undefined;
  651. | }
  652. |
  653. 24 | function configureOnceOff(config, options) {
  654. 50 | if (config) {
  655. 50 | try {
  656. 50 | configureAppenders(config.appenders, options);
  657. 49 | configureLevels(config.levels);
  658. |
  659. 49 | if (config.replaceConsole) {
  660. 1 | replaceConsole();
  661. | } else {
  662. 48 | restoreConsole();
  663. | }
  664. | } catch (e) {
  665. 1 | throw new Error(
  666. | "Problem reading log4js config " + util.inspect(config) +
  667. | ". Error was \"" + e.message + "\" (" + e.stack + ")"
  668. | );
  669. | }
  670. | }
  671. | }
  672. |
  673. 24 | function reloadConfiguration() {
  674. 3 | var mtime = getMTime(configState.filename);
  675. 4 | if (!mtime) return;
  676. |
  677. 2 | if (configState.lastMTime && (mtime.getTime() > configState.lastMTime.getTime())) {
  678. 1 | configureOnceOff(loadConfigurationFile(configState.filename));
  679. | }
  680. 2 | configState.lastMTime = mtime;
  681. | }
  682. |
  683. 24 | function getMTime(filename) {
  684. 8 | var mtime;
  685. 8 | try {
  686. 8 | mtime = fs.statSync(configState.filename).mtime;
  687. | } catch (e) {
  688. 1 | getLogger('log4js').warn('Failed to load configuration file ' + filename);
  689. | }
  690. 8 | return mtime;
  691. | }
  692. |
  693. 24 | function initReloadConfiguration(filename, options) {
  694. 5 | if (configState.timerId) {
  695. 1 | clearInterval(configState.timerId);
  696. 1 | delete configState.timerId;
  697. | }
  698. 5 | configState.filename = filename;
  699. 5 | configState.lastMTime = getMTime(filename);
  700. 5 | configState.timerId = setInterval(reloadConfiguration, options.reloadSecs*1000);
  701. | }
  702. |
  703. 24 | function configure(configurationFileOrObject, options) {
  704. 49 | var config = configurationFileOrObject;
  705. 49 | config = config || process.env.LOG4JS_CONFIG;
  706. 49 | options = options || {};
  707. |
  708. 49 | if (config === undefined || config === null || typeof(config) === 'string') {
  709. 35 | if (options.reloadSecs) {
  710. 5 | initReloadConfiguration(config, options);
  711. | }
  712. 35 | config = loadConfigurationFile(config) || defaultConfig;
  713. | } else {
  714. 14 | if (options.reloadSecs) {
  715. 1 | getLogger('log4js').warn(
  716. | 'Ignoring configuration reload parameter for "object" configuration.'
  717. | );
  718. | }
  719. | }
  720. 49 | configureOnceOff(config, options);
  721. | }
  722. |
  723. 24 | var originalConsoleFunctions = {
  724. | log: console.log,
  725. | debug: console.debug,
  726. | info: console.info,
  727. | warn: console.warn,
  728. | error: console.error
  729. | };
  730. |
  731. 24 | function replaceConsole(logger) {
  732. 3 | function replaceWith(fn) {
  733. 15 | return function() {
  734. 10 | fn.apply(logger, arguments);
  735. | };
  736. | }
  737. 3 | logger = logger || getLogger("console");
  738. 3 | ['log','debug','info','warn','error'].forEach(function (item) {
  739. 15 | console[item] = replaceWith(item === 'log' ? logger.info : logger[item]);
  740. | });
  741. | }
  742. |
  743. 24 | function restoreConsole() {
  744. 50 | ['log', 'debug', 'info', 'warn', 'error'].forEach(function (item) {
  745. 250 | console[item] = originalConsoleFunctions[item];
  746. | });
  747. | }
  748. |
  749. 24 | function loadAppender(appender) {
  750. 43 | var appenderModule;
  751. 43 | try {
  752. 43 | appenderModule = require('./appenders/' + appender);
  753. | } catch (e) {
  754. 1 | appenderModule = require(appender);
  755. | }
  756. 43 | module.exports.appenders[appender] = appenderModule.appender.bind(appenderModule);
  757. 43 | appenderMakers[appender] = appenderModule.configure.bind(appenderModule);
  758. | }
  759. |
  760. 24 | module.exports = {
  761. | getLogger: getLogger,
  762. | getDefaultLogger: getDefaultLogger,
  763. |
  764. | addAppender: addAppender,
  765. | loadAppender: loadAppender,
  766. | clearAppenders: clearAppenders,
  767. | configure: configure,
  768. |
  769. | replaceConsole: replaceConsole,
  770. | restoreConsole: restoreConsole,
  771. |
  772. | levels: levels,
  773. | setGlobalLogLevel: setGlobalLogLevel,
  774. |
  775. | layouts: layouts,
  776. | appenders: {},
  777. | appenderMakers: appenderMakers,
  778. | connectLogger: require('./connect-logger').connectLogger
  779. | };
  780. |
  781. | //set ourselves up
  782. 24 | configure();
  783. |
  784. logger.js:
  785. [ hits: 35, misses: 0, sloc: 35, coverage: 100.00% ]
  786. 41 | "use strict";
  787. 41 | var levels = require('./levels')
  788. | , util = require('util')
  789. | , events = require('events')
  790. | , DEFAULT_CATEGORY = '[default]';
  791. |
  792. | /**
  793. | * Models a logging event.
  794. | * @constructor
  795. | * @param {String} categoryName name of category
  796. | * @param {Log4js.Level} level level of message
  797. | * @param {Array} data objects to log
  798. | * @param {Log4js.Logger} logger the associated logger
  799. | * @author Seth Chisamore
  800. | */
  801. 41 | function LoggingEvent (categoryName, level, data, logger) {
  802. 71 | this.startTime = new Date();
  803. 71 | this.categoryName = categoryName;
  804. 71 | this.data = data;
  805. 71 | this.level = level;
  806. 71 | this.logger = logger;
  807. | }
  808. |
  809. | /**
  810. | * Logger to log messages.
  811. | * use {@see Log4js#getLogger(String)} to get an instance.
  812. | * @constructor
  813. | * @param name name of category to log to
  814. | * @author Stephan Strittmatter
  815. | */
  816. 41 | function Logger (name, level) {
  817. 43 | this.category = name || DEFAULT_CATEGORY;
  818. |
  819. 43 | if (level) {
  820. 2 | this.setLevel(level);
  821. | }
  822. | }
  823. 41 | util.inherits(Logger, events.EventEmitter);
  824. 41 | Logger.DEFAULT_CATEGORY = DEFAULT_CATEGORY;
  825. 41 | Logger.prototype.level = levels.TRACE;
  826. |
  827. 41 | Logger.prototype.setLevel = function(level) {
  828. 213 | this.level = levels.toLevel(level, this.level || levels.TRACE);
  829. | };
  830. |
  831. 41 | Logger.prototype.removeLevel = function() {
  832. 2 | delete this.level;
  833. | };
  834. |
  835. 41 | Logger.prototype.log = function() {
  836. 71 | var args = Array.prototype.slice.call(arguments)
  837. | , logLevel = args.shift()
  838. | , loggingEvent = new LoggingEvent(this.category, logLevel, args, this);
  839. 71 | this.emit("log", loggingEvent);
  840. | };
  841. |
  842. 41 | Logger.prototype.isLevelEnabled = function(otherLevel) {
  843. 554 | return this.level.isLessThanOrEqualTo(otherLevel);
  844. | };
  845. |
  846. 41 | ['Trace','Debug','Info','Warn','Error','Fatal'].forEach(
  847. | function(levelString) {
  848. 246 | var level = levels.toLevel(levelString);
  849. 246 | Logger.prototype['is'+levelString+'Enabled'] = function() {
  850. 6 | return this.isLevelEnabled(level);
  851. | };
  852. |
  853. 246 | Logger.prototype[levelString.toLowerCase()] = function () {
  854. 80 | if (this.isLevelEnabled(level)) {
  855. 71 | var args = Array.prototype.slice.call(arguments);
  856. 71 | args.unshift(level);
  857. 71 | Logger.prototype.log.apply(this, args);
  858. | }
  859. | };
  860. | }
  861. | );
  862. |
  863. |
  864. 41 | exports.LoggingEvent = LoggingEvent;
  865. 41 | exports.Logger = Logger;
  866. connect-logger.js:
  867. [ hits: 53, misses: 0, sloc: 53, coverage: 100.00% ]
  868. 24 | "use strict";
  869. 24 | var levels = require("./levels");
  870. 24 | var DEFAULT_FORMAT = ':remote-addr - -' +
  871. | ' ":method :url HTTP/:http-version"' +
  872. | ' :status :content-length ":referrer"' +
  873. | ' ":user-agent"';
  874. | /**
  875. | * Log requests with the given `options` or a `format` string.
  876. | *
  877. | * Options:
  878. | *
  879. | * - `format` Format string, see below for tokens
  880. | * - `level` A log4js levels instance. Supports also 'auto'
  881. | *
  882. | * Tokens:
  883. | *
  884. | * - `:req[header]` ex: `:req[Accept]`
  885. | * - `:res[header]` ex: `:res[Content-Length]`
  886. | * - `:http-version`
  887. | * - `:response-time`
  888. | * - `:remote-addr`
  889. | * - `:date`
  890. | * - `:method`
  891. | * - `:url`
  892. | * - `:referrer`
  893. | * - `:user-agent`
  894. | * - `:status`
  895. | *
  896. | * @param {String|Function|Object} format or options
  897. | * @return {Function}
  898. | * @api public
  899. | */
  900. |
  901. 24 | function getLogger(logger4js, options) {
  902. 13 | if ('object' == typeof options) {
  903. 6 | options = options || {};
  904. 7 | } else if (options) {
  905. 4 | options = { format: options };
  906. | } else {
  907. 3 | options = {};
  908. | }
  909. |
  910. 13 | var thislogger = logger4js
  911. | , level = levels.toLevel(options.level, levels.INFO)
  912. | , fmt = options.format || DEFAULT_FORMAT
  913. | , nolog = options.nolog ? createNoLogCondition(options.nolog) : null;
  914. |
  915. 13 | return function (req, res, next) {
  916. | // mount safety
  917. 23 | if (req._logging) return next();
  918. |
  919. | // nologs
  920. 30 | if (nolog && nolog.test(req.originalUrl)) return next();
  921. 16 | if (thislogger.isLevelEnabled(level) || options.level === 'auto') {
  922. |
  923. 15 | var start = new Date()
  924. | , statusCode
  925. | , writeHead = res.writeHead
  926. | , end = res.end
  927. | , url = req.originalUrl;
  928. |
  929. | // flag as logging
  930. 15 | req._logging = true;
  931. |
  932. | // proxy for statusCode.
  933. 15 | res.writeHead = function(code, headers){
  934. 11 | res.writeHead = writeHead;
  935. 11 | res.writeHead(code, headers);
  936. 11 | res.__statusCode = statusCode = code;
  937. 11 | res.__headers = headers || {};
  938. |
  939. | //status code response level handling
  940. 11 | if(options.level === 'auto'){
  941. 5 | level = levels.INFO;
  942. 8 | if(code >= 300) level = levels.WARN;
  943. 7 | if(code >= 400) level = levels.ERROR;
  944. | } else {
  945. 6 | level = levels.toLevel(options.level, levels.INFO);
  946. | }
  947. | };
  948. |
  949. | // proxy end to output a line to the provided logger.
  950. 15 | res.end = function(chunk, encoding) {
  951. 15 | res.end = end;
  952. 15 | res.end(chunk, encoding);
  953. 15 | res.responseTime = new Date() - start;
  954. 15 | if (thislogger.isLevelEnabled(level)) {
  955. 15 | if (typeof fmt === 'function') {
  956. 1 | var line = fmt(req, res, function(str){ return format(str, req, res); });
  957. 2 | if (line) thislogger.log(level, line);
  958. | } else {
  959. 14 | thislogger.log(level, format(fmt, req, res));
  960. | }
  961. | }
  962. | };
  963. | }
  964. |
  965. | //ensure next gets always called
  966. 16 | next();
  967. | };
  968. | }
  969. |
  970. | /**
  971. | * Return formatted log line.
  972. | *
  973. | * @param {String} str
  974. | * @param {IncomingMessage} req
  975. | * @param {ServerResponse} res
  976. | * @return {String}
  977. | * @api private
  978. | */
  979. |
  980. 24 | function format(str, req, res) {
  981. 14 | return str
  982. | .replace(':url', req.originalUrl)
  983. | .replace(':method', req.method)
  984. | .replace(':status', res.__statusCode || res.statusCode)
  985. | .replace(':response-time', res.responseTime)
  986. | .replace(':date', new Date().toUTCString())
  987. | .replace(':referrer', req.headers.referer || req.headers.referrer || '')
  988. | .replace(':http-version', req.httpVersionMajor + '.' + req.httpVersionMinor)
  989. | .replace(
  990. | ':remote-addr',
  991. | req.socket &&
  992. | (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress))
  993. | )
  994. | .replace(':user-agent', req.headers['user-agent'] || '')
  995. | .replace(
  996. | ':content-length',
  997. | (res._headers && res._headers['content-length']) ||
  998. | (res.__headers && res.__headers['Content-Length']) ||
  999. | '-'
  1000. | )
  1001. 1 | .replace(/:req\[([^\]]+)\]/g, function(_, field){ return req.headers[field.toLowerCase()]; })
  1002. | .replace(/:res\[([^\]]+)\]/g, function(_, field){
  1003. 1 | return res._headers ?
  1004. | (res._headers[field.toLowerCase()] || res.__headers[field])
  1005. | : (res.__headers && res.__headers[field]);
  1006. | });
  1007. | }
  1008. |
  1009. | /**
  1010. | * Return RegExp Object about nolog
  1011. | *
  1012. | * @param {String} nolog
  1013. | * @return {RegExp}
  1014. | * @api private
  1015. | *
  1016. | * syntax
  1017. | * 1. String
  1018. | * 1.1 "\\.gif"
  1019. | * NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.gif?fuga
  1020. | * LOGGING http://example.com/hoge.agif
  1021. | * 1.2 in "\\.gif|\\.jpg$"
  1022. | * NOT LOGGING http://example.com/hoge.gif and
  1023. | * http://example.com/hoge.gif?fuga and http://example.com/hoge.jpg?fuga
  1024. | * LOGGING http://example.com/hoge.agif,
  1025. | * http://example.com/hoge.ajpg and http://example.com/hoge.jpg?hoge
  1026. | * 1.3 in "\\.(gif|jpe?g|png)$"
  1027. | * NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.jpeg
  1028. | * LOGGING http://example.com/hoge.gif?uid=2 and http://example.com/hoge.jpg?pid=3
  1029. | * 2. RegExp
  1030. | * 2.1 in /\.(gif|jpe?g|png)$/
  1031. | * SAME AS 1.3
  1032. | * 3. Array
  1033. | * 3.1 ["\\.jpg$", "\\.png", "\\.gif"]
  1034. | * SAME AS "\\.jpg|\\.png|\\.gif"
  1035. | */
  1036. 24 | function createNoLogCondition(nolog) {
  1037. 4 | var regexp = null;
  1038. |
  1039. 4 | if (nolog) {
  1040. 4 | if (nolog instanceof RegExp) {
  1041. 1 | regexp = nolog;
  1042. | }
  1043. |
  1044. 4 | if (typeof nolog === 'string') {
  1045. 2 | regexp = new RegExp(nolog);
  1046. | }
  1047. |
  1048. 4 | if (Array.isArray(nolog)) {
  1049. 1 | var regexpsAsStrings = nolog.map(
  1050. | function convertToStrings(o) {
  1051. 2 | return o.source ? o.source : o;
  1052. | }
  1053. | );
  1054. 1 | regexp = new RegExp(regexpsAsStrings.join('|'));
  1055. | }
  1056. | }
  1057. |
  1058. 4 | return regexp;
  1059. | }
  1060. |
  1061. 24 | exports.connectLogger = getLogger;
  1062. appenders/console.js:
  1063. [ hits: 13, misses: 0, sloc: 13, coverage: 100.00% ]
  1064. 19 | "use strict";
  1065. 19 | var layouts = require('../layouts')
  1066. | , consoleLog = console.log.bind(console);
  1067. |
  1068. 19 | function consoleAppender (layout) {
  1069. 21 | layout = layout || layouts.colouredLayout;
  1070. 21 | return function(loggingEvent) {
  1071. 1 | consoleLog(layout(loggingEvent));
  1072. | };
  1073. | }
  1074. |
  1075. 19 | function configure(config) {
  1076. 20 | var layout;
  1077. 20 | if (config.layout) {
  1078. 1 | layout = layouts.layout(config.layout.type, config.layout);
  1079. | }
  1080. 20 | return consoleAppender(layout);
  1081. | }
  1082. |
  1083. 19 | exports.appender = consoleAppender;
  1084. 19 | exports.configure = configure;
  1085. streams/BaseRollingFileStream.js:
  1086. [ hits: 48, misses: 0, sloc: 48, coverage: 100.00% ]
  1087. 4 | "use strict";
  1088. 4 | var fs = require('fs')
  1089. | , stream
  1090. | , debug = require('../debug')('BaseRollingFileStream')
  1091. | , util = require('util')
  1092. | , semver = require('semver');
  1093. |
  1094. 4 | if (semver.satisfies(process.version, '>=0.10.0')) {
  1095. 3 | stream = require('stream');
  1096. | } else {
  1097. 1 | stream = require('readable-stream');
  1098. | }
  1099. |
  1100. 4 | module.exports = BaseRollingFileStream;
  1101. |
  1102. 4 | function BaseRollingFileStream(filename, options) {
  1103. 24 | debug("In BaseRollingFileStream");
  1104. 24 | this.filename = filename;
  1105. 24 | this.options = options || { encoding: 'utf8', mode: parseInt('0644', 8), flags: 'a' };
  1106. 24 | this.currentSize = 0;
  1107. |
  1108. 24 | function currentFileSize(file) {
  1109. 23 | var fileSize = 0;
  1110. 23 | try {
  1111. 23 | fileSize = fs.statSync(file).size;
  1112. | } catch (e) {
  1113. | // file does not exist
  1114. | }
  1115. 23 | return fileSize;
  1116. | }
  1117. |
  1118. 24 | function throwErrorIfArgumentsAreNotValid() {
  1119. 24 | if (!filename) {
  1120. 1 | throw new Error("You must specify a filename");
  1121. | }
  1122. | }
  1123. |
  1124. 24 | throwErrorIfArgumentsAreNotValid();
  1125. 23 | debug("Calling BaseRollingFileStream.super");
  1126. 23 | BaseRollingFileStream.super_.call(this);
  1127. 23 | this.openTheStream();
  1128. 23 | this.currentSize = currentFileSize(this.filename);
  1129. | }
  1130. 4 | util.inherits(BaseRollingFileStream, stream.Writable);
  1131. |
  1132. 4 | BaseRollingFileStream.prototype._write = function(chunk, encoding, callback) {
  1133. 29 | var that = this;
  1134. 29 | function writeTheChunk() {
  1135. 29 | debug("writing the chunk to the underlying stream");
  1136. 29 | that.currentSize += chunk.length;
  1137. 29 | that.theStream.write(chunk, encoding, callback);
  1138. | }
  1139. |
  1140. 29 | debug("in _write");
  1141. |
  1142. 29 | if (this.shouldRoll()) {
  1143. 8 | this.currentSize = 0;
  1144. 8 | this.roll(this.filename, writeTheChunk);
  1145. | } else {
  1146. 21 | writeTheChunk();
  1147. | }
  1148. | };
  1149. |
  1150. 4 | BaseRollingFileStream.prototype.openTheStream = function(cb) {
  1151. 31 | debug("opening the underlying stream");
  1152. 31 | this.theStream = fs.createWriteStream(this.filename, this.options);
  1153. 31 | if (cb) {
  1154. 8 | this.theStream.on("open", cb);
  1155. | }
  1156. | };
  1157. |
  1158. 4 | BaseRollingFileStream.prototype.closeTheStream = function(cb) {
  1159. 8 | debug("closing the underlying stream");
  1160. 8 | this.theStream.end(cb);
  1161. | };
  1162. |
  1163. 4 | BaseRollingFileStream.prototype.shouldRoll = function() {
  1164. 1 | return false; // default behaviour is never to roll
  1165. | };
  1166. |
  1167. 4 | BaseRollingFileStream.prototype.roll = function(filename, callback) {
  1168. 1 | callback(); // default behaviour is not to do anything
  1169. | };
  1170. |
  1171. debug.js:
  1172. [ hits: 8, misses: 0, sloc: 8, coverage: 100.00% ]
  1173. 14 | "use strict";
  1174. |
  1175. 14 | module.exports = function(label) {
  1176. 18 | var debug;
  1177. |
  1178. 18 | if (process.env.NODE_DEBUG && /\blog4js\b/.test(process.env.NODE_DEBUG)) {
  1179. 1 | debug = function(message) {
  1180. 1 | console.error('LOG4JS: (%s) %s', label, message);
  1181. | };
  1182. | } else {
  1183. 17 | debug = function() { };
  1184. | }
  1185. |
  1186. 18 | return debug;
  1187. | };
  1188. streams/index.js:
  1189. [ hits: 2, misses: 0, sloc: 2, coverage: 100.00% ]
  1190. 2 | exports.RollingFileStream = require('./RollingFileStream');
  1191. 2 | exports.DateRollingFileStream = require('./DateRollingFileStream');
  1192. streams/RollingFileStream.js:
  1193. [ hits: 41, misses: 0, sloc: 41, coverage: 100.00% ]
  1194. 2 | "use strict";
  1195. 2 | var BaseRollingFileStream = require('./BaseRollingFileStream')
  1196. | , debug = require('../debug')('RollingFileStream')
  1197. | , util = require('util')
  1198. | , path = require('path')
  1199. | , fs = require('fs')
  1200. | , async = require('async');
  1201. |
  1202. 2 | module.exports = RollingFileStream;
  1203. |
  1204. 2 | function RollingFileStream (filename, size, backups, options) {
  1205. 9 | this.size = size;
  1206. 9 | this.backups = backups || 1;
  1207. |
  1208. 9 | function throwErrorIfArgumentsAreNotValid() {
  1209. 9 | if (!filename || !size || size <= 0) {
  1210. 1 | throw new Error("You must specify a filename and file size");
  1211. | }
  1212. | }
  1213. |
  1214. 9 | throwErrorIfArgumentsAreNotValid();
  1215. |
  1216. 8 | RollingFileStream.super_.call(this, filename, options);
  1217. | }
  1218. 2 | util.inherits(RollingFileStream, BaseRollingFileStream);
  1219. |
  1220. 2 | RollingFileStream.prototype.shouldRoll = function() {
  1221. 22 | debug("should roll with current size %d, and max size %d", this.currentSize, this.size);
  1222. 22 | return this.currentSize >= this.size;
  1223. | };
  1224. |
  1225. 2 | RollingFileStream.prototype.roll = function(filename, callback) {
  1226. 6 | var that = this,
  1227. | nameMatcher = new RegExp('^' + path.basename(filename));
  1228. |
  1229. 6 | function justTheseFiles (item) {
  1230. 276 | return nameMatcher.test(item);
  1231. | }
  1232. |
  1233. 6 | function index(filename_) {
  1234. 109 | return parseInt(filename_.substring((path.basename(filename) + '.').length), 10) || 0;
  1235. | }
  1236. |
  1237. 6 | function byIndex(a, b) {
  1238. 26 | if (index(a) > index(b)) {
  1239. 7 | return 1;
  1240. 19 | } else if (index(a) < index(b) ) {
  1241. 17 | return -1;
  1242. | } else {
  1243. 2 | return 0;
  1244. | }
  1245. | }
  1246. |
  1247. 6 | function increaseFileIndex (fileToRename, cb) {
  1248. 19 | var idx = index(fileToRename);
  1249. 19 | debug('Index of ' + fileToRename + ' is ' + idx);
  1250. 19 | if (idx < that.backups) {
  1251. | //on windows, you can get a EEXIST error if you rename a file to an existing file
  1252. | //so, we'll try to delete the file we're renaming to first
  1253. 15 | fs.unlink(filename + '.' + (idx+1), function (err) {
  1254. | //ignore err: if we could not delete, it's most likely that it doesn't exist
  1255. 15 | debug('Renaming ' + fileToRename + ' -> ' + filename + '.' + (idx+1));
  1256. 15 | fs.rename(path.join(path.dirname(filename), fileToRename), filename + '.' + (idx + 1), cb);
  1257. | });
  1258. | } else {
  1259. 4 | cb();
  1260. | }
  1261. | }
  1262. |
  1263. 6 | function renameTheFiles(cb) {
  1264. | //roll the backups (rename file.n to file.n+1, where n <= numBackups)
  1265. 6 | debug("Renaming the old files");
  1266. 6 | fs.readdir(path.dirname(filename), function (err, files) {
  1267. 6 | async.forEachSeries(
  1268. | files.filter(justTheseFiles).sort(byIndex).reverse(),
  1269. | increaseFileIndex,
  1270. | cb
  1271. | );
  1272. | });
  1273. | }
  1274. |
  1275. 6 | debug("Rolling, rolling, rolling");
  1276. 6 | async.series([
  1277. | this.closeTheStream.bind(this),
  1278. | renameTheFiles,
  1279. | this.openTheStream.bind(this)
  1280. | ], callback);
  1281. |
  1282. | };
  1283. streams/DateRollingFileStream.js:
  1284. [ hits: 44, misses: 0, sloc: 44, coverage: 100.00% ]
  1285. 2 | "use strict";
  1286. 2 | var BaseRollingFileStream = require('./BaseRollingFileStream')
  1287. | , debug = require('../debug')('DateRollingFileStream')
  1288. | , format = require('../date_format')
  1289. | , async = require('async')
  1290. | , fs = require('fs')
  1291. | , util = require('util');
  1292. |
  1293. 2 | module.exports = DateRollingFileStream;
  1294. |
  1295. 2 | function DateRollingFileStream(filename, pattern, options, now) {
  1296. 14 | debug("Now is " + now);
  1297. 14 | if (pattern && typeof(pattern) === 'object') {
  1298. 1 | now = options;
  1299. 1 | options = pattern;
  1300. 1 | pattern = null;
  1301. | }
  1302. 14 | this.pattern = pattern || '.yyyy-MM-dd';
  1303. 14 | this.now = now || Date.now;
  1304. 14 | this.lastTimeWeWroteSomething = format.asString(this.pattern, new Date(this.now()));
  1305. 14 | this.baseFilename = filename;
  1306. 14 | this.alwaysIncludePattern = false;
  1307. |
  1308. 14 | if (options) {
  1309. 11 | if (options.alwaysIncludePattern) {
  1310. 2 | this.alwaysIncludePattern = true;
  1311. 2 | filename = this.baseFilename + this.lastTimeWeWroteSomething;
  1312. | }
  1313. 11 | delete options.alwaysIncludePattern;
  1314. 11 | if (Object.keys(options).length === 0) {
  1315. 9 | options = null;
  1316. | }
  1317. | }
  1318. 14 | debug("this.now is " + this.now + ", now is " + now);
  1319. |
  1320. 14 | DateRollingFileStream.super_.call(this, filename, options);
  1321. | }
  1322. 2 | util.inherits(DateRollingFileStream, BaseRollingFileStream);
  1323. |
  1324. 2 | DateRollingFileStream.prototype.shouldRoll = function() {
  1325. 7 | var lastTime = this.lastTimeWeWroteSomething,
  1326. | thisTime = format.asString(this.pattern, new Date(this.now()));
  1327. |
  1328. 7 | debug("DateRollingFileStream.shouldRoll with now = " +
  1329. | this.now() + ", thisTime = " + thisTime + ", lastTime = " + lastTime);
  1330. |
  1331. 7 | this.lastTimeWeWroteSomething = thisTime;
  1332. 7 | this.previousTime = lastTime;
  1333. |
  1334. 7 | return thisTime !== lastTime;
  1335. | };
  1336. |
  1337. 2 | DateRollingFileStream.prototype.roll = function(filename, callback) {
  1338. 2 | var that = this;
  1339. |
  1340. 2 | debug("Starting roll");
  1341. |
  1342. 2 | if (this.alwaysIncludePattern) {
  1343. 1 | this.filename = this.baseFilename + this.lastTimeWeWroteSomething;
  1344. 1 | async.series([
  1345. | this.closeTheStream.bind(this),
  1346. | this.openTheStream.bind(this)
  1347. | ], callback);
  1348. | } else {
  1349. 1 | var newFilename = this.baseFilename + this.previousTime;
  1350. 1 | async.series([
  1351. | this.closeTheStream.bind(this),
  1352. | deleteAnyExistingFile,
  1353. | renameTheCurrentFile,
  1354. | this.openTheStream.bind(this)
  1355. | ], callback);
  1356. | }
  1357. |
  1358. 2 | function deleteAnyExistingFile(cb) {
  1359. | //on windows, you can get a EEXIST error if you rename a file to an existing file
  1360. | //so, we'll try to delete the file we're renaming to first
  1361. 1 | fs.unlink(newFilename, function (err) {
  1362. | //ignore err: if we could not delete, it's most likely that it doesn't exist
  1363. 1 | cb();
  1364. | });
  1365. | }
  1366. |
  1367. 2 | function renameTheCurrentFile(cb) {
  1368. 1 | debug("Renaming the " + filename + " -> " + newFilename);
  1369. 1 | fs.rename(filename, newFilename, cb);
  1370. | }
  1371. |
  1372. | };
  1373. appenders/dateFile.js:
  1374. [ hits: 22, misses: 0, sloc: 22, coverage: 100.00% ]
  1375. 3 | "use strict";
  1376. 3 | var streams = require('../streams')
  1377. | , layouts = require('../layouts')
  1378. | , path = require('path')
  1379. | , os = require('os')
  1380. | , eol = os.EOL || '\n'
  1381. | , openFiles = [];
  1382. |
  1383. | //close open files on process exit.
  1384. 3 | process.on('exit', function() {
  1385. 1 | openFiles.forEach(function (file) {
  1386. 5 | file.end();
  1387. | });
  1388. | });
  1389. |
  1390. | /**
  1391. | * File appender that rolls files according to a date pattern.
  1392. | * @filename base filename.
  1393. | * @pattern the format that will be added to the end of filename when rolling,
  1394. | * also used to check when to roll files - defaults to '.yyyy-MM-dd'
  1395. | * @layout layout function for log messages - defaults to basicLayout
  1396. | */
  1397. 3 | function appender(filename, pattern, alwaysIncludePattern, layout) {
  1398. 14 | layout = layout || layouts.basicLayout;
  1399. |
  1400. 14 | var logFile = new streams.DateRollingFileStream(
  1401. | filename,
  1402. | pattern,
  1403. | { alwaysIncludePattern: alwaysIncludePattern }
  1404. | );
  1405. 14 | openFiles.push(logFile);
  1406. |
  1407. 14 | return function(logEvent) {
  1408. 3 | logFile.write(layout(logEvent) + eol, "utf8");
  1409. | };
  1410. |
  1411. | }
  1412. |
  1413. 3 | function configure(config, options) {
  1414. 3 | var layout;
  1415. |
  1416. 3 | if (config.layout) {
  1417. 2 | layout = layouts.layout(config.layout.type, config.layout);
  1418. | }
  1419. |
  1420. 3 | if (!config.alwaysIncludePattern) {
  1421. 2 | config.alwaysIncludePattern = false;
  1422. | }
  1423. |
  1424. 3 | if (options && options.cwd && !config.absolute) {
  1425. 1 | config.filename = path.join(options.cwd, config.filename);
  1426. | }
  1427. |
  1428. 3 | return appender(config.filename, config.pattern, config.alwaysIncludePattern, layout);
  1429. | }
  1430. |
  1431. 3 | exports.appender = appender;
  1432. 3 | exports.configure = configure;
  1433. appenders/file.js:
  1434. [ hits: 32, misses: 0, sloc: 32, coverage: 100.00% ]
  1435. 4 | "use strict";
  1436. 4 | var layouts = require('../layouts')
  1437. | , path = require('path')
  1438. | , fs = require('fs')
  1439. | , streams = require('../streams')
  1440. | , os = require('os')
  1441. | , eol = os.EOL || '\n'
  1442. | , openFiles = [];
  1443. |
  1444. | //close open files on process exit.
  1445. 4 | process.on('exit', function() {
  1446. 1 | openFiles.forEach(function (file) {
  1447. 5 | file.end();
  1448. | });
  1449. | });
  1450. |
  1451. | /**
  1452. | * File Appender writing the logs to a text file. Supports rolling of logs by size.
  1453. | *
  1454. | * @param file file log messages will be written to
  1455. | * @param layout a function that takes a logevent and returns a string
  1456. | * (defaults to basicLayout).
  1457. | * @param logSize - the maximum size (in bytes) for a log file,
  1458. | * if not provided then logs won't be rotated.
  1459. | * @param numBackups - the number of log files to keep after logSize
  1460. | * has been reached (default 5)
  1461. | */
  1462. 4 | function fileAppender (file, layout, logSize, numBackups) {
  1463. 18 | var bytesWritten = 0;
  1464. 18 | file = path.normalize(file);
  1465. 18 | layout = layout || layouts.basicLayout;
  1466. 18 | numBackups = numBackups === undefined ? 5 : numBackups;
  1467. | //there has to be at least one backup if logSize has been specified
  1468. 18 | numBackups = numBackups === 0 ? 1 : numBackups;
  1469. |
  1470. 18 | function openTheStream(file, fileSize, numFiles) {
  1471. 18 | var stream;
  1472. 18 | if (fileSize) {
  1473. 9 | stream = new streams.RollingFileStream(
  1474. | file,
  1475. | fileSize,
  1476. | numFiles
  1477. | );
  1478. | } else {
  1479. 9 | stream = fs.createWriteStream(
  1480. | file,
  1481. | { encoding: "utf8",
  1482. | mode: parseInt('0644', 8),
  1483. | flags: 'a' }
  1484. | );
  1485. | }
  1486. 18 | stream.on("error", function (err) {
  1487. 1 | console.error("log4js.fileAppender - Writing to file %s, error happened ", file, err);
  1488. | });
  1489. 18 | return stream;
  1490. | }
  1491. |
  1492. 18 | var logFile = openTheStream(file, logSize, numBackups);
  1493. |
  1494. | // push file to the stack of open handlers
  1495. 18 | openFiles.push(logFile);
  1496. |
  1497. 18 | return function(loggingEvent) {
  1498. 15 | logFile.write(layout(loggingEvent) + eol, "utf8");
  1499. | };
  1500. | }
  1501. |
  1502. 4 | function configure(config, options) {
  1503. 4 | var layout;
  1504. 4 | if (config.layout) {
  1505. 3 | layout = layouts.layout(config.layout.type, config.layout);
  1506. | }
  1507. |
  1508. 4 | if (options && options.cwd && !config.absolute) {
  1509. 1 | config.filename = path.join(options.cwd, config.filename);
  1510. | }
  1511. |
  1512. 4 | return fileAppender(config.filename, layout, config.maxLogSize, config.backups);
  1513. | }
  1514. |
  1515. 4 | exports.appender = fileAppender;
  1516. 4 | exports.configure = configure;
  1517. appenders/gelf.js:
  1518. [ hits: 83, misses: 0, sloc: 83, coverage: 100.00% ]
  1519. 7 | "use strict";
  1520. 7 | var zlib = require('zlib');
  1521. 7 | var layouts = require('../layouts');
  1522. 7 | var levels = require('../levels');
  1523. 7 | var dgram = require('dgram');
  1524. 7 | var util = require('util');
  1525. 7 | var debug = require('../debug')('GELF Appender');
  1526. |
  1527. 7 | var LOG_EMERG=0; // system is unusable
  1528. 7 | var LOG_ALERT=1; // action must be taken immediately
  1529. 7 | var LOG_CRIT=2; // critical conditions
  1530. 7 | var LOG_ERR=3; // error conditions
  1531. 7 | var LOG_ERROR=3; // because people WILL typo
  1532. 7 | var LOG_WARNING=4; // warning conditions
  1533. 7 | var LOG_NOTICE=5; // normal, but significant, condition
  1534. 7 | var LOG_INFO=6; // informational message
  1535. 7 | var LOG_DEBUG=7; // debug-level message
  1536. |
  1537. 7 | var levelMapping = {};
  1538. 7 | levelMapping[levels.ALL] = LOG_DEBUG;
  1539. 7 | levelMapping[levels.TRACE] = LOG_DEBUG;
  1540. 7 | levelMapping[levels.DEBUG] = LOG_DEBUG;
  1541. 7 | levelMapping[levels.INFO] = LOG_INFO;
  1542. 7 | levelMapping[levels.WARN] = LOG_WARNING;
  1543. 7 | levelMapping[levels.ERROR] = LOG_ERR;
  1544. 7 | levelMapping[levels.FATAL] = LOG_CRIT;
  1545. |
  1546. | /**
  1547. | * GELF appender that supports sending UDP packets to a GELF compatible server such as Graylog
  1548. | *
  1549. | * @param layout a function that takes a logevent and returns a string (defaults to none).
  1550. | * @param host - host to which to send logs (default:localhost)
  1551. | * @param port - port at which to send logs to (default:12201)
  1552. | * @param hostname - hostname of the current host (default:os hostname)
  1553. | * @param facility - facility to log to (default:nodejs-server)
  1554. | */
  1555. 7 | function gelfAppender (layout, host, port, hostname, facility) {
  1556. 7 | var config, customFields;
  1557. 7 | if (typeof(host) === 'object') {
  1558. 7 | config = host;
  1559. 7 | host = config.host;
  1560. 7 | port = config.port;
  1561. 7 | hostname = config.hostname;
  1562. 7 | facility = config.facility;
  1563. 7 | customFields = config.customFields;
  1564. | }
  1565. |
  1566. 7 | host = host || 'localhost';
  1567. 7 | port = port || 12201;
  1568. 7 | hostname = hostname || require('os').hostname();
  1569. 7 | facility = facility || 'nodejs-server';
  1570. 7 | layout = layout || layouts.messagePassThroughLayout;
  1571. |
  1572. 7 | var defaultCustomFields = customFields || {};
  1573. |
  1574. 7 | var client = dgram.createSocket("udp4");
  1575. |
  1576. 7 | process.on('exit', function() {
  1577. 2 | if (client) client.close();
  1578. | });
  1579. |
  1580. | /**
  1581. | * Add custom fields (start with underscore )
  1582. | * - if the first object passed to the logger contains 'GELF' field,
  1583. | * copy the underscore fields to the message
  1584. | * @param loggingEvent
  1585. | * @param msg
  1586. | */
  1587. 7 | function addCustomFields(loggingEvent, msg){
  1588. |
  1589. | /* append defaultCustomFields firsts */
  1590. 5 | Object.keys(defaultCustomFields).forEach(function(key) {
  1591. | // skip _id field for graylog2, skip keys not starts with UNDERSCORE
  1592. 2 | if (key.match(/^_/) && key !== "_id") {
  1593. 2 | msg[key] = defaultCustomFields[key];
  1594. | }
  1595. | });
  1596. |
  1597. | /* append custom fields per message */
  1598. 5 | var data = loggingEvent.data;
  1599. 5 | if (!Array.isArray(data) || data.length === 0) return;
  1600. 5 | var firstData = data[0];
  1601. |
  1602. 9 | if (!firstData.GELF) return; // identify with GELF field defined
  1603. 1 | Object.keys(firstData).forEach(function(key) {
  1604. | // skip _id field for graylog2, skip keys not starts with UNDERSCORE
  1605. 3 | if (key.match(/^_/) || key !== "_id") {
  1606. 3 | msg[key] = firstData[key];
  1607. | }
  1608. | });
  1609. |
  1610. | /* the custom field object should be removed, so it will not be looged by the later appenders */
  1611. 1 | loggingEvent.data.shift();
  1612. | }
  1613. |
  1614. 7 | function preparePacket(loggingEvent) {
  1615. 5 | var msg = {};
  1616. 5 | addCustomFields(loggingEvent, msg);
  1617. 5 | msg.full_message = layout(loggingEvent);
  1618. 5 | msg.short_message = msg.full_message;
  1619. |
  1620. 5 | msg.version="1.0";
  1621. 5 | msg.timestamp = msg.timestamp || new Date().getTime() / 1000 >> 0;
  1622. 5 | msg.host = hostname;
  1623. 5 | msg.level = levelMapping[loggingEvent.level || levels.DEBUG];
  1624. 5 | msg.facility = facility;
  1625. 5 | return msg;
  1626. | }
  1627. |
  1628. 7 | function sendPacket(packet) {
  1629. 3 | try {
  1630. 3 | client.send(packet, 0, packet.length, port, host);
  1631. | } catch(e) {}
  1632. | }
  1633. |
  1634. 7 | return function(loggingEvent) {
  1635. 5 | var message = preparePacket(loggingEvent);
  1636. 5 | zlib.gzip(new Buffer(JSON.stringify(message)), function(err, packet) {
  1637. 5 | if (err) {
  1638. 1 | console.error(err.stack);
  1639. | } else {
  1640. 4 | if (packet.length > 8192) {
  1641. 1 | debug("Message packet length (" + packet.length + ") is larger than 8k. Not sending");
  1642. | } else {
  1643. 3 | sendPacket(packet);
  1644. | }
  1645. | }
  1646. | });
  1647. | };
  1648. | }
  1649. |
  1650. 7 | function configure(config) {
  1651. 7 | var layout;
  1652. 7 | if (config.layout) {
  1653. 1 | layout = layouts.layout(config.layout.type, config.layout);
  1654. | }
  1655. 7 | return gelfAppender(layout, config);
  1656. | }
  1657. |
  1658. 7 | exports.appender = gelfAppender;
  1659. 7 | exports.configure = configure;
  1660. appenders/hookio.js:
  1661. [ hits: 46, misses: 0, sloc: 46, coverage: 100.00% ]
  1662. 4 | "use strict";
  1663. 4 | var log4js = require('../log4js')
  1664. | , layouts = require('../layouts')
  1665. | , Hook = require('hook.io').Hook
  1666. | , util = require('util');
  1667. |
  1668. 4 | var Logger = function createLogger(options) {
  1669. 1 | var self = this;
  1670. 1 | var actualAppender = options.actualAppender;
  1671. 1 | Hook.call(self, options);
  1672. 1 | self.on('hook::ready', function hookReady() {
  1673. 1 | self.on('*::' + options.name + '::log', function log(loggingEvent) {
  1674. 2 | deserializeLoggingEvent(loggingEvent);
  1675. 2 | actualAppender(loggingEvent);
  1676. | });
  1677. | });
  1678. | };
  1679. 4 | util.inherits(Logger, Hook);
  1680. |
  1681. 4 | function deserializeLoggingEvent(loggingEvent) {
  1682. 2 | loggingEvent.startTime = new Date(loggingEvent.startTime);
  1683. 2 | loggingEvent.level.toString = function levelToString() {
  1684. 2 | return loggingEvent.level.levelStr;
  1685. | };
  1686. | }
  1687. |
  1688. 4 | function initHook(hookioOptions) {
  1689. 4 | var loggerHook;
  1690. 4 | if (hookioOptions.mode === 'master') {
  1691. | // Start the master hook, handling the actual logging
  1692. 1 | loggerHook = new Logger(hookioOptions);
  1693. | } else {
  1694. | // Start a worker, just emitting events for a master
  1695. 3 | loggerHook = new Hook(hookioOptions);
  1696. | }
  1697. 4 | loggerHook.start();
  1698. 4 | return loggerHook;
  1699. | }
  1700. |
  1701. 4 | function getBufferedHook(hook, eventName) {
  1702. 4 | var hookBuffer = [];
  1703. 4 | var hookReady = false;
  1704. 4 | hook.on('hook::ready', function emptyBuffer() {
  1705. 3 | hookBuffer.forEach(function logBufferItem(loggingEvent) {
  1706. 1 | hook.emit(eventName, loggingEvent);
  1707. | });
  1708. 3 | hookReady = true;
  1709. | });
  1710. |
  1711. 4 | return function log(loggingEvent) {
  1712. 6 | if (hookReady) {
  1713. 4 | hook.emit(eventName, loggingEvent);
  1714. | } else {
  1715. 2 | hookBuffer.push(loggingEvent);
  1716. | }
  1717. | };
  1718. | }
  1719. |
  1720. 4 | function createAppender(hookioOptions) {
  1721. 4 | var loggerHook = initHook(hookioOptions);
  1722. 4 | var loggerEvent = hookioOptions.name + '::log';
  1723. 4 | return getBufferedHook(loggerHook, loggerEvent);
  1724. | }
  1725. |
  1726. 4 | function configure(config) {
  1727. 4 | var actualAppender;
  1728. 4 | if (config.appender && config.mode === 'master') {
  1729. 1 | log4js.loadAppender(config.appender.type);
  1730. 1 | actualAppender = log4js.appenderMakers[config.appender.type](config.appender);
  1731. 1 | config.actualAppender = actualAppender;
  1732. | }
  1733. 4 | return createAppender(config);
  1734. | }
  1735. |
  1736. 4 | exports.appender = createAppender;
  1737. 4 | exports.configure = configure;
  1738. appenders/logLevelFilter.js:
  1739. [ hits: 13, misses: 0, sloc: 13, coverage: 100.00% ]
  1740. 1 | "use strict";
  1741. 1 | var levels = require('../levels')
  1742. | , log4js = require('../log4js');
  1743. |
  1744. 1 | function logLevelFilter (levelString, appender) {
  1745. 2 | var level = levels.toLevel(levelString);
  1746. 2 | return function(logEvent) {
  1747. 8 | if (logEvent.level.isGreaterThanOrEqualTo(level)) {
  1748. 4 | appender(logEvent);
  1749. | }
  1750. | };
  1751. | }
  1752. |
  1753. 1 | function configure(config) {
  1754. 1 | log4js.loadAppender(config.appender.type);
  1755. 1 | var appender = log4js.appenderMakers[config.appender.type](config.appender);
  1756. 1 | return logLevelFilter(config.level, appender);
  1757. | }
  1758. |
  1759. 1 | exports.appender = logLevelFilter;
  1760. 1 | exports.configure = configure;
  1761. appenders/multiprocess.js:
  1762. [ hits: 65, misses: 0, sloc: 65, coverage: 100.00% ]
  1763. 6 | "use strict";
  1764. 6 | var log4js = require('../log4js')
  1765. | , net = require('net')
  1766. | , END_MSG = '__LOG4JS__';
  1767. |
  1768. | /**
  1769. | * Creates a server, listening on config.loggerPort, config.loggerHost.
  1770. | * Output goes to config.actualAppender (config.appender is used to
  1771. | * set up that appender).
  1772. | */
  1773. 6 | function logServer(config) {
  1774. |
  1775. | /**
  1776. | * Takes a utf-8 string, returns an object with
  1777. | * the correct log properties.
  1778. | */
  1779. 3 | function deserializeLoggingEvent(clientSocket, msg) {
  1780. 7 | var loggingEvent;
  1781. 7 | try {
  1782. 7 | loggingEvent = JSON.parse(msg);
  1783. 6 | loggingEvent.startTime = new Date(loggingEvent.startTime);
  1784. 6 | loggingEvent.level = log4js.levels.toLevel(loggingEvent.level.levelStr);
  1785. | } catch (e) {
  1786. | // JSON.parse failed, just log the contents probably a naughty.
  1787. 1 | loggingEvent = {
  1788. | startTime: new Date(),
  1789. | categoryName: 'log4js',
  1790. | level: log4js.levels.ERROR,
  1791. | data: [ 'Unable to parse log:', msg ]
  1792. | };
  1793. | }
  1794. |
  1795. 7 | loggingEvent.remoteAddress = clientSocket.remoteAddress;
  1796. 7 | loggingEvent.remotePort = clientSocket.remotePort;
  1797. |
  1798. 7 | return loggingEvent;
  1799. | }
  1800. |
  1801. 3 | var actualAppender = config.actualAppender,
  1802. | server = net.createServer(function serverCreated(clientSocket) {
  1803. 3 | clientSocket.setEncoding('utf8');
  1804. 3 | var logMessage = '';
  1805. |
  1806. 3 | function logTheMessage(msg) {
  1807. 7 | if (logMessage.length > 0) {
  1808. 7 | actualAppender(deserializeLoggingEvent(clientSocket, msg));
  1809. | }
  1810. | }
  1811. |
  1812. 3 | function chunkReceived(chunk) {
  1813. 13 | var event;
  1814. 13 | logMessage += chunk || '';
  1815. 13 | if (logMessage.indexOf(END_MSG) > -1) {
  1816. 7 | event = logMessage.substring(0, logMessage.indexOf(END_MSG));
  1817. 7 | logTheMessage(event);
  1818. 7 | logMessage = logMessage.substring(event.length + END_MSG.length) || '';
  1819. | //check for more, maybe it was a big chunk
  1820. 7 | chunkReceived();
  1821. | }
  1822. | }
  1823. |
  1824. 3 | clientSocket.on('data', chunkReceived);
  1825. 3 | clientSocket.on('end', chunkReceived);
  1826. | });
  1827. |
  1828. 3 | server.listen(config.loggerPort || 5000, config.loggerHost || 'localhost');
  1829. |
  1830. 3 | return actualAppender;
  1831. | }
  1832. |
  1833. 6 | function workerAppender(config) {
  1834. 3 | var canWrite = false,
  1835. | buffer = [],
  1836. | socket;
  1837. |
  1838. 3 | createSocket();
  1839. |
  1840. 3 | function createSocket() {
  1841. 5 | socket = net.createConnection(config.loggerPort || 5000, config.loggerHost || 'localhost');
  1842. 5 | socket.on('connect', function() {
  1843. 4 | emptyBuffer();
  1844. 4 | canWrite = true;
  1845. | });
  1846. 5 | socket.on('timeout', socket.end.bind(socket));
  1847. | //don't bother listening for 'error', 'close' gets called after that anyway
  1848. 5 | socket.on('close', createSocket);
  1849. | }
  1850. |
  1851. 3 | function emptyBuffer() {
  1852. 4 | var evt;
  1853. 4 | while ((evt = buffer.shift())) {
  1854. 2 | write(evt);
  1855. | }
  1856. | }
  1857. |
  1858. 3 | function write(loggingEvent) {
  1859. 9 | socket.write(JSON.stringify(loggingEvent), 'utf8');
  1860. 9 | socket.write(END_MSG, 'utf8');
  1861. | }
  1862. |
  1863. 3 | return function log(loggingEvent) {
  1864. 9 | if (canWrite) {
  1865. 7 | write(loggingEvent);
  1866. | } else {
  1867. 2 | buffer.push(loggingEvent);
  1868. | }
  1869. | };
  1870. | }
  1871. |
  1872. 6 | function createAppender(config) {
  1873. 6 | if (config.mode === 'master') {
  1874. 3 | return logServer(config);
  1875. | } else {
  1876. 3 | return workerAppender(config);
  1877. | }
  1878. | }
  1879. |
  1880. 6 | function configure(config, options) {
  1881. 1 | var actualAppender;
  1882. 1 | if (config.appender && config.mode === 'master') {
  1883. 1 | log4js.loadAppender(config.appender.type);
  1884. 1 | actualAppender = log4js.appenderMakers[config.appender.type](config.appender, options);
  1885. 1 | config.actualAppender = actualAppender;
  1886. | }
  1887. 1 | return createAppender(config);
  1888. | }
  1889. |
  1890. 6 | exports.appender = createAppender;
  1891. 6 | exports.configure = configure;
  1892. appenders/smtp.js:
  1893. [ hits: 40, misses: 0, sloc: 40, coverage: 100.00% ]
  1894. 6 | "use strict";
  1895. 6 | var layouts = require("../layouts")
  1896. | , mailer = require("nodemailer")
  1897. | , os = require('os');
  1898. |
  1899. | /**
  1900. | * SMTP Appender. Sends logging events using SMTP protocol.
  1901. | * It can either send an email on each event or group several
  1902. | * logging events gathered during specified interval.
  1903. | *
  1904. | * @param config appender configuration data
  1905. | * config.sendInterval time between log emails (in seconds), if 0
  1906. | * then every event sends an email
  1907. | * @param layout a function that takes a logevent and returns a string (defaults to basicLayout).
  1908. | */
  1909. 6 | function smtpAppender(config, layout) {
  1910. 6 | layout = layout || layouts.basicLayout;
  1911. 6 | var subjectLayout = layouts.messagePassThroughLayout;
  1912. 6 | var sendInterval = config.sendInterval*1000 || 0;
  1913. |
  1914. 6 | var logEventBuffer = [];
  1915. 6 | var sendTimer;
  1916. |
  1917. 6 | function sendBuffer() {
  1918. 8 | if (logEventBuffer.length > 0) {
  1919. |
  1920. 8 | var transport = mailer.createTransport(config.transport, config[config.transport]);
  1921. 8 | var firstEvent = logEventBuffer[0];
  1922. 8 | var body = "";
  1923. 8 | while (logEventBuffer.length > 0) {
  1924. 9 | body += layout(logEventBuffer.shift()) + "\n";
  1925. | }
  1926. |
  1927. 8 | var msg = {
  1928. | to: config.recipients,
  1929. | subject: config.subject || subjectLayout(firstEvent),
  1930. | text: body,
  1931. | headers: { "Hostname": os.hostname() }
  1932. | };
  1933. 8 | if (config.sender) {
  1934. 1 | msg.from = config.sender;
  1935. | }
  1936. 8 | transport.sendMail(msg, function(error, success) {
  1937. 8 | if (error) {
  1938. 1 | console.error("log4js.smtpAppender - Error happened", error);
  1939. | }
  1940. 8 | transport.close();
  1941. | });
  1942. | }
  1943. | }
  1944. |
  1945. 6 | function scheduleSend() {
  1946. 3 | if (!sendTimer) {
  1947. 2 | sendTimer = setTimeout(function() {
  1948. 2 | sendTimer = null;
  1949. 2 | sendBuffer();
  1950. | }, sendInterval);
  1951. | }
  1952. | }
  1953. |
  1954. 6 | return function(loggingEvent) {
  1955. 9 | logEventBuffer.push(loggingEvent);
  1956. 9 | if (sendInterval > 0) {
  1957. 3 | scheduleSend();
  1958. | } else {
  1959. 6 | sendBuffer();
  1960. | }
  1961. | };
  1962. | }
  1963. |
  1964. 6 | function configure(config) {
  1965. 6 | var layout;
  1966. 6 | if (config.layout) {
  1967. 1 | layout = layouts.layout(config.layout.type, config.layout);
  1968. | }
  1969. 6 | return smtpAppender(config, layout);
  1970. | }
  1971. |
  1972. 6 | exports.name = "smtp";
  1973. 6 | exports.appender = smtpAppender;
  1974. 6 | exports.configure = configure;
  1975. |