Coverage

866
0
866
100%

levels.js

28
0
28
100%
LineHitsSource
082"use strict";
1
282function Level(level, levelStr) {
3656 this.level = level;
4656 this.levelStr = levelStr;
5}
6
7/**
8 * converts given String to corresponding Level
9 * @param {String} sArg String value of Level OR Log4js.Level
10 * @param {Log4js.Level} defaultLevel default Level, if no String representation
11 * @return Level object
12 * @type Log4js.Level
13 */
1482function toLevel(sArg, defaultLevel) {
15
161726 if (!sArg) {
1716 return defaultLevel;
18 }
19
201710 if (typeof sArg == "string") {
211636 var s = sArg.toUpperCase();
221636 if (module.exports[s]) {
231632 return module.exports[s];
24 } else {
254 return defaultLevel;
26 }
27 }
28
2974 return toLevel(sArg.toString());
30}
31
3282Level.prototype.toString = function() {
33556 return this.levelStr;
34};
35
3682Level.prototype.isLessThanOrEqualTo = function(otherLevel) {
371094 if (typeof otherLevel === "string") {
38151 otherLevel = toLevel(otherLevel);
39 }
401094 return this.level <= otherLevel.level;
41};
42
4382Level.prototype.isGreaterThanOrEqualTo = function(otherLevel) {
44103 if (typeof otherLevel === "string") {
457 otherLevel = toLevel(otherLevel);
46 }
47103 return this.level >= otherLevel.level;
48};
49
5082Level.prototype.isEqualTo = function(otherLevel) {
5178 if (typeof otherLevel == "string") {
523 otherLevel = toLevel(otherLevel);
53 }
5478 return this.level === otherLevel.level;
55};
56
5782module.exports = {
58 ALL: new Level(Number.MIN_VALUE, "ALL"),
59 TRACE: new Level(5000, "TRACE"),
60 DEBUG: new Level(10000, "DEBUG"),
61 INFO: new Level(20000, "INFO"),
62 WARN: new Level(30000, "WARN"),
63 ERROR: new Level(40000, "ERROR"),
64 FATAL: new Level(50000, "FATAL"),
65 OFF: new Level(Number.MAX_VALUE, "OFF"),
66 toLevel: toLevel
67};

layouts.js

115
0
115
100%
LineHitsSource
045"use strict";
145var dateFormat = require('./date_format')
2, os = require('os')
3, eol = os.EOL || '\n'
4, util = require('util')
5, replacementRegExp = /%[sdj]/g
6, layoutMakers = {
79 "messagePassThrough": function() { return messagePassThroughLayout; },
81 "basic": function() { return basicLayout; },
91 "colored": function() { return colouredLayout; },
101 "coloured": function() { return colouredLayout; },
11 "pattern": function (config) {
121 return patternLayout(config && config.pattern, config && config.tokens);
13 }
14}
15, colours = {
16 ALL: "grey",
17 TRACE: "blue",
18 DEBUG: "cyan",
19 INFO: "green",
20 WARN: "yellow",
21 ERROR: "red",
22 FATAL: "magenta",
23 OFF: "grey"
24};
25
2645function wrapErrorsWithInspect(items) {
2785 return items.map(function(item) {
28159 if ((item instanceof Error) && item.stack) {
296 return { inspect: function() { return util.format(item) + '\n' + item.stack; } };
30 } else {
31156 return item;
32 }
33 });
34}
35
3645function formatLogData(logData) {
3785 var data = Array.isArray(logData) ? logData : Array.prototype.slice.call(arguments);
3885 return util.format.apply(util, wrapErrorsWithInspect(data));
39}
40
4145var styles = {
42 //styles
43 'bold' : [1, 22],
44 'italic' : [3, 23],
45 'underline' : [4, 24],
46 'inverse' : [7, 27],
47 //grayscale
48 'white' : [37, 39],
49 'grey' : [90, 39],
50 'black' : [90, 39],
51 //colors
52 'blue' : [34, 39],
53 'cyan' : [36, 39],
54 'green' : [32, 39],
55 'magenta' : [35, 39],
56 'red' : [31, 39],
57 'yellow' : [33, 39]
58};
59
6045function colorizeStart(style) {
6124 return style ? '\x1B[' + styles[style][0] + 'm' : '';
62}
6345function colorizeEnd(style) {
6424 return style ? '\x1B[' + styles[style][1] + 'm' : '';
65}
66/**
67 * Taken from masylum's fork (https://github.com/masylum/log4js-node)
68 */
6945function colorize (str, style) {
7023 return colorizeStart(style) + str + colorizeEnd(style);
71}
72
7345function timestampLevelAndCategory(loggingEvent, colour) {
7423 var output = colorize(
75 formatLogData(
76 '[%s] [%s] %s - '
77 , dateFormat.asString(loggingEvent.startTime)
78 , loggingEvent.level
79 , loggingEvent.categoryName
80 )
81 , colour
82 );
8323 return output;
84}
85
86/**
87 * BasicLayout is a simple layout for storing the logs. The logs are stored
88 * in following format:
89 * <pre>
90 * [startTime] [logLevel] categoryName - message\n
91 * </pre>
92 *
93 * @author Stephan Strittmatter
94 */
9545function basicLayout (loggingEvent) {
9621 return timestampLevelAndCategory(loggingEvent) + formatLogData(loggingEvent.data);
97}
98
99/**
100 * colouredLayout - taken from masylum's fork.
101 * same as basicLayout, but with colours.
102 */
10345function colouredLayout (loggingEvent) {
1042 return timestampLevelAndCategory(
105 loggingEvent,
106 colours[loggingEvent.level.toString()]
107 ) + formatLogData(loggingEvent.data);
108}
109
11045function messagePassThroughLayout (loggingEvent) {
11131 return formatLogData(loggingEvent.data);
112}
113
114/**
115 * PatternLayout
116 * Format for specifiers is %[padding].[truncation][field]{[format]}
117 * e.g. %5.10p - left pad the log level by 5 characters, up to a max of 10
118 * Fields can be any of:
119 * - %r time in toLocaleTimeString format
120 * - %p log level
121 * - %c log category
122 * - %m log data
123 * - %d date in various formats
124 * - %% %
125 * - %n newline
126 * - %x{<tokenname>} add dynamic tokens to your log. Tokens are specified in the tokens parameter
127 * You can use %[ and %] to define a colored block.
128 *
129 * Tokens are specified as simple key:value objects.
130 * The key represents the token name whereas the value can be a string or function
131 * which is called to extract the value to put in the log message. If token is not
132 * found, it doesn't replace the field.
133 *
134 * A sample token would be: { "pid" : function() { return process.pid; } }
135 *
136 * Takes a pattern string, array of tokens and returns a layout function.
137 * @param {String} Log format pattern String
138 * @param {object} map object of different tokens
139 * @return {Function}
140 * @author Stephan Strittmatter
141 * @author Jan Schmidle
142 */
14345function patternLayout (pattern, tokens) {
14442 var TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";
14542 var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([\[\]cdmnprx%])(\{([^\}]+)\})?|([^%]+)/;
146
14742 pattern = pattern || TTCC_CONVERSION_PATTERN;
148
14942 function categoryName(loggingEvent, specifier) {
1509 var loggerName = loggingEvent.categoryName;
1519 if (specifier) {
1527 var precision = parseInt(specifier, 10);
1537 var loggerNameBits = loggerName.split(".");
1547 if (precision < loggerNameBits.length) {
1554 loggerName = loggerNameBits.slice(loggerNameBits.length - precision).join(".");
156 }
157 }
1589 return loggerName;
159 }
160
16142 function formatAsDate(loggingEvent, specifier) {
1627 var format = dateFormat.ISO8601_FORMAT;
1637 if (specifier) {
1646 format = specifier;
165 // Pick up special cases
1666 if (format == "ISO8601") {
1671 format = dateFormat.ISO8601_FORMAT;
1685 } else if (format == "ABSOLUTE") {
1692 format = dateFormat.ABSOLUTETIME_FORMAT;
1703 } else if (format == "DATE") {
1711 format = dateFormat.DATETIME_FORMAT;
172 }
173 }
174 // Format the date
1757 return dateFormat.asString(format, loggingEvent.startTime);
176 }
177
17842 function formatMessage(loggingEvent) {
1798 return formatLogData(loggingEvent.data);
180 }
181
18242 function endOfLine() {
1834 return eol;
184 }
185
18642 function logLevel(loggingEvent) {
18711 return loggingEvent.level.toString();
188 }
189
19042 function startTime(loggingEvent) {
1913 return "" + loggingEvent.startTime.toLocaleTimeString();
192 }
193
19442 function startColour(loggingEvent) {
1951 return colorizeStart(colours[loggingEvent.level.toString()]);
196 }
197
19842 function endColour(loggingEvent) {
1991 return colorizeEnd(colours[loggingEvent.level.toString()]);
200 }
201
20242 function percent() {
2031 return '%';
204 }
205
20642 function userDefined(loggingEvent, specifier) {
2075 if (typeof(tokens[specifier]) !== 'undefined') {
2083 if (typeof(tokens[specifier]) === 'function') {
2092 return tokens[specifier](loggingEvent);
210 } else {
2111 return tokens[specifier];
212 }
213 }
2142 return null;
215 }
216
21742 var replacers = {
218 'c': categoryName,
219 'd': formatAsDate,
220 'm': formatMessage,
221 'n': endOfLine,
222 'p': logLevel,
223 'r': startTime,
224 '[': startColour,
225 ']': endColour,
226 '%': percent,
227 'x': userDefined
228 };
229
23042 function replaceToken(conversionCharacter, loggingEvent, specifier) {
23150 return replacers[conversionCharacter](loggingEvent, specifier);
232 }
233
23442 function truncate(truncation, toTruncate) {
23550 var len;
23650 if (truncation) {
2375 len = parseInt(truncation.substr(1), 10);
2385 return toTruncate.substring(0, len);
239 }
240
24145 return toTruncate;
242 }
243
24442 function pad(padding, toPad) {
24550 var len;
24650 if (padding) {
2478 if (padding.charAt(0) == "-") {
2484 len = parseInt(padding.substr(1), 10);
249 // Right pad with spaces
2504 while (toPad.length < len) {
2519 toPad += " ";
252 }
253 } else {
2544 len = parseInt(padding, 10);
255 // Left pad with spaces
2564 while (toPad.length < len) {
2579 toPad = " " + toPad;
258 }
259 }
260 }
26150 return toPad;
262 }
263
26442 return function(loggingEvent) {
26541 var formattedString = "";
26641 var result;
26741 var searchString = pattern;
268
26941 while ((result = regex.exec(searchString))) {
27058 var matchedString = result[0];
27158 var padding = result[1];
27258 var truncation = result[2];
27358 var conversionCharacter = result[3];
27458 var specifier = result[5];
27558 var text = result[6];
276
277 // Check if the pattern matched was just normal text
27858 if (text) {
2798 formattedString += "" + text;
280 } else {
281 // Create a raw replacement string based on the conversion
282 // character and specifier
28350 var replacement =
284 replaceToken(conversionCharacter, loggingEvent, specifier) ||
285 matchedString;
286
287 // Format the replacement according to any padding or
288 // truncation specified
28950 replacement = truncate(truncation, replacement);
29050 replacement = pad(padding, replacement);
29150 formattedString += replacement;
292 }
29358 searchString = searchString.substr(result.index + result[0].length);
294 }
29541 return formattedString;
296 };
297
298}
299
30045module.exports = {
301 basicLayout: basicLayout,
302 messagePassThroughLayout: messagePassThroughLayout,
303 patternLayout: patternLayout,
304 colouredLayout: colouredLayout,
305 coloredLayout: colouredLayout,
306 layout: function(name, config) {
30713 return layoutMakers[name] && layoutMakers[name](config);
308 }
309};

