diff --git a/src/apps.js b/src/apps.js index 420853846..747064a90 100644 --- a/src/apps.js +++ b/src/apps.js @@ -2050,7 +2050,7 @@ async function getLogs(app, options) { const cp = logs.tail(logPaths, { lines: options.lines, follow: options.follow }); const logStream = new logs.LogStream({ format: options.format || 'json', source: appId }); - logStream.close = cp.terminate; // closing stream kills the child process + logStream.on('close', () => cp.terminate()); // the caller has to call destroy() on logStream. destroy() of Transform emits 'close' cp.stdout.pipe(logStream); diff --git a/src/logs.js b/src/logs.js index eb6d2fb3c..86662cca0 100644 --- a/src/logs.js +++ b/src/logs.js @@ -60,7 +60,7 @@ function tail(filePaths, options) { const args = [ LOGTAIL_CMD, '--lines=' + lines ]; if (options.follow) args.push('--follow'); - return shell.sudo('tail', args.concat(filePaths), { streamStdout: true }, function (e) { console.log(e); }); + return shell.sudo('tail', args.concat(filePaths), { streamStdout: true }, () => {}); } function journalctl(unit, options) { diff --git a/src/routes/apps.js b/src/routes/apps.js index 83267f99a..5f2889ce1 100644 --- a/src/routes/apps.js +++ b/src/routes/apps.js @@ -688,7 +688,7 @@ async function getLogStream(req, res, next) { 'Access-Control-Allow-Origin': '*' }); res.write('retry: 3000\n'); - res.on('close', logStream.close); + res.on('close', () => logStream.destroy()); logStream.on('data', function (data) { const obj = JSON.parse(data); const sse = `data: ${JSON.stringify(obj)}\n\n`; @@ -719,6 +719,7 @@ async function getLogs(req, res, next) { 'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no' // disable nginx buffering }); + res.on('close', () => logStream.destroy()); logStream.pipe(res); } diff --git a/src/routes/services.js b/src/routes/services.js index be609bf8f..32b02ee91 100644 --- a/src/routes/services.js +++ b/src/routes/services.js @@ -83,6 +83,7 @@ async function getLogs(req, res, next) { 'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no' // disable nginx buffering }); + res.on('close', () => logStream.destroy()); logStream.pipe(res); } @@ -112,7 +113,7 @@ async function getLogStream(req, res, next) { 'Access-Control-Allow-Origin': '*' }); res.write('retry: 3000\n'); - res.on('close', logStream.close); + res.on('close', () => logStream.destroy()); logStream.on('data', function (data) { const obj = JSON.parse(data); const sse = `data: ${JSON.stringify(obj)}\n\n`; diff --git a/src/routes/system.js b/src/routes/system.js index d6553784d..1a656695f 100644 --- a/src/routes/system.js +++ b/src/routes/system.js @@ -88,6 +88,7 @@ async function getLogs(req, res, next) { 'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no' // disable nginx buffering }); + res.on('close', () => logStream.destroy()); logStream.pipe(res); } @@ -118,7 +119,7 @@ async function getLogStream(req, res, next) { 'Access-Control-Allow-Origin': '*' }); res.write('retry: 3000\n'); - res.on('close', logStream.close); + res.on('close', () => logStream.destroy()); logStream.on('data', function (data) { const obj = JSON.parse(data); res.write(sse(obj.realtimeTimestamp, JSON.stringify(obj))); // send timestamp as id diff --git a/src/routes/tasks.js b/src/routes/tasks.js index 9239c7349..2c909940a 100644 --- a/src/routes/tasks.js +++ b/src/routes/tasks.js @@ -82,6 +82,7 @@ async function getLogs(req, res, next) { 'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no' // disable nginx buffering }); + res.on('close', () => logStream.destroy()); logStream.pipe(res); } @@ -113,7 +114,7 @@ async function getLogStream(req, res, next) { 'Access-Control-Allow-Origin': '*' }); res.write('retry: 3000\n'); - res.on('close', logStream.close); + res.on('close', () => logStream.destroy()); logStream.on('data', function (data) { const obj = JSON.parse(data); res.write(sse(obj.realtimeTimestamp, JSON.stringify(obj))); // send timestamp as id diff --git a/src/services.js b/src/services.js index 9c01a806e..851edc309 100644 --- a/src/services.js +++ b/src/services.js @@ -474,7 +474,7 @@ async function getServiceLogs(id, options) { } const logStream = new logs.LogStream({ format: options.format || 'json', source: name }); - logStream.close = cp.terminate; // closing stream kills the child process + logStream.on('close', () => cp.terminate()); // the caller has to call destroy() on logStream. destroy() of Transform emits 'close' cp.stdout.pipe(logStream); diff --git a/src/shell.js b/src/shell.js index 83100e816..57eadea2f 100644 --- a/src/shell.js +++ b/src/shell.js @@ -89,7 +89,11 @@ function sudo(tag, args, options, callback) { e.code = code; e.signal = signal; - debug(`${tag}: ${SUDO} ${spawnArgs.join(' ').replace(/\n/g, '\\n')} errored`, e); + if (cp.terminated) { + debug(`${tag}: ${SUDO} ${spawnArgs.join(' ').replace(/\n/g, '\\n')} terminated`); // was killed by us + } else { + debug(`${tag}: ${SUDO} ${spawnArgs.join(' ').replace(/\n/g, '\\n')} errored`, e); + } callback(e); }); @@ -107,6 +111,7 @@ function sudo(tag, args, options, callback) { // the workaround is to invoke a kill from a different process group and this is done by starting detached // another idea is: use "ps --pid cp.pid -o pid=" to get the pid of the command and then send it signal directly cp.terminate = function () { + cp.terminated = true; // hint for better debug message in 'exit' child_process.spawn('kill', ['-SIGTERM', cp.pid], { detached: true }, (error) => { if (error) debug(`${tag} could not terminate`, error); }); }; diff --git a/src/system.js b/src/system.js index 5add78ec7..75e243f94 100644 --- a/src/system.js +++ b/src/system.js @@ -321,7 +321,7 @@ async function getLogs(unit, options) { const cp = logs.tail([logFile], { lines: options.lines, follow: options.follow }); const logStream = new logs.LogStream({ format: options.format || 'json', source: unit }); - logStream.close = cp.terminate; // closing stream kills the child process + logStream.on('close', () => cp.terminate()); // the caller has to call destroy() on logStream. destroy() of Transform emits 'close' cp.stdout.pipe(logStream); diff --git a/src/tasks.js b/src/tasks.js index bfd839cda..ed9ccc848 100644 --- a/src/tasks.js +++ b/src/tasks.js @@ -277,7 +277,7 @@ async function getLogs(task, options) { const cp = logs.tail([`${paths.TASKS_LOG_DIR}/${task.id}.log`], { lines: options.lines, follow: options.follow }); const logStream = new logs.LogStream({ format: options.format || 'json', source: task.id }); - logStream.close = cp.terminate; // closing stream kills the child process + logStream.on('close', () => cp.terminate()); // the caller has to call destroy() on logStream. destroy() of Transform emits 'close' cp.stdout.pipe(logStream);