UNPKG

log4js-logstash-tcp

Version:

This is a copy of the logstashUDP appender but instead sending via UDP send via TCP to avoid the maximum 64k bytes message size with the logstashUDP appender.

131 lines (103 loc) • 3.62 kB
"use strict"; const net = require("net"); const EventEmitter = require('events'); const DEFAULT_MAX_TCP_CONNECTIONS = 300; class TcpConnectionWrapper extends EventEmitter { constructor(host, port, config) { super(); this.connectionNotReadyRetryInterval = parseInt(config.connectionNotReadyRetryInterval || 500); this.connectionTimeout = parseInt(config.connectionTimeout || 5000); const self = this; this.connection = net.connect({ host: host, port: port }, function() { self.connected = true; }); this.connection.setTimeout(this.connectionTimeout); this.connection.on("timeout", () => {self.destroy()}); this.connection.on("close", () => {self.destroy()}); this.connection.on("error", (err) => { console.error(`logstash Error with the connection to ${host}:${port}. ${err}`); // From docs: "The close event will be called just after this one }); } send(logObject) { const message = ( (obj) => { if (typeof obj === "string") { return obj + "\n"; } else { return JSON.stringify(obj) + "\n"; } } )(logObject); this.realSend(message); } realSend(message) { const self = this; if(this.connected === true) { this.connection.write(message) } else { const timeout = setTimeout(() => { self.realSend(message); clearTimeout(timeout); }, this.connectionNotReadyRetryInterval); } } destroy(cb) { const self = this; this.connection.end(() => { self.connection.destroy(); if (typeof cb === "function") { cb(); } }); this.emit("destroy"); } } class TcpConnectionPool { constructor(config) { this.tcpConnections = {} if(config) this.config = config; else this.config = {}; if(!this.config.maxTcpConnections) { this.config.maxTcpConnections = DEFAULT_MAX_TCP_CONNECTIONS; } } send(host, port, logObject) { this._getTcpConnection(host, port).send(logObject); } _getTcpConnection(host, port) { const index = this._createIndexForTcpConnection(); return this.tcpConnections[index] || this._createTcpConnection(index, host, port); } _createTcpConnection(index, host, port) { const self = this; const tcpConnectionWrapper = new TcpConnectionWrapper(host, port, this.config); this.tcpConnections[index] = tcpConnectionWrapper; tcpConnectionWrapper.on("destroy", () => { delete self.tcpConnections[index]; }); return tcpConnectionWrapper; } _createIndexForTcpConnection() { return Math.floor( Math.random() * this.config.maxTcpConnections) % this.config.maxTcpConnections; } close(cb) { const connections = []; Object.keys(this.tcpConnections).forEach((index) => { connections.push(this.tcpConnections[index]); }); let completed = 0; const complete = () => { if (++completed >= connections.length) { if (typeof cb === "function") { cb(); } } }; for (const tcpConnectionWrapper of connections) { tcpConnectionWrapper.destroy(complete); } } } module.exports.TcpConnectionPool = TcpConnectionPool;