#!/usr/bin/env node 'use strict'; exports = module.exports = { start, stop }; const debug = require('debug')('syslog:server'), fs = require('fs'), net = require('net'), path = require('path'), paths = require('./src/paths.js'), parser = require('nsyslog-parser'), util = require('util'); let gServer = null; async function start() { debug('=========================================='); debug(' Cloudron Syslog Daemon '); debug('=========================================='); gServer = net.createServer(); gServer.on('error', function (error) { console.error(`server error: ${error}`); }); gServer.on('connection', function (socket) { socket.on('data', function (msg) { const info = parser(msg.toString()); if (!info || !info.appName) return debug('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 appLogDir = path.join(paths.LOG_DIR, info.appName); try { fs.mkdirSync(appLogDir, { recursive: true }); fs.appendFileSync(`${appLogDir}/app.log`, info.ts.toISOString() + ' ' + message + '\n'); } catch (error) { console.error(error); } }); socket.on('error', function (error) { console.error(`socket error: ${error}`); }); }); await fs.promises.rm(paths.SYSLOG_SOCKET_FILE, { force: true }); await util.promisify(gServer.listen.bind(gServer))(paths.SYSLOG_SOCKET_FILE); debug(`Listening on ${paths.SYSLOG_SOCKET_FILE}`); } async function stop() { await fs.promises.rm(paths.SYSLOG_SOCKET_FILE, { force: true }); gServer.unref(); // TODO : cleanup client connections. otherwise server.close() won't return gServer = null; } async function main() { await start(); process.on('SIGTERM', async function () { debug('Received SIGTERM. Shutting down.'); await stop(); setTimeout(process.exit.bind(process), 1000); }); } if (require.main === module) { main(); }