date_format.js

38
0
38
100%
LineHitsSource
045"use strict";
145exports.ISO8601_FORMAT = "yyyy-MM-dd hh:mm:ss.SSS";
245exports.ISO8601_WITH_TZ_OFFSET_FORMAT = "yyyy-MM-ddThh:mm:ssO";
345exports.DATETIME_FORMAT = "dd MM yyyy hh:mm:ss.SSS";
445exports.ABSOLUTETIME_FORMAT = "hh:mm:ss.SSS";
5
645function padWithZeros(vNumber, width) {
7456 var numAsString = vNumber + "";
8456 while (numAsString.length < width) {
9184 numAsString = "0" + numAsString;
10 }
11456 return numAsString;
12}
13
1445function addZero(vNumber) {
15399 return padWithZeros(vNumber, 2);
16}
17
18/**
19 * Formats the TimeOffest
20 * Thanks to http://www.svendtofte.com/code/date_format/
21 * @private
22 */
2345function offset(date) {
24 // Difference to Greenwich time (GMT) in hours
2557 var os = Math.abs(date.getTimezoneOffset());
2657 var h = String(Math.floor(os/60));
2757 var m = String(os%60);
2857 if (h.length == 1) {
292 h = "0" + h;
30 }
3157 if (m.length == 1) {
3257 m = "0" + m;
33 }
3457 return date.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m;
35}
36
3745exports.asString = function(/*format,*/ date) {
3857 var format = exports.ISO8601_FORMAT;
3957 if (typeof(date) === "string") {
4033 format = arguments[0];
4133 date = arguments[1];
42 }
43
4457 var vDay = addZero(date.getDate());
4557 var vMonth = addZero(date.getMonth()+1);
4657 var vYearLong = addZero(date.getFullYear());
4757 var vYearShort = addZero(date.getFullYear().toString().substring(3,4));
4857 var vYear = (format.indexOf("yyyy") > -1 ? vYearLong : vYearShort);
4957 var vHour = addZero(date.getHours());
5057 var vMinute = addZero(date.getMinutes());
5157 var vSecond = addZero(date.getSeconds());
5257 var vMillisecond = padWithZeros(date.getMilliseconds(), 3);
5357 var vTimeZone = offset(date);
5457 var formatted = format
55 .replace(/dd/g, vDay)
56 .replace(/MM/g, vMonth)
57 .replace(/y{1,4}/g, vYear)
58 .replace(/hh/g, vHour)
59 .replace(/mm/g, vMinute)
60 .replace(/ss/g, vSecond)
61 .replace(/SSS/g, vMillisecond)
62 .replace(/O/g, vTimeZone);
6357 return formatted;
64
65};

log4js.js

