const MAX_LOG_ENTRIES = 500; const logs = []; function formatTimestamp(ts) { return ts.toISOString().replace("T", " ").replace("Z", ""); } function safeStringify(val) { if (val === undefined) return undefined; try { const s = JSON.stringify(val); return s && s.length < 500 ? s : s.substring(0, 500) + "..."; } catch { return String(val); } } function createLogger(module) { function log(level, message, data) { const entry = { time: new Date(), module, level, message, data: safeStringify(data), }; logs.push(entry); if (logs.length > MAX_LOG_ENTRIES) logs.shift(); const prefix = `[OrbitMarks:${module}] [${level}]`; const line = `${prefix} ${message}`; switch (level) { case "ERROR": console.error(line, ...(data ? [data] : [])); break; case "WARN": console.warn(line, ...(data ? [data] : [])); break; case "INFO": console.info(line, ...(data ? [data] : [])); break; case "DEBUG": console.debug(line, ...(data ? [data] : [])); break; default: console.log(line, ...(data ? [data] : [])); break; } } const logMethods = { error: (msg, data) => log("ERROR", msg, data), warn: (msg, data) => log("WARN", msg, data), info: (msg, data) => log("INFO", msg, data), debug: (msg, data) => log("DEBUG", msg, data), trace: (msg, data) => log("TRACE", msg, data), timer: (label) => { const start = Date.now(); return (msg, data) => { const elapsed = Date.now() - start; log("INFO", `${label} — ${msg} (${elapsed}ms)`, data); return elapsed; }; }, }; return logMethods; } function getLogs() { return logs; } function clearLogs() { logs.length = 0; } function getLogsAsText() { return logs .map((e) => { const time = formatTimestamp(e.time); const data = e.data ? ` ${e.data}` : ""; return `[${time}] [${e.module}] [${e.level}] ${e.message}${data}`; }) .join("\n"); }