import { redactSecrets, formatMessage, safeJsonStringify } from "./utils/strings.js";
/**
* Supported log levels for structured logging.
*
* Each level corresponds to increasing severity:
* - debug: Detailed diagnostic information
* - info: General informational messages
* - warn: Warning messages for potentially harmful situations
* - error: Error messages for error events
*/
export type LogLevel = "debug" | "info" | "warn" | "error";
/**
* Interface for structured logging with secret scrubbing capabilities.
*
* All log methods write to stderr with timestamp and level prefix.
* The audit method automatically redacts sensitive data before logging.
*/
export interface Logger {
/** Log a debug message with optional format arguments. */
debug: (message: string, ...args: unknown[]) => void;
/** Log an info message with optional format arguments. */
info: (message: string, ...args: unknown[]) => void;
/** Log a warning message with optional format arguments. */
warn: (message: string, ...args: unknown[]) => void;
/** Log an error message with optional format arguments. */
error: (message: string, ...args: unknown[]) => void;
/**
* Log an audit event with secret redaction.
*
* Automatically scrubs sensitive fields (password, token, secret, etc.)
* from the payload before logging.
*/
audit: (event: string, payload: unknown) => void;
}
/**
* Internal log writer that formats and writes to stderr.
*
* Formats the log message with timestamp and level prefix,
* then writes to stderr to avoid interfering with stdio transport.
*
* @param level - The log level (debug, info, warn, error).
* @param message - The log message, optionally with format specifiers.
* @param args - Format arguments for the message.
*/
function log(level: LogLevel, message: string, args: unknown[]): void {
const timestamp = new Date().toISOString();
const formatted = formatMessage(message, args);
const line = `[${timestamp}] ${level.toUpperCase()} ${formatted}`;
process.stderr.write(`${line}\n`);
}
/**
* Create a structured logger with secret scrubbing for audit events.
*
* Returns a logger implementation that writes to stderr with timestamps.
* The audit method automatically redacts sensitive data before logging.
*
* @returns A configured Logger instance.
*/
export function createLogger(): Logger {
return {
// Forward all log levels to the internal log function
debug: (message, ...args) => log("debug", message, args),
info: (message, ...args) => log("info", message, args),
warn: (message, ...args) => log("warn", message, args),
error: (message, ...args) => log("error", message, args),
// Audit events require secret redaction before logging
audit: (event, payload) => {
const scrubbed = redactSecrets(payload);
log("info", "audit %s %s", [event, safeJsonStringify(scrubbed)]);
},
};
}