127
0
127
100%
LineHitsSource
024"use strict";
1/*
2 * Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
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 */
4524var 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/**
65 * Get a logger instance. Instance is cached on categoryName level.
66 * @param {String} categoryName name of category to log to.
67 * @return {Logger} instance of logger for the category
68 * @static
69 */
7024function getLogger (categoryName) {
71
72 // Use default logger if categoryName is not specified or invalid
73450 if (typeof categoryName !== "string") {
741 categoryName = Logger.DEFAULT_CATEGORY;
75 }
76
77450 var appenderList;
78450 if (!loggers[categoryName]) {
79 // Create the logger for this name if it doesn't already exist
8042 loggers[categoryName] = new Logger(categoryName);
8142 if (appenders[categoryName]) {
8214 appenderList = appenders[categoryName];
8314 appenderList.forEach(function(appender) {
8414 loggers[categoryName].addListener("log", appender);
85 });
86 }
8742 if (appenders[ALL_CATEGORIES]) {
8823 appenderList = appenders[ALL_CATEGORIES];
8923 appenderList.forEach(function(appender) {
9034 loggers[categoryName].addListener("log", appender);
91 });
92 }
93 }
94
95450 return loggers[categoryName];
96}
97
98/**
99 * args are appender, then zero or more categories
100 */
10124function addAppender () {
10281 var args = Array.prototype.slice.call(arguments);
10381 var appender = args.shift();
10481 if (args.length === 0 || args[0] === undefined) {
10547 args = [ ALL_CATEGORIES ];
106 }
107 //argument may already be an array
10881 if (Array.isArray(args[0])) {
1092 args = args[0];
110 }
111
11281 args.forEach(function(category) {
11384 addAppenderToCategory(appender, category);
114
11584 if (category === ALL_CATEGORIES) {
11647 addAppenderToAllLoggers(appender);
11737 } else if (loggers[category]) {
11823 loggers[category].addListener("log", appender);
119 }
120 });
121}
122
12324function addAppenderToAllLoggers(appender) {
12447 for (var logger in loggers) {
12580 if (loggers.hasOwnProperty(logger)) {
12680 loggers[logger].addListener("log", appender);
127 }
128 }
129}
130
13124function addAppenderToCategory(appender, category) {
13284 if (!appenders[category]) {
13369 appenders[category] = [];
134 }
13584 appenders[category].push(appender);
136}
137
13824function clearAppenders () {
13973 appenders = {};
14073 for (var logger in loggers) {
141231 if (loggers.hasOwnProperty(logger)) {
142231 loggers[logger].removeAllListeners("log");
143 }
144 }
145}
146
14724function configureAppenders(appenderList, options) {
14851 clearAppenders();
14951 if (appenderList) {
15040 appenderList.forEach(function(appenderConfig) {
15142 loadAppender(appenderConfig.type);
15242 var appender;
15342 appenderConfig.makers = appenderMakers;
15442 try {
15542 appender = appenderMakers[appenderConfig.type](appenderConfig, options);
15641 addAppender(appender, appenderConfig.category);
157 } catch(e) {
1581 throw new Error("log4js configuration problem for " + util.inspect(appenderConfig), e);
159 }
160 });
161 }
162}
163
16424function configureLevels(levels) {
16550 if (levels) {
16611 for (var category in levels) {
16710 if (levels.hasOwnProperty(category)) {
16810 getLogger(category).setLevel(levels[category]);
169 }
170 }
171 }
172}
173
17424function setGlobalLogLevel(level) {
1752 Logger.prototype.level = levels.toLevel(level, levels.TRACE);
176}
177
178/**
179 * Get the default logger instance.
180 * @return {Logger} instance of default logger
181 * @static
182 */
18324function getDefaultLogger () {
1841 return getLogger(Logger.DEFAULT_CATEGORY);
185}
186
18724var configState = {};
188
18924function loadConfigurationFile(filename) {
19037 if (filename) {
19112 return JSON.parse(fs.readFileSync(filename, "utf8"));
192 }
19325 return undefined;
194}
195
19624function configureOnceOff(config, options) {
19751 if (config) {
19851 try {
19951 configureAppenders(config.appenders, options);
20050 configureLevels(config.levels);
201
20250 if (config.replaceConsole) {
2031 replaceConsole();
204 } else {
20549 restoreConsole();
206 }
207 } catch (e) {
2081 throw new Error(
209 "Problem reading log4js config " + util.inspect(config) +
210 ". Error was \"" + e.message + "\" (" + e.stack + ")"
211 );
212 }
213 }
214}
215
21624function reloadConfiguration() {
2173 var mtime = getMTime(configState.filename);
2184 if (!mtime) return;
219
2202 if (configState.lastMTime && (mtime.getTime() > configState.lastMTime.getTime())) {
2211 configureOnceOff(loadConfigurationFile(configState.filename));
222 }
2232 configState.lastMTime = mtime;
224}
225
22624function getMTime(filename) {
2278 var mtime;
2288 try {
2298 mtime = fs.statSync(configState.filename).mtime;
230 } catch (e) {
2311 getLogger('log4js').warn('Failed to load configuration file ' + filename);
232 }
2338 return mtime;
234}
235
23624function initReloadConfiguration(filename, options) {
2375 if (configState.timerId) {
2381 clearInterval(configState.timerId);
2391 delete configState.timerId;
240 }
2415 configState.filename = filename;
2425 configState.lastMTime = getMTime(filename);
2435 configState.timerId = setInterval(reloadConfiguration, options.reloadSecs*1000);
244}
245
24624function configure(configurationFileOrObject, options) {
24750 var config = configurationFileOrObject;
24850 config = config || process.env.LOG4JS_CONFIG;
24950 options = options || {};
250
25150 if (config === undefined || config === null || typeof(config) === 'string') {
25236 if (options.reloadSecs) {
2535 initReloadConfiguration(config, options);
254 }
25536 config = loadConfigurationFile(config) || defaultConfig;
256 } else {
25714 if (options.reloadSecs) {
2581 getLogger('log4js').warn(
259 'Ignoring configuration reload parameter for "object" configuration.'
260 );
261 }
262 }
26350 configureOnceOff(config, options);
264}
265
26624var originalConsoleFunctions = {
267 log: console.log,
268 debug: console.debug,
269 info: console.info,
270 warn: console.warn,
271 error: console.error
272};
273
27424function replaceConsole(logger) {
2753 function replaceWith(fn) {
27615 return function() {
27710 fn.apply(logger, arguments);
278 };
279 }
2803 logger = logger || getLogger("console");
2813 ['log','debug','info','warn','error'].forEach(function (item) {
28215 console[item] = replaceWith(item === 'log' ? logger.info : logger[item]);
283 });
284}
285
28624function restoreConsole() {
28751 ['log', 'debug', 'info', 'warn', 'error'].forEach(function (item) {
288255 console[item] = originalConsoleFunctions[item];
289 });
290}
291
29224function loadAppender(appender) {
29346 var appenderModule;
29446 try {
29546 appenderModule = require('./appenders/' + appender);
296 } catch (e) {
2971 appenderModule = require(appender);
298 }
29946 module.exports.appenders[appender] = appenderModule.appender.bind(appenderModule);
30046 appenderMakers[appender] = appenderModule.configure.bind(appenderModule);
301}
302
30324module.exports = {
304 getLogger: getLogger,
305 getDefaultLogger: getDefaultLogger,
306
307 addAppender: addAppender,
308 loadAppender: loadAppender,
309 clearAppenders: clearAppenders,
310 configure: configure,
311
312 replaceConsole: replaceConsole,
313 restoreConsole: restoreConsole,
314
315 levels: levels,
316 setGlobalLogLevel: setGlobalLogLevel,
317
318 layouts: layouts,
319 appenders: {},
320 appenderMakers: appenderMakers,
321 connectLogger: require('./connect-logger').connectLogger
322};
323
324//set ourselves up
32524configure();
326

logger.js

