RPC: route logs to stderr to keep stdout JSON clean
This commit is contained in:
@@ -44,6 +44,7 @@ let cachedLogger: TsLogger<LogObj> | null = null;
|
|||||||
let cachedSettings: ResolvedSettings | null = null;
|
let cachedSettings: ResolvedSettings | null = null;
|
||||||
let overrideSettings: LoggerSettings | null = null;
|
let overrideSettings: LoggerSettings | null = null;
|
||||||
let consolePatched = false;
|
let consolePatched = false;
|
||||||
|
let forceConsoleToStderr = false;
|
||||||
|
|
||||||
function normalizeLevel(level?: string): Level {
|
function normalizeLevel(level?: string): Level {
|
||||||
if (isVerbose()) return "trace";
|
if (isVerbose()) return "trace";
|
||||||
@@ -183,6 +184,12 @@ export function resetLogger() {
|
|||||||
overrideSettings = null;
|
overrideSettings = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Route all console output (including tslog console writes) to stderr.
|
||||||
|
// This keeps stdout clean for RPC/JSON modes.
|
||||||
|
export function routeLogsToStderr(): void {
|
||||||
|
forceConsoleToStderr = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route console.* calls through pino while still emitting to stdout/stderr.
|
* Route console.* calls through pino while still emitting to stdout/stderr.
|
||||||
* This keeps user-facing output unchanged but guarantees every console call is captured in log files.
|
* This keeps user-facing output unchanged but guarantees every console call is captured in log files.
|
||||||
@@ -224,7 +231,15 @@ export function enableConsoleCapture(): void {
|
|||||||
} catch {
|
} catch {
|
||||||
// never block console output on logging failures
|
// never block console output on logging failures
|
||||||
}
|
}
|
||||||
orig.apply(console, args as []);
|
if (forceConsoleToStderr) {
|
||||||
|
const target =
|
||||||
|
level === "error" || level === "fatal" || level === "warn"
|
||||||
|
? process.stderr
|
||||||
|
: process.stderr; // in RPC/JSON mode, keep stdout clean
|
||||||
|
target.write(`${formatted}\n`);
|
||||||
|
} else {
|
||||||
|
orig.apply(console, args as []);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log = forward("info", original.log);
|
console.log = forward("info", original.log);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
listSystemPresence,
|
listSystemPresence,
|
||||||
updateSystemPresence,
|
updateSystemPresence,
|
||||||
} from "../infra/system-presence.js";
|
} from "../infra/system-presence.js";
|
||||||
|
import { routeLogsToStderr } from "../logging.js";
|
||||||
import { setHeartbeatsEnabled } from "../provider-web.js";
|
import { setHeartbeatsEnabled } from "../provider-web.js";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
|
|
||||||
@@ -28,6 +29,9 @@ export async function runRpcLoop(io: {
|
|||||||
input: Readable;
|
input: Readable;
|
||||||
output: Writable;
|
output: Writable;
|
||||||
}): Promise<RpcLoopHandles> {
|
}): Promise<RpcLoopHandles> {
|
||||||
|
// Keep stdout reserved for RPC JSON replies; send all other logs to stderr.
|
||||||
|
routeLogsToStderr();
|
||||||
|
|
||||||
const rl = createInterface({ input: io.input, crlfDelay: Infinity });
|
const rl = createInterface({ input: io.input, crlfDelay: Infinity });
|
||||||
|
|
||||||
const respond = (obj: unknown) => {
|
const respond = (obj: unknown) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user