diff --git a/README.md b/README.md index 6e479d6..7cfbb0f 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Out of the box it supports the following features: * SMTP appender * GELF appender * hook.io appender +* Loggly appender * multiprocess appender (useful when you've got worker processes) * a logger for connect/express servers * configurable log message layout/patterns diff --git a/examples/loggly-appender.js b/examples/loggly-appender.js new file mode 100644 index 0000000..1465c92 --- /dev/null +++ b/examples/loggly-appender.js @@ -0,0 +1,24 @@ +//Note that loggly appender needs node-loggly to work. +//If you haven't got node-loggly installed, you'll get cryptic +//"cannot find module" errors when using the loggly appender +var log4js = require('../lib/log4js'); + +log4js.configure({ + "appenders": [ + { + type: "console", + category: "test" + }, + { + "type" : "loggly", + "token" : "12345678901234567890", + "subdomain": "your-subdomain", + "tags" : ["test"], + "category" : "loggly" + } + ] +}); + +var logger = log4js.getLogger("loggly"); +logger.info("Test log message"); +//logger.debug("Test log message"); \ No newline at end of file diff --git a/lib/appenders/loggly.js b/lib/appenders/loggly.js new file mode 100644 index 0000000..2b9efd4 --- /dev/null +++ b/lib/appenders/loggly.js @@ -0,0 +1,37 @@ +"use strict"; +var layouts = require("../layouts") +, loggly = require("loggly") +, os = require('os'); + +/** + * Loggly Appender. Sends logging events to Loggly using node-loggly + * + * @param config object with loggly configuration data + * { + * token: 'your-really-long-input-token', + * subdomain: 'your-subdomain', + * tags: ['loggly-tag1', 'loggly-tag2', .., 'loggly-tagn'] + * } + * @param layout a function that takes a logevent and returns a string (defaults to basicLayout). + */ +function logglyAppender(config, layout) { + layout = layout || layouts.basicLayout; + + var client = loggly.createClient(config); + + return function(loggingEvent) { + client.log(layout(loggingEvent), config.tags); + }; +} + +function configure(config) { + var layout; + if (config.layout) { + layout = layouts.layout(config.layout.type, config.layout); + } + return logglyAppender(config, layout); +} + +exports.name = "loggly"; +exports.appender = logglyAppender; +exports.configure = configure; \ No newline at end of file diff --git a/test/logglyAppender-test.js b/test/logglyAppender-test.js new file mode 100644 index 0000000..7be81e3 --- /dev/null +++ b/test/logglyAppender-test.js @@ -0,0 +1,82 @@ +"use strict"; +var vows = require('vows') +, assert = require('assert') +, log4js = require('../lib/log4js') +, sandbox = require('sandboxed-module') +; + +function setupLogging(category, options) { + var msgs = []; + + var fakeLoggly = { + createClient: function (options) { + return { + config: options, + log: function (msg, tags) { + msgs.push({ + msg: msg, + tags: tags + }); + } + }; + } + }; + + var fakeLayouts = { + layout: function(type, config) { + this.type = type; + this.config = config; + return log4js.layouts.messagePassThroughLayout; + }, + basicLayout: log4js.layouts.basicLayout, + messagePassThroughLayout: log4js.layouts.messagePassThroughLayout + }; + + var fakeConsole = { + errors: [], + error: function(msg, value) { + this.errors.push({ msg: msg, value: value }); + } + }; + + var logglyModule = sandbox.require('../lib/appenders/loggly', { + requires: { + 'loggly': fakeLoggly, + '../layouts': fakeLayouts + }, + globals: { + console: fakeConsole + } + }); + + log4js.addAppender(logglyModule.configure(options), category); + + return { + logger: log4js.getLogger(category), + loggly: fakeLoggly, + layouts: fakeLayouts, + console: fakeConsole, + results: msgs + }; +} + +log4js.clearAppenders(); +vows.describe('log4js logglyAppender').addBatch({ + 'minimal config': { + topic: function() { + var setup = setupLogging('loggly', { + token: 'your-really-long-input-token', + subdomain: 'your-subdomain', + tags: ['loggly-tag1', 'loggly-tag2', 'loggly-tagn'] + }); + + setup.logger.log('Log event #1'); + return setup; + }, + 'there should be one message only': function (topic) { + //console.log('topic', topic); + assert.equal(topic.results.length, 1); + } + } + +}).export(module);