(core) Update logging in sandbox code, and log tracebacks as single log messages.

Summary:
- Replace logger module by the standard module 'logging'.
- When a log message from the sandbox includes newlines (e.g. for tracebacks),
  keep those lines together in the Node log message.

  Previously each line was a different message, making it difficult to view
  tracebacks, particularly in prod where each line becomes a separate message
  object.

- Fix assorted lint errors.

Test Plan: Added a test for the log-line splitting and escaping logic.

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D3956
This commit is contained in:
Dmitry S
2023-07-18 11:20:02 -04:00
parent 7fd48364df
commit 534615dd50
46 changed files with 154 additions and 249 deletions

View File

@@ -279,7 +279,7 @@ export class NSandbox implements ISandbox {
if (!this._streamToSandbox) {
throw new Error('expected streamToSandbox to be configured');
}
const sandboxStderrLogger = sandboxUtil.makeLinePrefixer('Sandbox stderr: ', this._logMeta);
const sandboxStderrLogger = sandboxUtil.makeLogLinePrefixer('Sandbox stderr: ', this._logMeta);
this.childProc.stderr!.on('data', data => {
this._lastStderr = data;
sandboxStderrLogger(data);

View File

@@ -33,16 +33,32 @@ export const EXC = false;
* Binary data is encoded as with JSON.stringify.
*/
export function makeLinePrefixer(prefix: string, logMeta: object) {
return _makeLinePrefixer(prefix, logMeta, text => text.indexOf('\n'));
}
/**
* Same as makeLinePrefixer, but avoids splitting lines except when a line starts with '[', since
* the sandbox prefixes all log messages with "[LEVEL]" prefix.
*/
export function makeLogLinePrefixer(prefix: string, logMeta: object) {
return _makeLinePrefixer(prefix, logMeta, text => {
const newline = text.indexOf("\n[");
// If no next log message, split at the last newline. Any earlier newlines would be included.
return (newline !== -1) ? newline : text.lastIndexOf("\n");
});
}
function _makeLinePrefixer(prefix: string, logMeta: object, findLineEnd: (text: string) => number) {
let partial = '';
return (data: Uint8Array) => {
partial += MemBuffer.arrayToString(data);
let newline;
while ((newline = partial.indexOf("\n")) !== -1) {
while (partial && (newline = findLineEnd(partial)) !== -1) {
const line = partial.slice(0, newline);
partial = partial.slice(newline + 1);
// Escape some parts of the string by serializing it to JSON (without the quotes).
log.origLog('info', "%s%s", prefix,
JSON.stringify(line).slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'),
JSON.stringify(line).slice(1, -1).replace(/\\(['"\\])/g, '$1').replace(/\\n/g, '\n'),
logMeta);
}
};