diff --git a/lib/appenders/gelf.js b/lib/appenders/gelf.js index 4599856..0a731db 100644 --- a/lib/appenders/gelf.js +++ b/lib/appenders/gelf.js @@ -34,22 +34,61 @@ levelMapping[levels.FATAL] = LOG_CRIT; * @param hostname - hostname of the current host (default:os hostname) * @param facility - facility to log to (default:nodejs-server) */ -function gelfAppender (layout, host, port, hostname, facility) { +function gelfAppender (layout, host, port, hostname, facility, customFields) { host = host || 'localhost'; port = port || 12201; hostname = hostname || require('os').hostname(); facility = facility || 'nodejs-server'; layout = layout || layouts.messagePassThroughLayout; + + var defaultCustomFields = customFields || {}; var client = dgram.createSocket("udp4"); process.on('exit', function() { if (client) client.close(); }); - + + /** + * Add custom fields (start with underscore ) + * - if the first object passed to the logger contains 'GELF' field, add copy the underscore fields to the message + * @param loggingEvent + * @param msg + */ + function addCustomFields(loggingEvent, msg){ + + /* append defaultCustomFields firsts */ + var keys = Object.keys(defaultCustomFields); + for (var i in keys){ + var key = keys[i]; + // skip _id field for graylog2, skip keys not starts with UNDERSCORE + if (!key.match(/^_/) || key === "_id") continue; + msg[key] = defaultCustomFields[key]; + } + + + /* append custom fields per message */ + var data = loggingEvent.data; + if (!Array.isArray(data) || data.length === 0) return; + var firstData = data[0]; + + if (!firstData['GELF']) return; // identify with GELF field defined + var keys = Object.keys(firstData); + for (var i in keys){ + var key = keys[i]; + // skip _id field for graylog2, skip keys not starts with UNDERSCORE + if (!key.match(/^_/) || key === "_id") continue; + msg[key] = firstData[key]; + } + + /* the custom field object should be removed, so it will not be looged by the later appenders */ + loggingEvent.data.shift(); + } + function preparePacket(loggingEvent) { var msg = {}; + addCustomFields(loggingEvent, msg); msg.full_message = layout(loggingEvent); msg.short_message = msg.full_message; @@ -88,7 +127,7 @@ function configure(config) { if (config.layout) { layout = layouts.layout(config.layout.type, config.layout); } - return gelfAppender(layout, config.host, config.port, config.hostname, config.facility); + return gelfAppender(layout, config.host, config.port, config.hostname, config.facility, config.customFields); } exports.appender = gelfAppender; diff --git a/test/gelfAppender-test.js b/test/gelfAppender-test.js index 1f45f33..7a0541b 100644 --- a/test/gelfAppender-test.js +++ b/test/gelfAppender-test.js @@ -135,5 +135,51 @@ vows.describe('log4js gelfAppender').addBatch({ assert.equal(message.facility, 'nonsense'); } } + }, + 'with custom fields options': { + topic: function() { + var setup = setupLogging({ + host: 'somewhere', + port: 12345, + hostname: 'cheese', + facility: 'nonsense', + customFields: { + _every1: 'Hello every one', + _every2: 'Hello every two' + } + }); + var myFields = { + GELF: true, + _every2: 'Overwritten!', + _myField: 'This is my field!' + }; + setup.logger.debug(myFields, "Just testing."); + return setup; + }, + 'the dgram packet': { + topic: function(setup) { + return setup.dgram; + }, + 'should pick up the options': function(dgram) { + assert.equal(dgram.socket.host, 'somewhere'); + assert.equal(dgram.socket.port, 12345); + } + }, + 'the uncompressed packet': { + topic: function(setup) { + var message = JSON.parse(setup.compress.uncompressed); + return message; + }, + 'should pick up the options': function(message) { + assert.equal(message.host, 'cheese'); + assert.equal(message.facility, 'nonsense'); + assert.equal(message._every1, 'Hello every one'); // the default value + assert.equal(message._every2, 'Overwritten!'); // the overwritten value + assert.equal(message._myField, 'This is my field!'); // the value for this message only + assert.equal(message.short_message, 'Just testing.'); // skip the field object + assert.equal(message.full_message, 'Just testing.'); // should be as same as short_message + } + } } + }).export(module);