/** * @file rr-logger.js * @description Structured logger for Reynolds & Reynolds (Rome) integration. * Mirrors PBS/Fortellis log shape for consistent log parsing. */ const util = require("util"); const dayjs = require("dayjs"); /** * @typedef {Object} LogContext * @property {string} [jobid] * @property {string} [action] * @property {string} [stage] * @property {string} [endpoint] * @property {Object} [meta] */ /** * Emit a structured log event to console, Socket.IO, or upstream logger. * @param {Socket|null} socket - Optional socket for WsLogger passthrough * @param {"info"|"debug"|"warn"|"error"} level * @param {string} message - Primary log message * @param {LogContext|any} [context] */ function RRLogger(socket, level, message, context = {}) { const logEvent = { source: "RR", level, timestamp: dayjs().toISOString(), message, ...context }; // Console log (stdout/stderr) const serialized = `[RR] ${logEvent.timestamp} [${level.toUpperCase()}] ${message}`; if (level === "error" || level === "warn") { console.error(serialized, context ? util.inspect(context, { depth: 4, colors: false }) : ""); } else { console.log(serialized, context ? util.inspect(context, { depth: 4, colors: false }) : ""); } // Optional: forward to WsLogger (if your socket is configured that way) try { if (socket && typeof socket.emit === "function") { socket.emit("rr-log-event", logEvent); } else if (global.WsLogger && typeof global.WsLogger.createLogEvent === "function") { global.WsLogger.createLogEvent(socket, level.toUpperCase(), message, context.jobid, context); } } catch (e) { console.error("[RRLogger] forwarding error", e.message); } } module.exports = RRLogger;