logs: escape and unescape new lines

This commit is contained in:
Girish Ramakrishnan
2026-04-07 12:54:31 +02:00
parent 20e0774df2
commit 9e20c5a3e3
9 changed files with 25 additions and 10 deletions

View File

@@ -3221,3 +3221,5 @@
[9.2.0]
* apppasswords: generate easier to type passwords
* logs: escape and unescape new lines

6
box.js
View File

@@ -38,8 +38,10 @@ async function setupNetworking() {
function exitSync(status) {
const ts = new Date().toISOString();
if (status.message) fs.write(logFd, `${ts} ${status.message}\n`, function () {});
const msg = status.error.stack.replace(/\n/g, `\n${ts} `); // prefix each line with ts
if (status.error) fs.write(logFd, `${ts} ${msg}\n`, function () {});
if (status.error) {
const escapedStack = status.error.stack.replace(/\\/g, '\\\\').replace(/\n/g, '\\n');
fs.write(logFd, `${ts} ${escapedStack}\n`, function () {});
}
fs.fsyncSync(logFd);
fs.closeSync(logFd);
process.exit(status.code);

View File

@@ -209,7 +209,7 @@ body {
color: white;
font-family: monospace;
font-size: 14px;
white-space: nowrap;
white-space: pre-wrap;
width: 100%;
}

View File

@@ -82,7 +82,8 @@ export function create(type, id, options = {}) {
}
const time = data.realtimeTimestamp ? moment(data.realtimeTimestamp/1000).format('MMM DD HH:mm:ss') : '';
const html = ansiToHtml(escapeHtml(typeof data.message === 'string' ? data.message : ab2str(data.message)));
const escaped = ansiToHtml(escapeHtml(typeof data.message === 'string' ? data.message : ab2str(data.message)));
const html = escaped.replace(/\n/g, '<br>');
eventSource._lastMessage = { time, html };
lineHandler(time, html);

View File

@@ -1377,7 +1377,8 @@ async function appendLogLine(app, line) {
const logFilePath = path.join(paths.LOG_DIR, app.id, 'app.log');
const isoDate = new Date(new Date().toUTCString()).toISOString();
if (!safe.fs.appendFileSync(logFilePath, `${isoDate} ${line}\n`)) console.error(`Could not append log line for app ${app.id} at ${logFilePath}: ${safe.error.message}`);
const escaped = line.replace(/\\/g, '\\\\').replace(/\n/g, '\\n');
if (!safe.fs.appendFileSync(logFilePath, `${isoDate} ${escaped}\n`)) console.error(`Could not append log line for app ${app.id} at ${logFilePath}: ${safe.error.message}`);
}
async function checkManifest(manifest) {

View File

@@ -5,7 +5,8 @@ const LOG_ENABLED = process.env.BOX_ENV !== 'test' || !!process.env.LOG;
function output(namespace, args) {
const ts = new Date().toISOString();
process.stdout.write(`${ts} ${namespace}: ${util.format(...args)}\n`);
const msg = util.format(...args).replace(/\\/g, '\\\\').replace(/\n/g, '\\n');
process.stdout.write(`${ts} ${namespace}: ${msg}\n`);
}
export default function logger(namespace) {

View File

@@ -34,9 +34,12 @@ class LogStream extends TransformStream {
message = line.slice(data[0].length+1);
}
// unescape \\n → newline and \\\\ → backslash (writers escape newlines to keep one entry per line)
message = (message || line).replace(/\\(\\|n)/g, (_, c) => c === 'n' ? '\n' : '\\');
return JSON.stringify({
realtimeTimestamp: timestamp * 1000, // timestamp info can be missing (0) for app logs via logPaths
message: message || line, // send the line if message parsing failed
message: message,
source: this._options.source
}) + '\n';
}

View File

@@ -70,8 +70,12 @@ async function setupNetworking() {
// taskworker.sh forwards the exit code of the actual worker. It's either a raw signal number OR the exit code. So, choose exit codes > 31
// 50 - internal error , 70 - SIGTERM exit
function exitSync(status) {
if (status.error) fs.write(logFd, status.error.stack + '\n', function () {});
fs.write(logFd, `${(new Date()).toISOString()} Exiting with code ${status.code}\n`, function () {});
const ts = (new Date()).toISOString();
if (status.error) {
const escapedStack = status.error.stack.replace(/\\/g, '\\\\').replace(/\n/g, '\\n');
fs.write(logFd, `${ts} ${escapedStack}\n`, function () {});
}
fs.write(logFd, `${ts} Exiting with code ${status.code}\n`, function () {});
fs.fsyncSync(logFd);
fs.closeSync(logFd);
process.exit(status.code);

View File

@@ -59,7 +59,8 @@ async function start() {
try {
fs.mkdirSync(appLogDir, { recursive: true });
fs.appendFileSync(`${appLogDir}/app.log`, `${info.timestamp} ${info.message.trim()}\n`);
const escaped = info.message.trim().replace(/\\/g, '\\\\').replace(/\n/g, '\\n');
fs.appendFileSync(`${appLogDir}/app.log`, `${info.timestamp} ${escaped}\n`);
} catch (error) {
log(error);
}