Compare commits

...

5 Commits

Author SHA1 Message Date
Girish Ramakrishnan
2f2a832db1 Version 1.1.0 2022-01-13 16:26:14 -08:00
Girish Ramakrishnan
a0d9f7fe75 Update packages 2022-01-13 16:25:43 -08:00
Johannes Zellner
af89e04c89 Update to fixed nsyslog-parser node module 2018-06-25 19:30:05 +02:00
Johannes Zellner
123a11ee9d add some test description 2018-06-25 00:37:47 +02:00
Johannes Zellner
3a22716df6 Add some initial test cases 2018-06-25 00:28:42 +02:00
5 changed files with 1712 additions and 308 deletions

View File

@@ -2,20 +2,17 @@
'use strict';
var dgram = require('dgram'),
fs = require('fs'),
path = require('path'),
mkdirp = require('mkdirp'),
parser = require('nsyslog-parser');
const server = require('./server.js');
const argv = require('yargs')
.default('port', 2514, 'The port to listen on') // syslog is 514 so we prefix with 2
.default('logdir', '/tmp/logs', 'The root log directory')
.argv;
const LOG_FILE_FOLDER = argv.logdir;
const LOG_FILE_NAME = 'app.log';
const PORT = argv.port;
const options = {
logFolder: argv.logdir,
port: argv.port
};
if (argv.version) {
console.log('1.0.1');
@@ -27,34 +24,13 @@ console.log('==========================================');
console.log(' Cloudron Syslog Daemon ');
console.log('==========================================');
console.log();
console.log(' Log Folder: ', LOG_FILE_FOLDER);
console.log(' UDP Port: ', PORT);
console.log(' Log Folder: ', options.logFolder);
console.log(' UDP Port: ', options.port);
console.log();
console.log('==========================================');
console.log();
var server = dgram.createSocket('udp4');
server.on('error', function (error) {
console.error('Error:', error);
}).on('listening', function () {
server.start(options, function (error) {
if (error) return console.error(error);
console.log('Listening...');
}).on('message', function (msg, rinfo) {
var info = parser(msg.toString());
if (!info || !info.appName) return console.log('Ignore unknown app log:', msg.toString());
// remove line breaks to avoid holes in the log file
// we do not ignore empty log lines, to allow gaps for potential ease of readability
const message = info.message.replace(/\n/g, '');
const filePath = path.join(LOG_FILE_FOLDER, info.appName);
const fileName = path.join(filePath, LOG_FILE_NAME);
try {
mkdirp.sync(filePath);
fs.appendFileSync(fileName, info.ts.toISOString() + ' ' + message + '\n');
} catch (error) {
console.error(error);
}
}).bind(PORT);
});

1812
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,10 @@
{
"name": "cloudron-syslog",
"version": "1.0.2",
"version": "1.1.0",
"description": "Cloudron Syslog Daemon listening on port 2514",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "./node_modules/.bin/mocha ./test.js"
},
"bin": {
"cloudron-syslog": "./index.js"
@@ -16,8 +16,12 @@
"author": "Cloudron Developers",
"license": "MIT",
"dependencies": {
"mkdirp": "^0.5.1",
"nsyslog-parser": "^0.8.1",
"yargs": "^11.0.0"
"nsyslog-parser": "^0.9.6",
"yargs": "^17.3.1"
},
"devDependencies": {
"expect.js": "^0.3.1",
"grepit": "^1.0.0",
"mocha": "^9.1.3"
}
}

61
server.js Normal file
View File

@@ -0,0 +1,61 @@
'use strict';
exports = module.exports = {
start,
stop
};
const LOG_FILENAME = 'app.log';
const assert = require('assert'),
dgram = require('dgram'),
fs = require('fs'),
path = require('path'),
parser = require('nsyslog-parser');
let server = null;
function start(options, callback) {
assert.strictEqual(typeof options, 'object');
assert.strictEqual(typeof options.port, 'number');
assert.strictEqual(typeof options.logFolder, 'string');
assert.strictEqual(typeof callback, 'function');
server = dgram.createSocket('udp4');
server.on('error', function (error) {
callback(error);
}).on('listening', function () {
callback();
}).on('message', function (msg /*, rinfo */) {
const info = parser(msg.toString());
if (!info || !info.appName) return console.log('Ignore unknown app log:', msg.toString());
// remove line breaks to avoid holes in the log file
// we do not ignore empty log lines, to allow gaps for potential ease of readability
const message = info.message.replace(/\n/g, '');
const filePath = path.join(options.logFolder, info.appName);
const fileName = path.join(filePath, LOG_FILENAME);
try {
fs.mkdirSync(filePath, { recursive: true });
fs.appendFileSync(fileName, info.ts.toISOString() + ' ' + message + '\n');
} catch (error) {
console.error(error);
}
}).bind(options.port);
}
function stop(callback) {
assert.strictEqual(typeof callback, 'function');
if (!server) return callback();
server.close();
server = null;
callback();
}

89
test.js Normal file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/env node
/* global it:false */
/* global describe:false */
/* global after:false */
'use strict';
const dgram = require('dgram'),
expect = require('expect.js'),
fs = require('fs'),
grepit = require('grepit'),
path = require('path'),
os = require('os'),
server = require('./server.js');
const PORT = 5678;
const LOG_FOLDER = path.join(os.tmpdir(), '/cloudron-syslog-test/');
function sendMessage(message, callback) {
const client = dgram.createSocket('udp4');
client.send(message, PORT, 'localhost', function (error) {
if (error) return callback(error);
client.close();
callback();
});
}
function verifyMessage(pattern, fileName, callback) {
// give the server some time to write to disk
setTimeout(function () {
const found = grepit(pattern, path.join(LOG_FOLDER, fileName));
if (found.length === 0) return callback('not found');
callback();
}, 250);
}
describe('Daemon', function () {
this.timeout(5000);
after(function (done) {
fs.rmSync(LOG_FOLDER, { recursive: true, force: true });
server.stop(done);
});
it('can start', function (done) {
server.start({ port: PORT, logFolder: LOG_FOLDER }, function (error) {
expect(error).to.not.be.ok();
done();
});
});
it('handle good message', function (done) {
// IETF (RFC 5424) message, with structured data and chained hostnames
const ietfLine = '<110>1 2009-05-03T14:00:39.529966+02:00 host.example.org/relay.example.org testapp 2138 - [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"][exampleSDID@32474 iut="4" eventSource="Application" eventID="1012"][ssign VER="0111" RSID="1" SG="0" SPRI="0" GBC="2" FMN="1" CNT="7" HB="K6wzcombEvKJ+UTMcn9bPryAeaU= zrkDcIeaDluypaPCY8WWzwHpPok= zgrWOdpx16ADc7UmckyIFY53icE= XfopJ+S8/hODapiBBCgVQaLqBKg= J67gKMFl/OauTC20ibbydwIlJC8= M5GziVgB6KPY3ERU1HXdSi2vtdw= Wxd/lU7uG/ipEYT9xeqnsfohyH0=" SIGN="AKBbX4J7QkrwuwdbV7Taujk2lvOf8gCgC62We1QYfnrNHz7FzAvdySuMyfM="] BOMAn application event log entry';
sendMessage(ietfLine, function (error) {
expect(error).to.not.be.ok();
verifyMessage(/An application event log entry/, 'testapp/app.log', done);
});
});
it('ignores invalid message', function (done) {
const invalidLine = 'foobar';
sendMessage(invalidLine, function (error) {
expect(error).to.not.be.ok();
verifyMessage(/foobar/, 'testapp/app.log', function (error) {
expect(error).to.be.ok();
done();
});
});
});
it('can handle message with :', function (done) {
// this is what we see from docker syslog
const message = '<30>1 2018-06-24T22:22:53Z my.test.com testapp 26599 testapp - This: contains two : colons';
sendMessage(message, function (error) {
expect(error).to.not.be.ok();
verifyMessage(/This: contains two : colons/, 'testapp/app.log', done);
});
});
});