diff --git a/lib/appenders/gelf.js b/lib/appenders/gelf.js index 4599856..3b32915 100644 --- a/lib/appenders/gelf.js +++ b/lib/appenders/gelf.js @@ -35,21 +35,67 @@ levelMapping[levels.FATAL] = LOG_CRIT; * @param facility - facility to log to (default:nodejs-server) */ function gelfAppender (layout, host, port, hostname, facility) { + var config, customFields; + if (typeof(host) === 'object') { + config = host; + host = config.host; + port = config.port; + hostname = config.hostname; + facility = config.facility; + customFields = config.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, + * copy the underscore fields to the message + * @param loggingEvent + * @param msg + */ + function addCustomFields(loggingEvent, msg){ + + /* append defaultCustomFields firsts */ + Object.keys(defaultCustomFields).forEach(function(key) { + // skip _id field for graylog2, skip keys not starts with UNDERSCORE + if (key.match(/^_/) && key !== "_id") { + 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 + Object.keys(firstData).forEach(function(key) { + // skip _id field for graylog2, skip keys not starts with UNDERSCORE + if (key.match(/^_/) || key !== "_id") { + 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 +134,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); } exports.appender = gelfAppender; diff --git a/test/gelfAppender-test.js b/test/gelfAppender-test.js index a79988e..4a1ff58 100644 --- a/test/gelfAppender-test.js +++ b/test/gelfAppender-test.js @@ -208,5 +208,52 @@ vows.describe('log4js gelfAppender').addBatch({ assert.equal(setup.layouts.type, 'madeuplayout'); assert.equal(setup.layouts.options.earlgrey, 'yes, please'); } + }, + + '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);