diff --git a/lib/appenders/gelf.js b/lib/appenders/gelf.js deleted file mode 100644 index 3b32915..0000000 --- a/lib/appenders/gelf.js +++ /dev/null @@ -1,141 +0,0 @@ -"use strict"; -var zlib = require('zlib'); -var layouts = require('../layouts'); -var levels = require('../levels'); -var dgram = require('dgram'); -var util = require('util'); -var debug = require('../debug')('GELF Appender'); - -var LOG_EMERG=0; // system is unusable -var LOG_ALERT=1; // action must be taken immediately -var LOG_CRIT=2; // critical conditions -var LOG_ERR=3; // error conditions -var LOG_ERROR=3; // because people WILL typo -var LOG_WARNING=4; // warning conditions -var LOG_NOTICE=5; // normal, but significant, condition -var LOG_INFO=6; // informational message -var LOG_DEBUG=7; // debug-level message - -var levelMapping = {}; -levelMapping[levels.ALL] = LOG_DEBUG; -levelMapping[levels.TRACE] = LOG_DEBUG; -levelMapping[levels.DEBUG] = LOG_DEBUG; -levelMapping[levels.INFO] = LOG_INFO; -levelMapping[levels.WARN] = LOG_WARNING; -levelMapping[levels.ERROR] = LOG_ERR; -levelMapping[levels.FATAL] = LOG_CRIT; - -/** - * GELF appender that supports sending UDP packets to a GELF compatible server such as Graylog - * - * @param layout a function that takes a logevent and returns a string (defaults to none). - * @param host - host to which to send logs (default:localhost) - * @param port - port at which to send logs to (default:12201) - * @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) { - 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; - - msg.version="1.0"; - msg.timestamp = msg.timestamp || new Date().getTime() / 1000 >> 0; - msg.host = hostname; - msg.level = levelMapping[loggingEvent.level || levels.DEBUG]; - msg.facility = facility; - return msg; - } - - function sendPacket(packet) { - try { - client.send(packet, 0, packet.length, port, host); - } catch(e) {} - } - - return function(loggingEvent) { - var message = preparePacket(loggingEvent); - zlib.gzip(new Buffer(JSON.stringify(message)), function(err, packet) { - if (err) { - console.error(err.stack); - } else { - if (packet.length > 8192) { - debug("Message packet length (" + packet.length + ") is larger than 8k. Not sending"); - } else { - sendPacket(packet); - } - } - }); - }; -} - -function configure(config) { - var layout; - if (config.layout) { - layout = layouts.layout(config.layout.type, config.layout); - } - return gelfAppender(layout, config); -} - -exports.appender = gelfAppender; -exports.configure = configure; diff --git a/test/gelfAppender-test.js b/test/gelfAppender-test.js deleted file mode 100644 index 4a1ff58..0000000 --- a/test/gelfAppender-test.js +++ /dev/null @@ -1,259 +0,0 @@ -"use strict"; -var vows = require('vows') -, assert = require('assert') -, sandbox = require('sandboxed-module') -, log4js = require('../lib/log4js') -, realLayouts = require('../lib/layouts') -, setupLogging = function(options, category, compressedLength) { - var fakeDgram = { - sent: false, - socket: { - packetLength: 0, - closed: false, - close: function() { - this.closed = true; - }, - send: function(pkt, offset, pktLength, port, host) { - fakeDgram.sent = true; - this.packet = pkt; - this.offset = offset; - this.packetLength = pktLength; - this.port = port; - this.host = host; - } - }, - createSocket: function(type) { - this.type = type; - return this.socket; - } - } - , fakeZlib = { - gzip: function(objectToCompress, callback) { - fakeZlib.uncompressed = objectToCompress; - if (this.shouldError) { - callback({ stack: "oh noes" }); - return; - } - - if (compressedLength) { - callback(null, { length: compressedLength }); - } else { - callback(null, "I've been compressed"); - } - } - } - , exitHandler - , fakeConsole = { - error: function(message) { - this.message = message; - } - } - , fakeLayouts = { - layout: function(type, options) { - this.type = type; - this.options = options; - return realLayouts.messagePassThroughLayout; - }, - messagePassThroughLayout: realLayouts.messagePassThroughLayout - } - , appender = sandbox.require('../lib/appenders/gelf', { - requires: { - dgram: fakeDgram, - zlib: fakeZlib, - '../layouts': fakeLayouts - }, - globals: { - process: { - on: function(evt, handler) { - if (evt === 'exit') { - exitHandler = handler; - } - } - }, - console: fakeConsole - } - }); - - log4js.clearAppenders(); - log4js.addAppender(appender.configure(options || {}), category || "gelf-test"); - return { - dgram: fakeDgram, - compress: fakeZlib, - exitHandler: exitHandler, - console: fakeConsole, - layouts: fakeLayouts, - logger: log4js.getLogger(category || "gelf-test") - }; -}; - -vows.describe('log4js gelfAppender').addBatch({ - - 'with default gelfAppender settings': { - topic: function() { - var setup = setupLogging(); - setup.logger.info("This is a test"); - return setup; - }, - 'the dgram packet': { - topic: function(setup) { - return setup.dgram; - }, - 'should be sent via udp to the localhost gelf server': function(dgram) { - assert.equal(dgram.type, "udp4"); - assert.equal(dgram.socket.host, "localhost"); - assert.equal(dgram.socket.port, 12201); - assert.equal(dgram.socket.offset, 0); - assert.ok(dgram.socket.packetLength > 0, "Received blank message"); - }, - 'should be compressed': function(dgram) { - assert.equal(dgram.socket.packet, "I've been compressed"); - } - }, - 'the uncompressed log message': { - topic: function(setup) { - var message = JSON.parse(setup.compress.uncompressed); - return message; - }, - 'should be in the gelf format': function(message) { - assert.equal(message.version, '1.0'); - assert.equal(message.host, require('os').hostname()); - assert.equal(message.level, 6); //INFO - assert.equal(message.facility, 'nodejs-server'); - assert.equal(message.full_message, message.short_message); - assert.equal(message.full_message, 'This is a test'); - } - } - }, - 'with a message longer than 8k': { - topic: function() { - var setup = setupLogging(undefined, undefined, 10240); - setup.logger.info("Blah."); - return setup; - }, - 'the dgram packet': { - topic: function(setup) { - return setup.dgram; - }, - 'should not be sent': function(dgram) { - assert.equal(dgram.sent, false); - } - } - }, - 'with non-default options': { - topic: function() { - var setup = setupLogging({ - host: 'somewhere', - port: 12345, - hostname: 'cheese', - facility: 'nonsense' - }); - setup.logger.debug("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'); - } - } - }, - - 'on process.exit': { - topic: function() { - var setup = setupLogging(); - setup.exitHandler(); - return setup; - }, - 'should close open sockets': function(setup) { - assert.isTrue(setup.dgram.socket.closed); - } - }, - - 'on zlib error': { - topic: function() { - var setup = setupLogging(); - setup.compress.shouldError = true; - setup.logger.info('whatever'); - return setup; - }, - 'should output to console.error': function(setup) { - assert.equal(setup.console.message, 'oh noes'); - } - }, - - 'with layout in configuration': { - topic: function() { - var setup = setupLogging({ - layout: { - type: 'madeuplayout', - earlgrey: 'yes, please' - } - }); - return setup; - }, - 'should pass options to layout': function(setup) { - 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);