Files
bodyshop/server/rr/rr-logger.js

57 lines
1.9 KiB
JavaScript

// File: server/rr/rr-logger.js
// Console logger for RR flows with safe JSON. No socket emission by default.
const baseLogger = require("../utils/logger");
function RRLogger(_socket, defaults = {}) {
function safeSerialize(value) {
try {
const seen = new WeakSet();
return JSON.stringify(value, (key, val) => {
if (typeof val === "bigint") return val.toString();
if (val instanceof Error) return { name: val.name, message: val.message, stack: val.stack };
if (typeof val === "function") return undefined;
if (typeof val === "object" && val !== null) {
if (seen.has(val)) return "[Circular]";
seen.add(val);
if (val instanceof Date) return val.toISOString();
if (val instanceof Map) return Object.fromEntries(val);
if (val instanceof Set) return Array.from(val);
if (typeof Buffer !== "undefined" && Buffer.isBuffer?.(val)) return `<Buffer len=${val.length}>`;
}
return val;
});
} catch {
try {
return String(value);
} catch {
return "[Unserializable]";
}
}
}
return function log(level = "info", message = "", ctx = {}) {
const lvl = String(level || "info").toLowerCase();
const iso = new Date().toISOString();
const msgStr = typeof message === "string" ? message : safeSerialize(message);
const mergedCtx = ctx && typeof ctx === "object" ? { ...defaults, ...ctx } : { ...defaults };
const ctxStr = Object.keys(mergedCtx || {}).length ? ` ${safeSerialize(mergedCtx)}` : "";
const line = `[RR] ${iso} [${lvl.toUpperCase()}] ${msgStr}${ctxStr}`;
const logger = baseLogger?.logger || baseLogger || console;
const fn = (logger[lvl] || logger.log || logger.info || console[lvl] || console.log).bind(logger);
try {
fn(line);
} catch {
try {
console.log(line);
} catch {}
}
};
}
module.exports = RRLogger;