diff --git a/box.js b/box.js index 3275f81a0..624388fae 100755 --- a/box.js +++ b/box.js @@ -10,15 +10,29 @@ const dockerProxy = require('./src/dockerproxy.js'), safe = require('safetydance'), server = require('./src/server.js'); -function setupLogging() { +let logFd; + +async function setupLogging() { if (process.env.BOX_ENV === 'test') return; - const logfileStream = fs.createWriteStream(paths.BOX_LOG_FILE, { flags:'a' }); - process.stdout.write = process.stderr.write = logfileStream.write.bind(logfileStream); + logFd = fs.openSync(paths.BOX_LOG_FILE, 'a'); + // we used to write using a stream before but it caches internally and there is no way to flush it when things crash + process.stdout.write = process.stderr.write = function (...args) { + const callback = typeof args[args.length-1] === 'function' ? args.pop() : function () {}; // callback is required for fs.write + fs.write.apply(fs, [logFd, ...args, callback]); + }; +} + +// this is also used as the 'uncaughtException' handler which can only have synchronous functions +function exitSync(status) { + if (status.error) fs.write(logFd, status.error.stack + '\n', function () {}); + fs.fsyncSync(logFd); + fs.closeSync(logFd); + process.exit(status.code); } async function startServers() { - setupLogging(); + await setupLogging(); await server.start(); // do this first since it also inits the database await proxyAuth.start(); await ldap.start(); @@ -27,10 +41,7 @@ async function startServers() { async function main() { const [error] = await safe(startServers()); - if (error) { - console.log('Error starting server', error); - process.exit(1); - } + if (error) return exitSync({ error: new Error(`Error starting server: ${JSON.stringify(error)}`), code: 1 }); // require those here so that logging handler is already setup require('supererror'); @@ -56,10 +67,7 @@ async function main() { setTimeout(process.exit.bind(process), 3000); }); - process.on('uncaughtException', function (error) { - console.error((error && error.stack) ? error.stack : error); - setTimeout(process.exit.bind(process, 1), 3000); - }); + process.on('uncaughtException', (error) => exitSync({ error, code: 1 })); console.log(`Cloudron is up and running. Logs are at ${paths.BOX_LOG_FILE}`); // this goes to journalctl }