logging: route console output into pino
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
|||||||
autoReplyIfConfigured,
|
autoReplyIfConfigured,
|
||||||
getReplyFromConfig,
|
getReplyFromConfig,
|
||||||
} from "./auto-reply/reply.js";
|
} from "./auto-reply/reply.js";
|
||||||
|
import { enableConsoleCapture } from "./logging.js";
|
||||||
import { applyTemplate } from "./auto-reply/templating.js";
|
import { applyTemplate } from "./auto-reply/templating.js";
|
||||||
import { createDefaultDeps, monitorTwilio } from "./cli/deps.js";
|
import { createDefaultDeps, monitorTwilio } from "./cli/deps.js";
|
||||||
import { promptYesNo } from "./cli/prompt.js";
|
import { promptYesNo } from "./cli/prompt.js";
|
||||||
@@ -56,6 +57,9 @@ import { assertProvider, normalizeE164, toWhatsappJid } from "./utils.js";
|
|||||||
|
|
||||||
dotenv.config({ quiet: true });
|
dotenv.config({ quiet: true });
|
||||||
|
|
||||||
|
// Capture all console output into pino logs while keeping stdout/stderr behavior.
|
||||||
|
enableConsoleCapture();
|
||||||
|
|
||||||
import { buildProgram } from "./cli/program.js";
|
import { buildProgram } from "./cli/program.js";
|
||||||
|
|
||||||
const program = buildProgram();
|
const program = buildProgram();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
import util from "node:util";
|
||||||
|
|
||||||
import pino, { type Bindings, type LevelWithSilent, type Logger } from "pino";
|
import pino, { type Bindings, type LevelWithSilent, type Logger } from "pino";
|
||||||
import { loadConfig, type WarelayConfig } from "./config/config.js";
|
import { loadConfig, type WarelayConfig } from "./config/config.js";
|
||||||
@@ -37,9 +38,10 @@ export type LoggerResolvedSettings = ResolvedSettings;
|
|||||||
let cachedLogger: Logger | null = null;
|
let cachedLogger: Logger | 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;
|
||||||
|
|
||||||
function normalizeLevel(level?: string): LevelWithSilent {
|
function normalizeLevel(level?: string): LevelWithSilent {
|
||||||
if (isVerbose()) return "debug";
|
if (isVerbose()) return "trace";
|
||||||
const candidate = level ?? "info";
|
const candidate = level ?? "info";
|
||||||
return ALLOWED_LEVELS.includes(candidate as LevelWithSilent)
|
return ALLOWED_LEVELS.includes(candidate as LevelWithSilent)
|
||||||
? (candidate as LevelWithSilent)
|
? (candidate as LevelWithSilent)
|
||||||
@@ -113,6 +115,58 @@ export function resetLogger() {
|
|||||||
overrideSettings = null;
|
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 {
|
function defaultRollingPathForToday(): string {
|
||||||
const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
|
const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
|
||||||
return path.join(DEFAULT_LOG_DIR, `${LOG_PREFIX}-${today}${LOG_SUFFIX}`);
|
return path.join(DEFAULT_LOG_DIR, `${LOG_PREFIX}-${today}${LOG_SUFFIX}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user