Merge pull request #242 from marcelog/marcelog_logstash_udp_appender
adding logstash UDP appender
This commit is contained in:
commit
39ce97d140
@ -13,6 +13,7 @@ Out of the box it supports the following features:
|
|||||||
* GELF appender
|
* GELF appender
|
||||||
* hook.io appender
|
* hook.io appender
|
||||||
* Loggly appender
|
* Loggly appender
|
||||||
|
* Logstash UDP appender
|
||||||
* multiprocess appender (useful when you've got worker processes)
|
* multiprocess appender (useful when you've got worker processes)
|
||||||
* a logger for connect/express servers
|
* a logger for connect/express servers
|
||||||
* configurable log message layout/patterns
|
* configurable log message layout/patterns
|
||||||
|
39
examples/logstashUDP.js
Normal file
39
examples/logstashUDP.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
var log4js = require('../lib/log4js');
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sample logstash config:
|
||||||
|
udp {
|
||||||
|
codec => json
|
||||||
|
port => 10001
|
||||||
|
queue_size => 2
|
||||||
|
workers => 2
|
||||||
|
type => myAppType
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
log4js.configure({
|
||||||
|
"appenders": [
|
||||||
|
{
|
||||||
|
type: "console",
|
||||||
|
category: "myLogger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 10001,
|
||||||
|
"type": "logstashUDP",
|
||||||
|
"logType": "myAppType", // Optional, defaults to 'category'
|
||||||
|
"fields": { // Optional, will be added to the 'fields' object in logstash
|
||||||
|
"field1": "value1",
|
||||||
|
"field2": "value2"
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"type": "pattern",
|
||||||
|
"pattern": "%m"
|
||||||
|
},
|
||||||
|
"category": "myLogger"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
var logger = log4js.getLogger("myLogger");
|
||||||
|
logger.info("Test log message %s", "arg1", "arg2");
|
50
lib/appenders/logstashUDP.js
Normal file
50
lib/appenders/logstashUDP.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
"use strict";
|
||||||
|
var layouts = require('../layouts')
|
||||||
|
, dgram = require('dgram')
|
||||||
|
, util = require('util');
|
||||||
|
|
||||||
|
function logstashUDP (config, layout) {
|
||||||
|
var udp = dgram.createSocket('udp4');
|
||||||
|
var type = config.logType ? config.logType : config.category;
|
||||||
|
layout = layout || layouts.colouredLayout;
|
||||||
|
if(!config.fields) {
|
||||||
|
config.fields = {};
|
||||||
|
}
|
||||||
|
return function(loggingEvent) {
|
||||||
|
var logMessage = layout(loggingEvent);
|
||||||
|
var fields = {};
|
||||||
|
for(var i in config.fields) {
|
||||||
|
fields[i] = config.fields[i];
|
||||||
|
}
|
||||||
|
fields['level'] = loggingEvent.level.levelStr;
|
||||||
|
var logObject = {
|
||||||
|
'@timestamp': (new Date(loggingEvent.startTime)).toISOString(),
|
||||||
|
type: type,
|
||||||
|
message: logMessage,
|
||||||
|
fields: fields
|
||||||
|
};
|
||||||
|
sendLog(udp, config.host, config.port, logObject);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendLog(udp, host, port, logObject) {
|
||||||
|
var buffer = new Buffer(JSON.stringify(logObject));
|
||||||
|
udp.send(buffer, 0, buffer.length, port, host, function(err, bytes) {
|
||||||
|
if(err) {
|
||||||
|
console.error(
|
||||||
|
"log4js.logstashUDP - %s:%p Error: %s", host, port, util.inspect(err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function configure(config) {
|
||||||
|
var layout;
|
||||||
|
if (config.layout) {
|
||||||
|
layout = layouts.layout(config.layout.type, config.layout);
|
||||||
|
}
|
||||||
|
return logstashUDP(config, layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.appender = logstashUDP;
|
||||||
|
exports.configure = configure;
|
106
test/logstashUDP-test.js
Normal file
106
test/logstashUDP-test.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
"use strict";
|
||||||
|
var sys = require("sys");
|
||||||
|
var vows = require('vows')
|
||||||
|
, assert = require('assert')
|
||||||
|
, log4js = require('../lib/log4js')
|
||||||
|
, sandbox = require('sandboxed-module')
|
||||||
|
;
|
||||||
|
|
||||||
|
function setupLogging(category, options) {
|
||||||
|
var udpSent = {};
|
||||||
|
|
||||||
|
var fakeDgram = {
|
||||||
|
createSocket: function (type) {
|
||||||
|
return {
|
||||||
|
send: function(buffer, offset, length, port, host, callback) {
|
||||||
|
udpSent.date = new Date();
|
||||||
|
udpSent.host = host;
|
||||||
|
udpSent.port = port;
|
||||||
|
udpSent.length = length;
|
||||||
|
udpSent.offset = 0;
|
||||||
|
udpSent.buffer = buffer;
|
||||||
|
callback(undefined, length);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var logstashModule = sandbox.require('../lib/appenders/logstashUDP', {
|
||||||
|
requires: {
|
||||||
|
'dgram': fakeDgram
|
||||||
|
}
|
||||||
|
});
|
||||||
|
log4js.clearAppenders();
|
||||||
|
log4js.addAppender(logstashModule.configure(options), category);
|
||||||
|
|
||||||
|
return {
|
||||||
|
logger: log4js.getLogger(category),
|
||||||
|
results: udpSent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
vows.describe('logstashUDP appender').addBatch({
|
||||||
|
'when logging with logstash via UDP': {
|
||||||
|
topic: function() {
|
||||||
|
var setup = setupLogging('logstashUDP', {
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 10001,
|
||||||
|
"type": "logstashUDP",
|
||||||
|
"logType": "myAppType",
|
||||||
|
"category": "myLogger",
|
||||||
|
"fields": {
|
||||||
|
"field1": "value1",
|
||||||
|
"field2": "value2"
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"type": "pattern",
|
||||||
|
"pattern": "%m"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setup.logger.log('trace', 'Log event #1');
|
||||||
|
return setup;
|
||||||
|
},
|
||||||
|
'an UDP packet should be sent': function (topic) {
|
||||||
|
assert.equal(topic.results.host, "127.0.0.1");
|
||||||
|
assert.equal(topic.results.port, 10001);
|
||||||
|
assert.equal(topic.results.offset, 0);
|
||||||
|
var json = JSON.parse(topic.results.buffer.toString());
|
||||||
|
assert.equal(json.type, 'myAppType');
|
||||||
|
var fields = {
|
||||||
|
field1: 'value1',
|
||||||
|
field2: 'value2',
|
||||||
|
level: 'TRACE'
|
||||||
|
};
|
||||||
|
assert.equal(JSON.stringify(json.fields), JSON.stringify(fields));
|
||||||
|
assert.equal(json.message, 'Log event #1');
|
||||||
|
// Assert timestamp, up to hours resolution.
|
||||||
|
var date = new Date(json['@timestamp']);
|
||||||
|
assert.equal(
|
||||||
|
date.toISOString().substring(0, 14),
|
||||||
|
topic.results.date.toISOString().substring(0, 14)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
'when missing some options': {
|
||||||
|
topic: function() {
|
||||||
|
var setup = setupLogging('myLogger', {
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 10001,
|
||||||
|
"type": "logstashUDP",
|
||||||
|
"category": "myLogger",
|
||||||
|
"layout": {
|
||||||
|
"type": "pattern",
|
||||||
|
"pattern": "%m"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setup.logger.log('trace', 'Log event #1');
|
||||||
|
return setup;
|
||||||
|
},
|
||||||
|
'it sets some defaults': function (topic) {
|
||||||
|
var json = JSON.parse(topic.results.buffer.toString());
|
||||||
|
assert.equal(json.type, 'myLogger');
|
||||||
|
assert.equal(JSON.stringify(json.fields), JSON.stringify({'level': 'TRACE'}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).export(module);
|
Loading…
Reference in New Issue
Block a user