35
0
35
100%
LineHitsSource
041"use strict";
141var levels = require('./levels')
2, util = require('util')
3, events = require('events')
4, DEFAULT_CATEGORY = '[default]';
5
6/**
7 * Models a logging event.
8 * @constructor
9 * @param {String} categoryName name of category
10 * @param {Log4js.Level} level level of message
11 * @param {Array} data objects to log
12 * @param {Log4js.Logger} logger the associated logger
13 * @author Seth Chisamore
14 */
1541function LoggingEvent (categoryName, level, data, logger) {
1679 this.startTime = new Date();
1779 this.categoryName = categoryName;
1879 this.data = data;
1979 this.level = level;
2079 this.logger = logger;
21}
22
23/**
24 * Logger to log messages.
25 * use {@see Log4js#getLogger(String)} to get an instance.
26 * @constructor
27 * @param name name of category to log to
28 * @author Stephan Strittmatter
29 */
3041function Logger (name, level) {
3146 this.category = name || DEFAULT_CATEGORY;
32
3346 if (level) {
342 this.setLevel(level);
35 }
36}
3741util.inherits(Logger, events.EventEmitter);
3841Logger.DEFAULT_CATEGORY = DEFAULT_CATEGORY;
3941Logger.prototype.level = levels.TRACE;
40
4141Logger.prototype.setLevel = function(level) {
42213 this.level = levels.toLevel(level, this.level || levels.TRACE);
43};
44
4541Logger.prototype.removeLevel = function() {
462 delete this.level;
47};
48
4941Logger.prototype.log = function() {
5079 var args = Array.prototype.slice.call(arguments)
51 , logLevel = args.shift()
52 , loggingEvent = new LoggingEvent(this.category, logLevel, args, this);
5379 this.emit("log", loggingEvent);
54};
55
5641Logger.prototype.isLevelEnabled = function(otherLevel) {
57562 return this.level.isLessThanOrEqualTo(otherLevel);
58};
59
6041['Trace','Debug','Info','Warn','Error','Fatal'].forEach(
61 function(levelString) {
62246 var level = levels.toLevel(levelString);
63246 Logger.prototype['is'+levelString+'Enabled'] = function() {
646 return this.isLevelEnabled(level);
65 };
66
67246 Logger.prototype[levelString.toLowerCase()] = function () {
6888 if (this.isLevelEnabled(level)) {
6979 var args = Array.prototype.slice.call(arguments);
7079 args.unshift(level);
7179 Logger.prototype.log.apply(this, args);
72 }
73 };
74 }
75);
76
77
7841exports.LoggingEvent = LoggingEvent;
7941exports.Logger = Logger;

connect-logger.js

53
0
53
100%
LineHitsSource
024"use strict";
124var levels = require("./levels");
224var DEFAULT_FORMAT = ':remote-addr - -' +
3 ' ":method :url HTTP/:http-version"' +
4 ' :status :content-length ":referrer"' +
5 ' ":user-agent"';
6/**
7 * Log requests with the given `options` or a `format` string.
8 *
9 * Options:
10 *
11 * - `format` Format string, see below for tokens
12 * - `level` A log4js levels instance. Supports also 'auto'
13 *
14 * Tokens:
15 *
16 * - `:req[header]` ex: `:req[Accept]`
17 * - `:res[header]` ex: `:res[Content-Length]`
18 * - `:http-version`
19 * - `:response-time`
20 * - `:remote-addr`
21 * - `:date`
22 * - `:method`
23 * - `:url`
24 * - `:referrer`
25 * - `:user-agent`
26 * - `:status`
27 *
28 * @param {String|Function|Object} format or options
29 * @return {Function}
30 * @api public
31 */
32
3324function getLogger(logger4js, options) {
3413 if ('object' == typeof options) {
356 options = options || {};
367 } else if (options) {
374 options = { format: options };
38 } else {
393 options = {};
40 }
41
4213 var thislogger = logger4js
43 , level = levels.toLevel(options.level, levels.INFO)
44 , fmt = options.format || DEFAULT_FORMAT
45 , nolog = options.nolog ? createNoLogCondition(options.nolog) : null;
46
4713 return function (req, res, next) {
48 // mount safety
4923 if (req._logging) return next();
50
51 // nologs
5230 if (nolog && nolog.test(req.originalUrl)) return next();
5316 if (thislogger.isLevelEnabled(level) || options.level === 'auto') {
54
5515 var start = new Date()
56 , statusCode
57 , writeHead = res.writeHead
58 , end = res.end
59 , url = req.originalUrl;
60
61 // flag as logging
6215 req._logging = true;
63
64 // proxy for statusCode.
6515 res.writeHead = function(code, headers){
6611 res.writeHead = writeHead;
6711 res.writeHead(code, headers);
6811 res.__statusCode = statusCode = code;
6911 res.__headers = headers || {};
70
71 //status code response level handling
7211 if(options.level === 'auto'){
735 level = levels.INFO;
748 if(code >= 300) level = levels.WARN;
757 if(code >= 400) level = levels.ERROR;
76 } else {
776 level = levels.toLevel(options.level, levels.INFO);
78 }
79 };
80
81 // proxy end to output a line to the provided logger.
8215 res.end = function(chunk, encoding) {
8315 res.end = end;
8415 res.end(chunk, encoding);
8515 res.responseTime = new Date() - start;
8615 if (thislogger.isLevelEnabled(level)) {
8715 if (typeof fmt === 'function') {
881 var line = fmt(req, res, function(str){ return format(str, req, res); });
892 if (line) thislogger.log(level, line);
90 } else {
9114 thislogger.log(level, format(fmt, req, res));
92 }
93 }
94 };
95 }
96
97 //ensure next gets always called
9816 next();
99 };
100}
101
102/**
103 * Return formatted log line.
104 *
105 * @param {String} str
106 * @param {IncomingMessage} req
107 * @param {ServerResponse} res
108 * @return {String}
109 * @api private
110 */
111
11224function format(str, req, res) {
11314 return str
114 .replace(':url', req.originalUrl)
115 .replace(':method', req.method)
116 .replace(':status', res.__statusCode || res.statusCode)
117 .replace(':response-time', res.responseTime)
118 .replace(':date', new Date().toUTCString())
119 .replace(':referrer', req.headers.referer || req.headers.referrer || '')
120 .replace(':http-version', req.httpVersionMajor + '.' + req.httpVersionMinor)
121 .replace(
122 ':remote-addr',
123 req.socket &&
124 (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress))
125 )
126 .replace(':user-agent', req.headers['user-agent'] || '')
127 .replace(
128 ':content-length',
129 (res._headers && res._headers['content-length']) ||
130 (res.__headers && res.__headers['Content-Length']) ||
131 '-'
132 )
1331 .replace(/:req\[([^\]]+)\]/g, function(_, field){ return req.headers[field.toLowerCase()]; })
134 .replace(/:res\[([^\]]+)\]/g, function(_, field){
1351 return res._headers ?
136 (res._headers[field.toLowerCase()] || res.__headers[field])
137 : (res.__headers && res.__headers[field]);
138 });
139}
140
141/**
142 * Return RegExp Object about nolog
143 *
144 * @param {String} nolog
145 * @return {RegExp}
146 * @api private
147 *
148 * syntax
149 * 1. String
150 * 1.1 "\\.gif"
151 * NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.gif?fuga
152 * LOGGING http://example.com/hoge.agif
153 * 1.2 in "\\.gif|\\.jpg$"
154 * NOT LOGGING http://example.com/hoge.gif and
155 * http://example.com/hoge.gif?fuga and http://example.com/hoge.jpg?fuga
156 * LOGGING http://example.com/hoge.agif,
157 * http://example.com/hoge.ajpg and http://example.com/hoge.jpg?hoge
158 * 1.3 in "\\.(gif|jpe?g|png)$"
159 * NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.jpeg
160 * LOGGING http://example.com/hoge.gif?uid=2 and http://example.com/hoge.jpg?pid=3
161 * 2. RegExp
162 * 2.1 in /\.(gif|jpe?g|png)$/
163 * SAME AS 1.3
164 * 3. Array
165 * 3.1 ["\\.jpg$", "\\.png", "\\.gif"]
166 * SAME AS "\\.jpg|\\.png|\\.gif"
167 */
16824function createNoLogCondition(nolog) {
1694 var regexp = null;
170
1714 if (nolog) {
1724 if (nolog instanceof RegExp) {
1731 regexp = nolog;
174 }
175
1764 if (typeof nolog === 'string') {
1772 regexp = new RegExp(nolog);
178 }
179
1804 if (Array.isArray(nolog)) {
1811 var regexpsAsStrings = nolog.map(
182 function convertToStrings(o) {
1832 return o.source ? o.source : o;
184 }
185 );
1861 regexp = new RegExp(regexpsAsStrings.join('|'));
187 }
188 }
189
1904 return regexp;
191}
192
19324exports.connectLogger = getLogger;

