fix(logger): make console logging opt-in via ASK262_LOG_CONSOLE

Console output is now disabled by default. Set ASK262_LOG_CONSOLE=true
to enable pretty-printed logs routed to stderr. This prevents:
- Stdio MCP protocol corruption from stdout noise
- Noisy test output during bun test runs

Also fixes misleading comments about HTTP/stdio log level defaults.
This commit is contained in:
2026-04-27 16:59:16 +05:30
parent af1daab2a8
commit 30cd83f6d4
2 changed files with 28 additions and 15 deletions
+5 -1
View File
@@ -45,9 +45,13 @@ ASK262_EMBEDDING_PROVIDER=ollama
# ============================================================================= # =============================================================================
# Log level: trace, debug, info, warn, error # Log level: trace, debug, info, warn, error
# HTTP server defaults to 'debug', stdio server defaults to 'info' # Defaults to 'debug' for file logging when not set
# ASK262_LOG_LEVEL=info # ASK262_LOG_LEVEL=info
# Console logging is opt-in to avoid corrupting stdio MCP protocol and noisy tests.
# Set to 'true' to enable pretty-printed console output (goes to stderr).
# ASK262_LOG_CONSOLE=true
# Directory for log files (optional, defaults to ./logs) # Directory for log files (optional, defaults to ./logs)
# ASK262_LOG_DIR=./logs # ASK262_LOG_DIR=./logs
+18 -9
View File
@@ -115,7 +115,7 @@ export type LogComponent =
/** /**
* Get the file log level from environment. * Get the file log level from environment.
* HTTP server defaults to 'debug', stdio defaults to 'info'. * Defaults to 'debug' when ASK262_LOG_LEVEL is not set.
* *
* @returns The configured file log level * @returns The configured file log level
*/ */
@@ -124,7 +124,7 @@ function getFileLogLevel(): LogLevel {
if (envLevel && VALID_LOG_LEVELS.includes(envLevel as LogLevel)) { if (envLevel && VALID_LOG_LEVELS.includes(envLevel as LogLevel)) {
return envLevel as LogLevel; return envLevel as LogLevel;
} }
// Default: debug for HTTP, info for stdio // Default: debug (logs everything to file)
return "debug"; return "debug";
} }
@@ -186,7 +186,12 @@ const REDACT_FIELDS = [
/** /**
* Create the root Pino logger instance. * Create the root Pino logger instance.
* *
* @returns Configured Pino logger with dual transport * Console output is opt-in via ASK262_LOG_CONSOLE=true to avoid:
* - Corrupting stdio MCP protocol on stdout
* - Noisy test output when running under bun test
* When enabled, console logs are routed to stderr.
*
* @returns Configured Pino logger with file transport, and optional console
*/ */
async function createRootLogger(): Promise<pino.Logger> { async function createRootLogger(): Promise<pino.Logger> {
await ensureLogDir(); await ensureLogDir();
@@ -195,17 +200,24 @@ async function createRootLogger(): Promise<pino.Logger> {
const logFile = join(logDir, "ask262.jsonl"); const logFile = join(logDir, "ask262.jsonl");
const fileLevel = getFileLogLevel(); const fileLevel = getFileLogLevel();
const consoleLevel = getConsoleLogLevel();
// File transport: JSON Lines format, synchronous writes // File transport: JSON Lines format, synchronous writes
const fileStream = createWriteStream(logFile, { flags: "a" }); const fileStream = createWriteStream(logFile, { flags: "a" });
const streams: pino.StreamEntry[] = [
{ stream: fileStream, level: fileLevel },
];
// Console transport: Pretty printed // Console transport: opt-in only (ASK262_LOG_CONSOLE=true)
if (process.env.ASK262_LOG_CONSOLE === "true") {
const consoleLevel = getConsoleLogLevel();
const consoleStream = pretty({ const consoleStream = pretty({
colorize: true, colorize: true,
translateTime: "SYS:standard", translateTime: "SYS:standard",
ignore: "pid,hostname", ignore: "pid,hostname",
destination: process.stderr,
}); });
streams.push({ stream: consoleStream, level: consoleLevel });
}
return pino( return pino(
{ {
@@ -234,10 +246,7 @@ async function createRootLogger(): Promise<pino.Logger> {
}, },
timestamp: () => `,"timestamp":"${new Date().toISOString()}"`, timestamp: () => `,"timestamp":"${new Date().toISOString()}"`,
}, },
pino.multistream([ pino.multistream(streams),
{ stream: fileStream, level: fileLevel },
{ stream: consoleStream, level: consoleLevel },
]),
); );
} }