Skip to content

Commit 74a6447

Browse files
committed
Merge remote branch 'upstream/master'
Conflicts: lib/appenders/smtp.js test/smtpAppender.js
2 parents 910b21a + c8157ce commit 74a6447

24 files changed

+1460
-381
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
*.log
22
*.log??
3+
build
4+
node_modules
5+

.travis.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
language: node_js
2+
node_js:
3+
- 0.4
4+
- 0.5
5+
- 0.6

README.md

+48-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# log4js-node
1+
# log4js-node [![Build Status](https://secure.travis-ci.org/nomiddlename/log4js-node.png?branch=master)](http://travis-ci.org/nomiddlename/log4js-node)
22

33
NOTE: v0.3.8 of log4js is the last that will work with node versions older than 0.4. To use v0.3.9 you will need node 0.4 or later.
44

@@ -73,6 +73,35 @@ To specify a different period:
7373

7474
You can also pass an object to the configure function, which has the same properties as the json versions.
7575

76+
For FileAppender you can also pass the path to the log directory as an option where all your log files would be stored.
77+
78+
log4js.configure('my_log4js_configuration.json', { cwd: '/absolute/path/to/log/dir' });
79+
80+
If you have already defined an absolute path for one of the FileAppenders in the configuration file, you could add a "absolute": true to the particular FileAppender to override the cwd option passed. Here is an example configuration file:
81+
82+
#### my_log4js_configuration.json ####
83+
{
84+
"appenders": [
85+
{
86+
"type": "file",
87+
"filename": "relative/path/to/log_file.log",
88+
"maxLogSize": 20480,
89+
"backups": 3,
90+
"pollInterval": 15,
91+
"category": "relative-logger"
92+
},
93+
{
94+
"type": "file",
95+
"absolute": true,
96+
"filename": "/absolute/path/to/log_file.log",
97+
"maxLogSize": 20480,
98+
"backups": 10,
99+
"pollInterval": 15,
100+
"category": "absolute-logger"
101+
}
102+
]
103+
}
104+
76105
## connect/express logger
77106

