diff --git a/docs/tcp.md b/docs/tcp.md index 95438b8..9d5302b 100644 --- a/docs/tcp.md +++ b/docs/tcp.md @@ -7,6 +7,8 @@ The TCP appender sends log events to a master server over TCP sockets. It can be * `type` - `tcp` * `port` - `integer` (optional, defaults to `5000`) - the port to send to * `host` - `string` (optional, defaults to `localhost`) - the host/IP address to send to +* `endMsg` - `string` (optional, defaults to `__LOG4JS__`) - the delimiter that marks the end of a log message +* `layout` - `object` (optional, defaults to a serialized log event) - see [layouts](layouts.md) ## Example ```javascript diff --git a/lib/appenders/tcp.js b/lib/appenders/tcp.js index 38d3a41..dd24749 100644 --- a/lib/appenders/tcp.js +++ b/lib/appenders/tcp.js @@ -3,15 +3,16 @@ const debug = require('debug')('log4js:tcp'); const net = require('net'); -function appender(config) { +function appender(config, layout) { let canWrite = false; const buffer = []; let socket; let shutdownAttempts = 3; + let endMsg = '__LOG4JS__'; function write(loggingEvent) { debug('Writing log event to socket'); - canWrite = socket.write(`${loggingEvent.serialise()}__LOG4JS__`, 'utf8'); + canWrite = socket.write(`${layout(loggingEvent)}${endMsg}`, 'utf8'); } function emptyBuffer() { @@ -25,6 +26,7 @@ function appender(config) { function createSocket() { debug(`appender creating socket to ${config.host || 'localhost'}:${config.port || 5000}`); + endMsg = `${config.endMsg || '__LOG4JS__'}`; socket = net.createConnection(config.port || 5000, config.host || 'localhost'); socket.on('connect', () => { debug('socket connected'); @@ -68,9 +70,15 @@ function appender(config) { return log; } -function configure(config) { +function configure(config, layouts) { debug(`configure with config = ${config}`); - return appender(config); + let layout = function (loggingEvent) { + return loggingEvent.serialise(); + }; + if (config.layout) { + layout = layouts.layout(config.layout.type, config.layout); + } + return appender(config, layout); } module.exports.configure = configure; diff --git a/test/tap/tcp-appender-test.js b/test/tap/tcp-appender-test.js index 57a5667..0f855fd 100644 --- a/test/tap/tcp-appender-test.js +++ b/test/tap/tcp-appender-test.js @@ -3,39 +3,57 @@ const net = require("net"); const log4js = require("../../lib/log4js"); const LoggingEvent = require("../../lib/LoggingEvent"); -const messages = []; -const server = net.createServer(socket => { - socket.setEncoding("utf8"); - socket.on("data", data => { - data - .split("__LOG4JS__") - .filter(s => s.length) - .forEach(s => { - messages.push(LoggingEvent.deserialise(s)); - }); +let messages = []; +let server = null; + +function makeServer(config) { + + server = net.createServer(socket => { + socket.setEncoding("utf8"); + + socket.on("data", data => { + data + .split(config.endMsg) + .filter(s => s.length) + .forEach(s => { + messages.push(config.deserialise(s)); + }); + }); }); -}); -server.unref(); + server.unref(); -server.listen(() => { - const { port } = server.address(); - log4js.configure({ - appenders: { - tcp: { type: "tcp", port } - }, - categories: { - default: { appenders: ["tcp"], level: "debug" } + return server; +} + +test("TCP Appender", batch => { + + batch.test("Default Configuration", t => { + messages = []; + + const serverConfig = { + endMsg: "__LOG4JS__", + deserialise: (log) => { return LoggingEvent.deserialise(log); } } - }); + server = makeServer(serverConfig); - const logger = log4js.getLogger(); - logger.info("This should be sent via TCP."); - logger.info("This should also be sent via TCP and not break things."); - log4js.shutdown(() => { - server.close(() => { - test("TCP Appender", batch => { - batch.test("should send log messages as JSON over TCP", t => { + server.listen(() => { + const { port } = server.address(); + log4js.configure({ + appenders: { + default: { type: "tcp", port }, + }, + categories: { + default: { appenders: ["default"], level: "debug" }, + } + }); + + const logger = log4js.getLogger(); + logger.info("This should be sent via TCP."); + logger.info("This should also be sent via TCP and not break things."); + + log4js.shutdown(() => { + server.close(() => { t.equal(messages.length, 2); t.match(messages[0], { data: ["This should be sent via TCP."], @@ -51,8 +69,109 @@ server.listen(() => { }); t.end(); }); - batch.end(); }); }); }); + + batch.test("Custom EndMessage String", t => { + messages = []; + + const serverConfig = { + endMsg: "\n", + deserialise: (log) => { return LoggingEvent.deserialise(log); } + } + server = makeServer(serverConfig); + + server.listen(() => { + const { port } = server.address(); + log4js.configure({ + appenders: { + customEndMsg: { type: "tcp", port, endMsg: "\n" }, + }, + categories: { + default: { appenders: ["customEndMsg"], level: "debug" }, + } + }); + + const logger = log4js.getLogger(); + logger.info("This should be sent via TCP using a custom EndMsg string."); + logger.info("This should also be sent via TCP using a custom EndMsg string and not break things."); + + log4js.shutdown(() => { + server.close(() => { + t.equal(messages.length, 2); + t.match(messages[0], { + data: ["This should be sent via TCP using a custom EndMsg string."], + categoryName: "default", + context: {}, + level: { levelStr: "INFO" } + }); + t.match(messages[1], { + data: ["This should also be sent via TCP using a custom EndMsg string and not break things."], + categoryName: "default", + context: {}, + level: { levelStr: "INFO" } + }); + t.end(); + }); + }); + }); + }); + + + batch.test("Custom Layout", t => { + messages = []; + + const serverConfig = { + endMsg: "__LOG4JS__", + deserialise: (log) => { return JSON.parse(log); } + } + server = makeServer(serverConfig); + + log4js.addLayout('json', function () { + return function (logEvent) { + return JSON.stringify({ + "time": logEvent.startTime, + "message": logEvent.data[0], + "level": logEvent.level.toString() + }); + } + }); + + server.listen(() => { + const { port } = server.address(); + log4js.configure({ + appenders: { + customLayout: { + type: "tcp", port, + layout: { type: 'json' } + }, + }, + categories: { + default: { appenders: ["customLayout"], level: "debug" }, + } + }); + + const logger = log4js.getLogger(); + logger.info("This should be sent as a customized json."); + logger.info("This should also be sent via TCP as a customized json and not break things."); + + log4js.shutdown(() => { + server.close(() => { + t.equal(messages.length, 2); + t.match(messages[0], { + message: "This should be sent as a customized json.", + level: "INFO" + }); + t.match(messages[1], { + message: "This should also be sent via TCP as a customized json and not break things.", + level: "INFO" + }); + t.end(); + }); + }); + }); + }); + + batch.end(); });