appenders/console.js

13
0
13
100%
LineHitsSource
019"use strict";
119var layouts = require('../layouts')
2, consoleLog = console.log.bind(console);
3
419function consoleAppender (layout) {
521 layout = layout || layouts.colouredLayout;
621 return function(loggingEvent) {
71 consoleLog(layout(loggingEvent));
8 };
9}
10
1119function configure(config) {
1220 var layout;
1320 if (config.layout) {
141 layout = layouts.layout(config.layout.type, config.layout);
15 }
1620 return consoleAppender(layout);
17}
18
1919exports.appender = consoleAppender;
2019exports.configure = configure;

streams/BaseRollingFileStream.js

48
0
48
100%
LineHitsSource
04"use strict";
14var fs = require('fs')
2, stream
3, debug = require('../debug')('BaseRollingFileStream')
4, util = require('util')
5, semver = require('semver');
6
74if (semver.satisfies(process.version, '>=0.10.0')) {
83 stream = require('stream');
9} else {
101 stream = require('readable-stream');
11}
12
134module.exports = BaseRollingFileStream;
14
154function BaseRollingFileStream(filename, options) {
1624 debug("In BaseRollingFileStream");
1724 this.filename = filename;
1824 this.options = options || { encoding: 'utf8', mode: parseInt('0644', 8), flags: 'a' };
1924 this.currentSize = 0;
20
2124 function currentFileSize(file) {
2223 var fileSize = 0;
2323 try {
2423 fileSize = fs.statSync(file).size;
25 } catch (e) {
26 // file does not exist
27 }
2823 return fileSize;
29 }
30
3124 function throwErrorIfArgumentsAreNotValid() {
3224 if (!filename) {
331 throw new Error("You must specify a filename");
34 }
35 }
36
3724 throwErrorIfArgumentsAreNotValid();
3823 debug("Calling BaseRollingFileStream.super");
3923 BaseRollingFileStream.super_.call(this);
4023 this.openTheStream();
4123 this.currentSize = currentFileSize(this.filename);
42}
434util.inherits(BaseRollingFileStream, stream.Writable);
44
454BaseRollingFileStream.prototype._write = function(chunk, encoding, callback) {
4629 var that = this;
4729 function writeTheChunk() {
4829 debug("writing the chunk to the underlying stream");
4929 that.currentSize += chunk.length;
5029 that.theStream.write(chunk, encoding, callback);
51 }
52
5329 debug("in _write");
54
5529 if (this.shouldRoll()) {
569 this.currentSize = 0;
579 this.roll(this.filename, writeTheChunk);
58 } else {
5920 writeTheChunk();
60 }
61};
62
634BaseRollingFileStream.prototype.openTheStream = function(cb) {
6432 debug("opening the underlying stream");
6532 this.theStream = fs.createWriteStream(this.filename, this.options);
6632 if (cb) {
679 this.theStream.on("open", cb);
68 }
69};
70
714BaseRollingFileStream.prototype.closeTheStream = function(cb) {
729 debug("closing the underlying stream");
739 this.theStream.end(cb);
74};
75
764BaseRollingFileStream.prototype.shouldRoll = function() {
771 return false; // default behaviour is never to roll
78};
79
804BaseRollingFileStream.prototype.roll = function(filename, callback) {
811 callback(); // default behaviour is not to do anything
82};
83

debug.js

8
0
8
100%
LineHitsSource
014"use strict";
1
214module.exports = function(label) {
318 var debug;
4
518 if (process.env.NODE_DEBUG && /\blog4js\b/.test(process.env.NODE_DEBUG)) {
61 debug = function(message) {
71 console.error('LOG4JS: (%s) %s', label, message);
8 };
9 } else {
1017 debug = function() { };
11 }
12
1318 return debug;
14};

streams/index.js

2
0
2
100%
LineHitsSource
02exports.RollingFileStream = require('./RollingFileStream');
12exports.DateRollingFileStream = require('./DateRollingFileStream');

streams/RollingFileStream.js

41
0
41
100%
LineHitsSource
02"use strict";
12var BaseRollingFileStream = require('./BaseRollingFileStream')
2, debug = require('../debug')('RollingFileStream')
3, util = require('util')
4, path = require('path')
5, fs = require('fs')
6, async = require('async');
7
82module.exports = RollingFileStream;
9
102function RollingFileStream (filename, size, backups, options) {
119 this.size = size;
129 this.backups = backups || 1;
13
149 function throwErrorIfArgumentsAreNotValid() {
159 if (!filename || !size || size <= 0) {
161 throw new Error("You must specify a filename and file size");
17 }
18 }
19
209 throwErrorIfArgumentsAreNotValid();
21
228 RollingFileStream.super_.call(this, filename, options);
23}
242util.inherits(RollingFileStream, BaseRollingFileStream);
25
262RollingFileStream.prototype.shouldRoll = function() {
2722 debug("should roll with current size %d, and max size %d", this.currentSize, this.size);
2822 return this.currentSize >= this.size;
29};
30
312RollingFileStream.prototype.roll = function(filename, callback) {
327 var that = this,
33 nameMatcher = new RegExp('^' + path.basename(filename));
34
357 function justTheseFiles (item) {
36305 return nameMatcher.test(item);
37 }
38
397 function index(filename_) {
40164 return parseInt(filename_.substring((path.basename(filename) + '.').length), 10) || 0;
41 }
42
437 function byIndex(a, b) {
4441 if (index(a) > index(b)) {
4514 return 1;
4627 } else if (index(a) < index(b) ) {
4724 return -1;
48 } else {
493 return 0;
50 }
51 }
52
537 function increaseFileIndex (fileToRename, cb) {
5428 var idx = index(fileToRename);
5528 debug('Index of ' + fileToRename + ' is ' + idx);
5628 if (idx < that.backups) {
57 //on windows, you can get a EEXIST error if you rename a file to an existing file
58 //so, we'll try to delete the file we're renaming to first
5921 fs.unlink(filename + '.' + (idx+1), function (err) {
60 //ignore err: if we could not delete, it's most likely that it doesn't exist
6121 debug('Renaming ' + fileToRename + ' -> ' + filename + '.' + (idx+1));
6221 fs.rename(path.join(path.dirname(filename), fileToRename), filename + '.' + (idx + 1), cb);
63 });
64 } else {
657 cb();
66 }
67 }
68
697 function renameTheFiles(cb) {
70 //roll the backups (rename file.n to file.n+1, where n <= numBackups)
717 debug("Renaming the old files");
727 fs.readdir(path.dirname(filename), function (err, files) {
737 async.forEachSeries(
74 files.filter(justTheseFiles).sort(byIndex).reverse(),
75 increaseFileIndex,
76 cb
77 );
78 });
79 }
80
817 debug("Rolling, rolling, rolling");
827 async.series([
83 this.closeTheStream.bind(this),
84 renameTheFiles,
85 this.openTheStream.bind(this)
86 ], callback);
87
88};