78107
A connect/express logger has been added to log4js, by [danbell](https://github.com/danbell). This allows connect/express servers to log using log4js. See example-connect-logger.js.
@@ -220,6 +249,24 @@ This was mainly created for [cluster](https://github.com/LearnBoost/cluster), bu
220249
.listen(3000);
221250
</pre>
222251

252+
## gelf logger
253+
254+
A gelf logger has been added to log4js, by [arifamirani](https://github.com/arifamirani). This allows log4js to log to [GELF](http://www.graylog2.org/about/gelf) compatible servers such as [Graylog](http://www.graylog2.org/). This is currently configuration based and needs the following configuration to be added to log4j.json. For example:
255+
256+
<pre>
257+
{
258+
"appenders": [
259+
{
260+
"type": "gelf",
261+
"host": "logs.mydomain.com", //defaults to localhost
262+
"hostname":"mrs-dev", //defaults to the value returned by os.hostname()
263+
"port": "12201", //defaults to 12201
264+
"facility": "myapp" //defaults to nodejs-server
265+
}
266+
}
267+
}
268+
</pre>
269+
223270
## author (of this node version)
224271

225272
Gareth Jones (csausdev - [email protected])

lib/appenders/console.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
var layouts = require('../layouts');
1+
var layouts = require('../layouts'),
2+
consoleLog = console.log;
23

34
function consoleAppender (layout) {
45
layout = layout || layouts.colouredLayout;
56
return function(loggingEvent) {
6-
console._preLog4js_log(layout(loggingEvent));
7+
consoleLog(layout(loggingEvent));
78
};
89
}
910

lib/appenders/file.js

+22-81
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
var layouts = require('../layouts')
2-
, fs = require('fs');
2+
, path = require('path')
3+
, fs = require('fs')
4+
, streams = require('../streams');
35

46
/**
57
* File Appender writing the logs to a text file. Supports rolling of logs by size.
@@ -8,104 +10,43 @@ var layouts = require('../layouts')
810
* @param layout a function that takes a logevent and returns a string (defaults to basicLayout).
911
* @param logSize - the maximum size (in bytes) for a log file, if not provided then logs won't be rotated.
1012
* @param numBackups - the number of log files to keep after logSize has been reached (default 5)
11-
* @param filePollInterval - the time in seconds between file size checks (default 30s)
1213
*/
13-
function fileAppender (file, layout, logSize, numBackups, filePollInterval) {
14+
function fileAppender (file, layout, logSize, numBackups) {
15+
var bytesWritten = 0;
16+
file = path.normalize(file);
1417
layout = layout || layouts.basicLayout;
1518
numBackups = numBackups === undefined ? 5 : numBackups;
1619
//there has to be at least one backup if logSize has been specified
1720
numBackups = numBackups === 0 ? 1 : numBackups;
18-
filePollInterval = filePollInterval * 1000 || 30000;
1921

20-
function setupLogRolling () {
21-
fs.watchFile(
22-
file,
23-
{
24-
persistent: false,
25-
interval: filePollInterval
26-
},
27-
function (curr, prev) {
28-
if (curr.size >= logSize) {
29-
rollThatLog();
30-
}
31-
}
32-
);
33-
}
34-
35-
function rollThatLog () {
36-
//roll the backups (rename file.n-1 to file.n, where n <= numBackups)
37-
for (var i=numBackups; i > 0; i--) {
38-
if (i > 1) {
39-
if (fileExists(file + '.' + (i-1))) {
40-
fs.renameSync(file+'.'+(i-1), file+'.'+i);
41-
}
42-
} else {
43-
fs.renameSync(file, file+'.1');
44-
}
45-
}
46-
//let's make a new file
47-
var newLogFileFD = fs.openSync(file, 'a', 0644)
48-
, oldLogFileFD = logFile.fd;
49-
logFile.fd = newLogFileFD;
50-
fs.close(oldLogFileFD);
51-
}
52-
53-
function fileExists (filename) {
54-
try {
55-
fs.statSync(filename);
56-
return true;
57-
} catch (e) {
58-
return false;
22+
function openTheStream(file, fileSize, numFiles) {
23+
var stream;
24+
if (fileSize) {
25+
stream = new streams.BufferedWriteStream(
26+
new streams.RollingFileStream(
27+
file,
28+
fileSize,
29+
numFiles
30+
)
31+
);
32+
} else {
33+
stream = new streams.BufferedWriteStream(fs.createWriteStream(file, { encoding: "utf8", mode: 0644, flags: 'a' }));
5934
}
60-
}
61-
62-
function openTheStream() {
63-
var stream = fs.createWriteStream(file, { flags: 'a', mode: 0644, encoding: 'utf8' });
64-
stream.on("open", function() {
65-
canWrite = true;
66-
while (logEventBuffer.length > 0 && canWrite) {
67-
canWrite = writeToLog(logEventBuffer.shift());
68-
}
69-
});
7035
stream.on("error", function (err) {
71-
console.error("log4js.fileAppender - Error happened ", err);
72-
});
73-
stream.on("drain", function() {
74-
canWrite = true;
75-
while (logEventBuffer.length > 0 && canWrite) {
76-
canWrite = writeToLog(logEventBuffer.shift());
77-
}
36+
console.error("log4js.fileAppender - Writing to file %s, error happened ", file, err);
7837
});
7938
return stream;
8039
}
8140

82-
83-
var logEventBuffer = []
84-
, canWrite = false
85-
, logFile = openTheStream();
86-
87-
if (logSize > 0) {
88-
setupLogRolling();
89-
}
41+
var logFile = openTheStream(file, logSize, numBackups);
9042

9143
//close the file on process exit.
9244
process.on('exit', function() {
9345
logFile.end();
94-
logFile.destroy();
9546
});
9647

97-
function writeToLog(loggingEvent) {
98-
return logFile.write(layout(loggingEvent)+'\n', "utf8");
99-
}
100-
10148
return function(loggingEvent) {
102-
//because the log stream is opened asynchronously, we don't want to write
103-
//until it is ready.
104-
if (canWrite) {
105-
canWrite = writeToLog(loggingEvent);
106-
} else {
107-
logEventBuffer.push(loggingEvent);
108-
}
49+
logFile.write(layout(loggingEvent)+'\n', "utf8");
10950
};
11051
}
11152

@@ -114,7 +55,7 @@ function configure(config) {
11455
if (config.layout) {
11556
layout = layouts.layout(config.layout.type, config.layout);
11657
}
117-
return fileAppender(config.filename, layout, config.maxLogSize, config.backups, config.pollInterval);
58+
return fileAppender(config.filename, layout, config.maxLogSize, config.backups);
11859
}
11960

12061
exports.name = "file";

lib/appenders/gelf.js

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
var compress = require('compress-buffer').compress;
2+
var layouts = require('../layouts');
3+
var levels = require('../levels');
4+
var dgram = require('dgram');
5+
var util = require('util');
6+
7+
var LOG_EMERG=0; // system is unusable
8+
var LOG_ALERT=1; // action must be taken immediately
9+
var LOG_CRIT=2; // critical conditions
10+
var LOG_ERR=3; // error conditions
11+
var LOG_ERROR=3; // because people WILL typo
12+
var LOG_WARNING=4; // warning conditions
13+
var LOG_NOTICE=5; // normal, but significant, condition
14+
var LOG_INFO=6; // informational message
15+
var LOG_DEBUG=7; // debug-level message
16+
17+
var levelMapping = {};
18+
levelMapping[levels.ALL] = LOG_DEBUG;
19+
levelMapping[levels.TRACE] = LOG_DEBUG;
20+
levelMapping[levels.DEBUG] = LOG_DEBUG;
21+
levelMapping[levels.INFO] = LOG_INFO;
22+
levelMapping[levels.WARN] = LOG_WARNING;
23+
levelMapping[levels.ERROR] = LOG_ERR;
24+
levelMapping[levels.FATAL] = LOG_CRIT;
25+
26+
/**
27+
* GELF appender that supports sending UDP packets to a GELF compatible server such as Graylog
28+
*
29+
* @param layout a function that takes a logevent and returns a string (defaults to none).
30+
* @param host - host to which to send logs (default:localhost)
31+
* @param port - port at which to send logs to (default:12201)
32+
* @param hostname - hostname of the current host (default:os hostname)
33+
* @param facility - facility to log to (default:nodejs-server)
34+
*/
35+
function gelfAppender (layout, host, port, hostname, facility) {
36+
37+
host = host || 'localhost';
38+
port = port || 12201;
39+
hostname = hostname || require('os').hostname();
40+
facility = facility || 'nodejs-server';
41+
layout = layout || layouts.messagePassThroughLayout;
42+
43+
var client = dgram.createSocket("udp4");
44+
45+
process.on('exit', function() {
46+
if (client) client.close();
47+
});
48+
49+
function preparePacket(loggingEvent) {
50+
var msg = {};
51+
msg.full_message = layout(loggingEvent);
52+
msg.short_message = msg.full_message;
53+
54+
msg.version="1.0";
55+
msg.timestamp = msg.timestamp || new Date().getTime() / 1000 >> 0;
56+
msg.host = hostname;
57+
msg.level = levelMapping[loggingEvent.level || levels.DEBUG];
58+
msg.facility = facility;
59+
return msg;
60+
}
61+
62+
function sendPacket(packet) {
63+
try {
64+
client.send(packet, 0, packet.length, port, host);
65+
} catch(e) {}
66+
}
67+
68+
return function(loggingEvent) {
69+
var message = preparePacket(loggingEvent);
70+
var packet = compress(new Buffer(JSON.stringify(message)));
71+
if (packet.length > 8192) {
72+
util.debug("Message packet length (" + packet.length + ") is larger than 8k. Not sending");
73+
} else {
74+
sendPacket(packet);
75+
}
76+
};
77+
}
78+
79+
function configure(config) {
80+
var layout;
81+
if (config.layout) {
82+
layout = layouts.layout(config.layout.type, config.layout);
83+
}
84+
return gelfAppender(layout, config.host, config.port, config.hostname, config.facility);
85+
}
86+
87+
exports.name = "gelf";
88+
exports.appender = gelfAppender;
89+
exports.configure = configure;

lib/appenders/smtp.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ var layouts = require("../layouts"),
1010
* @param subject subject of all email messages (defaults to first event's message)
1111
* @param layout a function that takes a logevent and returns a string (defaults to basicLayout).
1212
* @param smtpConfig SMTP configuration for 'nodemailer'
13-
* @param sendInterval the time in seconds between sending attempts (defualts to 0);
13+
* @param sendInterval the time in seconds between sending attempts (defaults to 0);
1414
* all events are buffered and sent in one email during this time; if 0 than every event sends an email
1515
*/
1616
function smtpAppender(recipients, sender, subject, layout, smtpConfig, sendInterval) {

lib/connect-logger.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,10 @@ function getLogger(logger4js, options) {
7979
thislogger.log(level, format(fmt, req, res));
8080
}
8181
};
82-
83-
next();
8482
}
83+
84+
//ensure next gets always called
85+
next();
8586
};
8687
}
8788

lib/levels.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ Level.prototype.toString = function() {
3131

3232
Level.prototype.isLessThanOrEqualTo = function(otherLevel) {
3333
if (typeof otherLevel === "string") {
34-
otherLevel = Level.toLevel(otherLevel);
34+
otherLevel = toLevel(otherLevel);
3535
}
3636
return this.level <= otherLevel.level;
3737
};
3838

3939
Level.prototype.isGreaterThanOrEqualTo = function(otherLevel) {
4040
if (typeof otherLevel === "string") {
41-
otherLevel = Level.toLevel(otherLevel);
41+
otherLevel = toLevel(otherLevel);
4242
}
4343
return this.level >= otherLevel.level;
4444
};

0 commit comments

Comments
 (0)