diff --git a/CHANGES b/CHANGES index f5d010744..c2460a223 100644 --- a/CHANGES +++ b/CHANGES @@ -2757,3 +2757,6 @@ * postgresql: fix bug in loading of contrib extensions * dashboard: use native slider element for app memory and cpu +[7.7.2] +* docker: use unix domain socket based logging instead of udp + diff --git a/setup/start/systemd/cloudron-syslog.service b/setup/start/systemd/cloudron-syslog.service index 83932d3a1..9dcc35f0d 100644 --- a/setup/start/systemd/cloudron-syslog.service +++ b/setup/start/systemd/cloudron-syslog.service @@ -3,9 +3,9 @@ Description=Cloudron Syslog After=network.target [Service] -ExecStart=/home/yellowtent/box/syslog/service.js +ExecStart=/home/yellowtent/box/syslog.js WorkingDirectory=/home/yellowtent/box -Environment="NODE_ENV=production" "DEBUG=syslog:*" +Environment="NODE_ENV=production" "DEBUG=syslog:*" "BOX_ENV=cloudron" Restart=always User=yellowtent Group=yellowtent diff --git a/syslog/syslog-test.js b/src/test/syslog-test.js similarity index 100% rename from syslog/syslog-test.js rename to src/test/syslog-test.js diff --git a/syslog.js b/syslog.js new file mode 100755 index 000000000..86bec7399 --- /dev/null +++ b/syslog.js @@ -0,0 +1,73 @@ +#!/usr/bin/env node + +'use strict'; + +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); + }); +} + +main(); diff --git a/syslog/.gitignore b/syslog/.gitignore deleted file mode 100644 index c2658d7d1..000000000 --- a/syslog/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ diff --git a/syslog/.jshintrc b/syslog/.jshintrc deleted file mode 100644 index 5be1df16e..000000000 --- a/syslog/.jshintrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "node": true, - "browser": true, - "unused": true, - "multistr": true, - "globalstrict": true, - "predef": [ "angular", "$" ], - "esnext": true -} diff --git a/syslog/server.js b/syslog/server.js deleted file mode 100644 index 41c411409..000000000 --- a/syslog/server.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -exports = module.exports = { - start, - stop -}; - -const LOG_FILENAME = 'app.log'; - -const assert = require('assert'), - debug = require('debug')('syslog:server'), - fs = require('fs'), - net = require('net'), - path = require('path'), - parser = require('nsyslog-parser'), - util = require('util'); - -let server = null; - -async function start(options) { - assert.strictEqual(typeof options, 'object'); - assert.strictEqual(typeof options.logFolder, 'string'); - - debug('=========================================='); - debug(' Cloudron Syslog Daemon '); - debug('=========================================='); - - server = net.createServer(); - - server.on('error', function (error) { - console.error(`server error: ${error}`); - }); - - server.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 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); - } - }); - - socket.on('error', function (error) { - console.error(`socket error: ${error}`); - }); - }); - - await fs.promises.rm('/home/yellowtent/platformdata/logs/syslog.sock', { force: true }); - await util.promisify(server.listen.bind(server))('/home/yellowtent/platformdata/logs/syslog.sock'); - - debug('Listening on syslog.sock'); -} - -async function stop() { - if (!server) return; - await util.promisify(server.close.bind(server))(); - server = null; -} diff --git a/syslog/service.js b/syslog/service.js deleted file mode 100755 index 20c14379b..000000000 --- a/syslog/service.js +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env node - -'use strict'; - -const server = require('./server.js'); - -const options = { - logFolder: '/home/yellowtent/platformdata/logs', -}; - -async function main() { - await server.start(options); -} - -main();