streams/DateRollingFileStream.js

44
0
44
100%
LineHitsSource
02"use strict";
12var BaseRollingFileStream = require('./BaseRollingFileStream')
2, debug = require('../debug')('DateRollingFileStream')
3, format = require('../date_format')
4, async = require('async')
5, fs = require('fs')
6, util = require('util');
7
82module.exports = DateRollingFileStream;
9
102function DateRollingFileStream(filename, pattern, options, now) {
1114 debug("Now is " + now);
1214 if (pattern && typeof(pattern) === 'object') {
131 now = options;
141 options = pattern;
151 pattern = null;
16 }
1714 this.pattern = pattern || '.yyyy-MM-dd';
1814 this.now = now || Date.now;
1914 this.lastTimeWeWroteSomething = format.asString(this.pattern, new Date(this.now()));
2014 this.baseFilename = filename;
2114 this.alwaysIncludePattern = false;
22
2314 if (options) {
2411 if (options.alwaysIncludePattern) {
252 this.alwaysIncludePattern = true;
262 filename = this.baseFilename + this.lastTimeWeWroteSomething;
27 }
2811 delete options.alwaysIncludePattern;
2911 if (Object.keys(options).length === 0) {
309 options = null;
31 }
32 }
3314 debug("this.now is " + this.now + ", now is " + now);
34
3514 DateRollingFileStream.super_.call(this, filename, options);
36}
372util.inherits(DateRollingFileStream, BaseRollingFileStream);
38
392DateRollingFileStream.prototype.shouldRoll = function() {
407 var lastTime = this.lastTimeWeWroteSomething,
41 thisTime = format.asString(this.pattern, new Date(this.now()));
42
437 debug("DateRollingFileStream.shouldRoll with now = " +
44 this.now() + ", thisTime = " + thisTime + ", lastTime = " + lastTime);
45
467 this.lastTimeWeWroteSomething = thisTime;
477 this.previousTime = lastTime;
48
497 return thisTime !== lastTime;
50};
51
522DateRollingFileStream.prototype.roll = function(filename, callback) {
532 var that = this;
54
552 debug("Starting roll");
56
572 if (this.alwaysIncludePattern) {
581 this.filename = this.baseFilename + this.lastTimeWeWroteSomething;
591 async.series([
60 this.closeTheStream.bind(this),
61 this.openTheStream.bind(this)
62 ], callback);
63 } else {
641 var newFilename = this.baseFilename + this.previousTime;
651 async.series([
66 this.closeTheStream.bind(this),
67 deleteAnyExistingFile,
68 renameTheCurrentFile,
69 this.openTheStream.bind(this)
70 ], callback);
71 }
72
732 function deleteAnyExistingFile(cb) {
74 //on windows, you can get a EEXIST error if you rename a file to an existing file
75 //so, we'll try to delete the file we're renaming to first
761 fs.unlink(newFilename, function (err) {
77 //ignore err: if we could not delete, it's most likely that it doesn't exist
781 cb();
79 });
80 }
81
822 function renameTheCurrentFile(cb) {
831 debug("Renaming the " + filename + " -> " + newFilename);
841 fs.rename(filename, newFilename, cb);
85 }
86
87};

appenders/categoryFilter.js

13
0
13
100%
LineHitsSource
01"use strict";
11var log4js = require('../log4js');
2
31function categoryFilter (excludes, appender) {
43 if (typeof(excludes) === 'string') excludes = [excludes];
52 return function(logEvent) {
67 if (excludes.indexOf(logEvent.categoryName) === -1) {
74 appender(logEvent);
8 }
9 };
10}
11
121function configure(config) {
131 log4js.loadAppender(config.appender.type);
141 var appender = log4js.appenderMakers[config.appender.type](config.appender);
151 return categoryFilter(config.exclude, appender);
16}
17
181exports.appender = categoryFilter;
191exports.configure = configure;

appenders/file.js

32
0
32
100%
LineHitsSource
05"use strict";
15var layouts = require('../layouts')
2, path = require('path')
3, fs = require('fs')
4, streams = require('../streams')
5, os = require('os')
6, eol = os.EOL || '\n'
7, openFiles = [];
8
9//close open files on process exit.
105process.on('exit', function() {
111 openFiles.forEach(function (file) {
125 file.end();
13 });
14});
15
16/**
17 * File Appender writing the logs to a text file. Supports rolling of logs by size.
18 *
19 * @param file file log messages will be written to
20 * @param layout a function that takes a logevent and returns a string
21 * (defaults to basicLayout).
22 * @param logSize - the maximum size (in bytes) for a log file,
23 * if not provided then logs won't be rotated.
24 * @param numBackups - the number of log files to keep after logSize
25 * has been reached (default 5)
26 */
275function fileAppender (file, layout, logSize, numBackups) {
2820 var bytesWritten = 0;
2920 file = path.normalize(file);
3020 layout = layout || layouts.basicLayout;
3120 numBackups = numBackups === undefined ? 5 : numBackups;
32 //there has to be at least one backup if logSize has been specified
3320 numBackups = numBackups === 0 ? 1 : numBackups;
34
3520 function openTheStream(file, fileSize, numFiles) {
3620 var stream;
3720 if (fileSize) {
389 stream = new streams.RollingFileStream(
39 file,
40 fileSize,
41 numFiles
42 );
43 } else {
4411 stream = fs.createWriteStream(
45 file,
46 { encoding: "utf8",
47 mode: parseInt('0644', 8),
48 flags: 'a' }
49 );
50 }
5120 stream.on("error", function (err) {
521 console.error("log4js.fileAppender - Writing to file %s, error happened ", file, err);
53 });
5420 return stream;
55 }
56
5720 var logFile = openTheStream(file, logSize, numBackups);
58
59 // push file to the stack of open handlers
6020 openFiles.push(logFile);
61
6220 return function(loggingEvent) {
6319 logFile.write(layout(loggingEvent) + eol, "utf8");
64 };
65}
66
675function configure(config, options) {
686 var layout;
696 if (config.layout) {
705 layout = layouts.layout(config.layout.type, config.layout);
71 }
72
736 if (options && options.cwd && !config.absolute) {
741 config.filename = path.join(options.cwd, config.filename);
75 }
76
776 return fileAppender(config.filename, layout, config.maxLogSize, config.backups);
78}
79
805exports.appender = fileAppender;
815exports.configure = configure;

appenders/dateFile.js

22
0
22
100%
LineHitsSource
03"use strict";
13var streams = require('../streams')
2, layouts = require('../layouts')
3, path = require('path')
4, os = require('os')
5, eol = os.EOL || '\n'
6, openFiles = [];
7
8//close open files on process exit.
93process.on('exit', function() {
101 openFiles.forEach(function (file) {
115 file.end();
12 });
13});
14
15/**
16 * File appender that rolls files according to a date pattern.
17 * @filename base filename.
18 * @pattern the format that will be added to the end of filename when rolling,
19 * also used to check when to roll files - defaults to '.yyyy-MM-dd'
20 * @layout layout function for log messages - defaults to basicLayout
21 */
223function appender(filename, pattern, alwaysIncludePattern, layout) {
2314 layout = layout || layouts.basicLayout;
24
2514 var logFile = new streams.DateRollingFileStream(
26 filename,
27 pattern,
28 { alwaysIncludePattern: alwaysIncludePattern }
29 );
3014 openFiles.push(logFile);
31
3214 return function(logEvent) {
333 logFile.write(layout(logEvent) + eol, "utf8");
34 };
35
36}
37
383function configure(config, options) {
393 var layout;
40
413 if (config.layout) {
422 layout = layouts.layout(config.layout.type, config.layout);
43 }
44
453 if (!config.alwaysIncludePattern) {
462 config.alwaysIncludePattern = false;
47 }
48
493 if (options && options.cwd && !config.absolute) {
501 config.filename = path.join(options.cwd, config.filename);
51 }
52
533 return appender(config.filename, config.pattern, config.alwaysIncludePattern, layout);
54}
55
563exports.appender = appender;
573exports.configure = configure;

