logging: route console output into pino

This commit is contained in:
Peter Steinberger
2025-12-03 13:07:47 +00:00
parent 7ea43b0145
commit 4c3635a7c0
2 changed files with 59 additions and 1 deletions

View File

@@ -7,6 +7,7 @@ import {
autoReplyIfConfigured,
getReplyFromConfig,
} from "./auto-reply/reply.js";
import { enableConsoleCapture } from "./logging.js";
import { applyTemplate } from "./auto-reply/templating.js";
import { createDefaultDeps, monitorTwilio } from "./cli/deps.js";
import { promptYesNo } from "./cli/prompt.js";
@@ -56,6 +57,9 @@ import { assertProvider, normalizeE164, toWhatsappJid } from "./utils.js";
dotenv.config({ quiet: true });
// Capture all console output into pino logs while keeping stdout/stderr behavior.
enableConsoleCapture();
import { buildProgram } from "./cli/program.js";
const program = buildProgram();

View File

@@ -1,6 +1,7 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import util from "node:util";
import pino, { type Bindings, type LevelWithSilent, type Logger } from "pino";
import { loadConfig, type WarelayConfig } from "./config/config.js";
@@ -37,9 +38,10 @@ export type LoggerResolvedSettings = ResolvedSettings;
let cachedLogger: Logger | null = null;
let cachedSettings: ResolvedSettings | null = null;
let overrideSettings: LoggerSettings | null = null;
let consolePatched = false;
function normalizeLevel(level?: string): LevelWithSilent {
if (isVerbose()) return "debug";
if (isVerbose()) return "trace";
const candidate = level ?? "info";
return ALLOWED_LEVELS.includes(candidate as LevelWithSilent)
? (candidate as LevelWithSilent)
@@ -113,6 +115,58 @@ export function resetLogger() {
overrideSettings = null;
}
/**
* 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.
*/
export function enableConsoleCapture(): void {
if (consolePatched) return;
consolePatched = true;
const logger = getLogger();
const original = {
log: console.log,
info: console.info,
warn: console.warn,
error: console.error,
debug: console.debug,
trace: console.trace,
};
const forward =
(level: LevelWithSilent, orig: (...args: unknown[]) => void) =>
(...args: unknown[]) => {
const formatted = util.format(...args);
try {
// Map console levels to pino
if (level === "trace") {
logger.trace(formatted);
} else if (level === "debug") {
logger.debug(formatted);
} else if (level === "info") {
logger.info(formatted);
} else if (level === "warn") {
logger.warn(formatted);
} else if (level === "error" || level === "fatal") {
logger.error(formatted);
} else {
logger.info(formatted);
}
} catch {
// never block console output on logging failures
}
orig.apply(console, args as []);
};
console.log = forward("info", original.log);
console.info = forward("info", original.info);
console.warn = forward("warn", original.warn);
console.error = forward("error", original.error);
console.debug = forward("debug", original.debug);
console.trace = forward("trace", original.trace);
}
function defaultRollingPathForToday(): string {
const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
return path.join(DEFAULT_LOG_DIR, `${LOG_PREFIX}-${today}${LOG_SUFFIX}`);