appenders/gelf.js

83
0
83
100%
LineHitsSource
07"use strict";
17var zlib = require('zlib');
27var layouts = require('../layouts');
37var levels = require('../levels');
47var dgram = require('dgram');
57var util = require('util');
67var debug = require('../debug')('GELF Appender');
7
87var LOG_EMERG=0; // system is unusable
97var LOG_ALERT=1; // action must be taken immediately
107var LOG_CRIT=2; // critical conditions
117var LOG_ERR=3; // error conditions
127var LOG_ERROR=3; // because people WILL typo
137var LOG_WARNING=4; // warning conditions
147var LOG_NOTICE=5; // normal, but significant, condition
157var LOG_INFO=6; // informational message
167var LOG_DEBUG=7; // debug-level message
17
187var levelMapping = {};
197levelMapping[levels.ALL] = LOG_DEBUG;
207levelMapping[levels.TRACE] = LOG_DEBUG;
217levelMapping[levels.DEBUG] = LOG_DEBUG;
227levelMapping[levels.INFO] = LOG_INFO;
237levelMapping[levels.WARN] = LOG_WARNING;
247levelMapping[levels.ERROR] = LOG_ERR;
257levelMapping[levels.FATAL] = LOG_CRIT;
26
27/**
28 * GELF appender that supports sending UDP packets to a GELF compatible server such as Graylog
29 *
30 * @param layout a function that takes a logevent and returns a string (defaults to none).
31 * @param host - host to which to send logs (default:localhost)
32 * @param port - port at which to send logs to (default:12201)
33 * @param hostname - hostname of the current host (default:os hostname)
34 * @param facility - facility to log to (default:nodejs-server)
35 */
367function gelfAppender (layout, host, port, hostname, facility) {
377 var config, customFields;
387 if (typeof(host) === 'object') {
397 config = host;
407 host = config.host;
417 port = config.port;
427 hostname = config.hostname;
437 facility = config.facility;
447 customFields = config.customFields;
45 }
46
477 host = host || 'localhost';
487 port = port || 12201;
497 hostname = hostname || require('os').hostname();
507 facility = facility || 'nodejs-server';
517 layout = layout || layouts.messagePassThroughLayout;
52
537 var defaultCustomFields = customFields || {};
54
557 var client = dgram.createSocket("udp4");
56
577 process.on('exit', function() {
582 if (client) client.close();
59 });
60
61 /**
62 * Add custom fields (start with underscore )
63 * - if the first object passed to the logger contains 'GELF' field,
64 * copy the underscore fields to the message
65 * @param loggingEvent
66 * @param msg
67 */
687 function addCustomFields(loggingEvent, msg){
69
70 /* append defaultCustomFields firsts */
715 Object.keys(defaultCustomFields).forEach(function(key) {
72 // skip _id field for graylog2, skip keys not starts with UNDERSCORE
732 if (key.match(/^_/) && key !== "_id") {
742 msg[key] = defaultCustomFields[key];
75 }
76 });
77
78 /* append custom fields per message */
795 var data = loggingEvent.data;
805 if (!Array.isArray(data) || data.length === 0) return;
815 var firstData = data[0];
82
839 if (!firstData.GELF) return; // identify with GELF field defined
841 Object.keys(firstData).forEach(function(key) {
85 // skip _id field for graylog2, skip keys not starts with UNDERSCORE
863 if (key.match(/^_/) || key !== "_id") {
873 msg[key] = firstData[key];
88 }
89 });
90
91 /* the custom field object should be removed, so it will not be looged by the later appenders */
921 loggingEvent.data.shift();
93 }
94
957 function preparePacket(loggingEvent) {
965 var msg = {};
975 addCustomFields(loggingEvent, msg);
985 msg.full_message = layout(loggingEvent);
995 msg.short_message = msg.full_message;
100
1015 msg.version="1.0";
1025 msg.timestamp = msg.timestamp || new Date().getTime() / 1000 >> 0;
1035 msg.host = hostname;
1045 msg.level = levelMapping[loggingEvent.level || levels.DEBUG];
1055 msg.facility = facility;
1065 return msg;
107 }
108
1097 function sendPacket(packet) {
1103 try {
1113 client.send(packet, 0, packet.length, port, host);
112 } catch(e) {}
113 }
114
1157 return function(loggingEvent) {
1165 var message = preparePacket(loggingEvent);
1175 zlib.gzip(new Buffer(JSON.stringify(message)), function(err, packet) {
1185 if (err) {
1191 console.error(err.stack);
120 } else {
1214 if (packet.length > 8192) {
1221 debug("Message packet length (" + packet.length + ") is larger than 8k. Not sending");
123 } else {
1243 sendPacket(packet);
125 }
126 }
127 });
128 };
129}
130
1317function configure(config) {
1327 var layout;
1337 if (config.layout) {
1341 layout = layouts.layout(config.layout.type, config.layout);
135 }
1367 return gelfAppender(layout, config);
137}
138
1397exports.appender = gelfAppender;
1407exports.configure = configure;

appenders/hookio.js

46
0
46
100%
LineHitsSource
04"use strict";
14var log4js = require('../log4js')
2, layouts = require('../layouts')
3, Hook = require('hook.io').Hook
4, util = require('util');
5
64var Logger = function createLogger(options) {
71 var self = this;
81 var actualAppender = options.actualAppender;
91 Hook.call(self, options);
101 self.on('hook::ready', function hookReady() {
111 self.on('*::' + options.name + '::log', function log(loggingEvent) {
122 deserializeLoggingEvent(loggingEvent);
132 actualAppender(loggingEvent);
14 });
15 });
16};
174util.inherits(Logger, Hook);
18
194function deserializeLoggingEvent(loggingEvent) {
202 loggingEvent.startTime = new Date(loggingEvent.startTime);
212 loggingEvent.level.toString = function levelToString() {
222 return loggingEvent.level.levelStr;
23 };
24}
25
264function initHook(hookioOptions) {
274 var loggerHook;
284 if (hookioOptions.mode === 'master') {
29 // Start the master hook, handling the actual logging
301 loggerHook = new Logger(hookioOptions);
31 } else {
32 // Start a worker, just emitting events for a master
333 loggerHook = new Hook(hookioOptions);
34 }
354 loggerHook.start();
364 return loggerHook;
37}
38
394function getBufferedHook(hook, eventName) {
404 var hookBuffer = [];
414 var hookReady = false;
424 hook.on('hook::ready', function emptyBuffer() {
433 hookBuffer.forEach(function logBufferItem(loggingEvent) {
441 hook.emit(eventName, loggingEvent);
45 });
463 hookReady = true;
47 });
48
494 return function log(loggingEvent) {
506 if (hookReady) {
514 hook.emit(eventName, loggingEvent);
52 } else {
532 hookBuffer.push(loggingEvent);
54 }
55 };
56}
57
584function createAppender(hookioOptions) {
594 var loggerHook = initHook(hookioOptions);
604 var loggerEvent = hookioOptions.name + '::log';
614 return getBufferedHook(loggerHook, loggerEvent);
62}
63
644function configure(config) {
654 var actualAppender;
664 if (config.appender && config.mode === 'master') {
671 log4js.loadAppender(config.appender.type);
681 actualAppender = log4js.appenderMakers[config.appender.type](config.appender);
691 config.actualAppender = actualAppender;
70 }
714 return createAppender(config);
72}
73
744exports.appender = createAppender;
754exports.configure = configure;

appenders/logLevelFilter.js

13
0
13
100%
LineHitsSource
01"use strict";
11var levels = require('../levels')
2, log4js = require('../log4js');
3
41function logLevelFilter (levelString, appender) {
52 var level = levels.toLevel(levelString);
62 return function(logEvent) {
78 if (logEvent.level.isGreaterThanOrEqualTo(level)) {
84 appender(logEvent);
9 }
10 };
11}
12
131function configure(config) {
141 log4js.loadAppender(config.appender.type);
151 var appender = log4js.appenderMakers[config.appender.type](config.appender);
161 return logLevelFilter(config.level, appender);
17}
18
191exports.appender = logLevelFilter;
201exports.configure = configure;

appenders/multiprocess.js

65
0
65
100%
LineHitsSource
06"use strict";
16var log4js = require('../log4js')
2, net = require('net')
3, END_MSG = '__LOG4JS__';
4
5/**
6 * Creates a server, listening on config.loggerPort, config.loggerHost.
7 * Output goes to config.actualAppender (config.appender is used to
8 * set up that appender).
9 */
106function logServer(config) {
11
12 /**
13 * Takes a utf-8 string, returns an object with
14 * the correct log properties.
15 */
163 function deserializeLoggingEvent(clientSocket, msg) {
177 var loggingEvent;
187 try {
197 loggingEvent = JSON.parse(msg);
206 loggingEvent.startTime = new Date(loggingEvent.startTime);
216 loggingEvent.level = log4js.levels.toLevel(loggingEvent.level.levelStr);
22 } catch (e) {
23 // JSON.parse failed, just log the contents probably a naughty.
241 loggingEvent = {
25 startTime: new Date(),
26 categoryName: 'log4js',
27 level: log4js.levels.ERROR,
28 data: [ 'Unable to parse log:', msg ]
29 };
30 }
31
327 loggingEvent.remoteAddress = clientSocket.remoteAddress;
337 loggingEvent.remotePort = clientSocket.remotePort;
34
357 return loggingEvent;
36 }
37
383 var actualAppender = config.actualAppender,
39 server = net.createServer(function serverCreated(clientSocket) {
403 clientSocket.setEncoding('utf8');
413 var logMessage = '';
42
433 function logTheMessage(msg) {
447 if (logMessage.length > 0) {
457 actualAppender(deserializeLoggingEvent(clientSocket, msg));
46 }
47 }
48
493 function chunkReceived(chunk) {
5013 var event;
5113 logMessage += chunk || '';
5213 if (logMessage.indexOf(END_MSG) > -1) {
537 event = logMessage.substring(0, logMessage.indexOf(END_MSG));
547 logTheMessage(event);
557 logMessage = logMessage.substring(event.length + END_MSG.length) || '';
56 //check for more, maybe it was a big chunk
577 chunkReceived();
58 }
59 }
60
613 clientSocket.on('data', chunkReceived);
623 clientSocket.on('end', chunkReceived);
63 });
64
653 server.listen(config.loggerPort || 5000, config.loggerHost || 'localhost');
66
673 return actualAppender;
68}
69
706function workerAppender(config) {
713 var canWrite = false,
72 buffer = [],
73 socket;
74
753 createSocket();
76
773 function createSocket() {
785 socket = net.createConnection(config.loggerPort || 5000, config.loggerHost || 'localhost');
795 socket.on('connect', function() {
804 emptyBuffer();
814 canWrite = true;
82 });
835 socket.on('timeout', socket.end.bind(socket));
84 //don't bother listening for 'error', 'close' gets called after that anyway
855 socket.on('close', createSocket);
86 }
87
883 function emptyBuffer() {
894 var evt;
904 while ((evt = buffer.shift())) {
912 write(evt);
92 }
93 }
94
953 function write(loggingEvent) {
969 socket.write(JSON.stringify(loggingEvent), 'utf8');
979 socket.write(END_MSG, 'utf8');
98 }
99
1003 return function log(loggingEvent) {
1019 if (canWrite) {
1027 write(loggingEvent);
103 } else {
1042 buffer.push(loggingEvent);
105 }
106 };
107}
108
1096function createAppender(config) {
1106 if (config.mode === 'master') {
1113 return logServer(config);
112 } else {
1133 return workerAppender(config);
114 }
115}
116
1176function configure(config, options) {
1181 var actualAppender;
1191 if (config.appender && config.mode === 'master') {
1201 log4js.loadAppender(config.appender.type);
1211 actualAppender = log4js.appenderMakers[config.appender.type](config.appender, options);
1221 config.actualAppender = actualAppender;
123 }
1241 return createAppender(config);
125}
126
1276exports.appender = createAppender;
1286exports.configure = configure;

appenders/smtp.js

40
0
40
100%
LineHitsSource
06"use strict";
16var layouts = require("../layouts")
2, mailer = require("nodemailer")
3, os = require('os');
4
5/**
6* SMTP Appender. Sends logging events using SMTP protocol.
7* It can either send an email on each event or group several
8* logging events gathered during specified interval.
9*
10* @param config appender configuration data
11* config.sendInterval time between log emails (in seconds), if 0
12* then every event sends an email
13* @param layout a function that takes a logevent and returns a string (defaults to basicLayout).
14*/
156function smtpAppender(config, layout) {
166 layout = layout || layouts.basicLayout;
176 var subjectLayout = layouts.messagePassThroughLayout;
186 var sendInterval = config.sendInterval*1000 || 0;
19
206 var logEventBuffer = [];
216 var sendTimer;
22
236 function sendBuffer() {
248 if (logEventBuffer.length > 0) {
25
268 var transport = mailer.createTransport(config.transport, config[config.transport]);
278 var firstEvent = logEventBuffer[0];
288 var body = "";
298 while (logEventBuffer.length > 0) {
309 body += layout(logEventBuffer.shift()) + "\n";
31 }
32
338 var msg = {
34 to: config.recipients,
35 subject: config.subject || subjectLayout(firstEvent),
36 text: body,
37 headers: { "Hostname": os.hostname() }
38 };
398 if (config.sender) {
401 msg.from = config.sender;
41 }
428 transport.sendMail(msg, function(error, success) {
438 if (error) {
441 console.error("log4js.smtpAppender - Error happened", error);
45 }
468 transport.close();
47 });
48 }
49 }
50
516 function scheduleSend() {
523 if (!sendTimer) {
532 sendTimer = setTimeout(function() {
542 sendTimer = null;
552 sendBuffer();
56 }, sendInterval);
57 }
58 }
59
606 return function(loggingEvent) {
619 logEventBuffer.push(loggingEvent);
629 if (sendInterval > 0) {
633 scheduleSend();
64 } else {
656 sendBuffer();
66 }
67 };
68}
69
706function configure(config) {
716 var layout;
726 if (config.layout) {
731 layout = layouts.layout(config.layout.type, config.layout);
74 }
756 return smtpAppender(config, layout);
76}
77
786exports.name = "smtp";
796exports.appender = smtpAppender;
806exports.configure = configure;
81