added comments

This commit is contained in:
rob 2025-10-16 00:35:20 -03:00
parent 0ac583fec4
commit b3a6986dc5
1 changed files with 96 additions and 0 deletions

View File

@ -1,6 +1,52 @@
// ==LOGGER START== // ==LOGGER START==
(function () { (function () {
/**
* AI Repo Commander Logger module
*
* Purpose
* - Provide structured, level-gated logging for all modules.
* - Buffer recent log entries for the in-page debug panel and copy/export.
* - Prevent log spam from hot paths via logLoop.
*
* Integration
* - Exposed as window.AI_REPO_LOGGER for use across modules.
* - Uses window.AI_REPO_CONFIG for runtime toggles and limits:
* - debug.enabled: boolean gate for all logging
* - debug.level: 05 (0=off, 1=error, 2=warn, 3=info, 4=verbose, 5=trace)
* - debug.watchMs: time window used by logLoop for anti-spam
* - debug.maxLines: max entries retained in memory buffer
*
* Console format
* - Each entry prints to the browser console as: [AI RC <LEVEL>] <message> <data?>
* - Data is sanitized to avoid dumping large strings or DOM nodes.
*
* Notes
* - No external dependencies, works in plain browser context.
* - This module does not persist logs; it keeps an in-memory ring buffer only.
*
* Example
* const log = window.AI_REPO_LOGGER;
* log.info('Starting');
* log.warn('Slow operation', { ms: 1234 });
* log.error('Failed', { error: e.message });
* console.log(log.getRecentLogs(100));
*/
/**
* Structured logger with in-memory buffer and anti-spam utilities.
* Fields:
* - config: ConfigManager; access to debug.* keys
* - buffer: Array<{timestamp, level, message, data}> recent log entries
* - loopCounts: Map used by logLoop to cap repeated messages
* - startedAt: number (ms) reference time for logLoop watch window
*/
class Logger { class Logger {
/**
* Initializes the logger.
* - Grabs the global config instance.
* - Prepares the in-memory buffer and loop counters.
* - Starts a periodic cleanup that resets logLoop counters after ~2× watch window.
*/
constructor() { constructor() {
this.config = window.AI_REPO_CONFIG; this.config = window.AI_REPO_CONFIG;
this.buffer = []; this.buffer = [];
@ -17,6 +63,8 @@
}, this.config.get('debug.watchMs') || 120000); }, this.config.get('debug.watchMs') || 120000);
} }
// Convenience level helpers. Gated by debug.enabled and debug.level (see _log).
// Levels: 1=ERROR, 2=WARN, 3=INFO, 4=VERBOSE, 5=TRACE
error(msg, data) { this._log(1, 'ERROR', msg, data); } error(msg, data) { this._log(1, 'ERROR', msg, data); }
warn(msg, data) { this._log(2, 'WARN', msg, data); } warn(msg, data) { this._log(2, 'WARN', msg, data); }
info(msg, data) { this._log(3, 'INFO', msg, data); } info(msg, data) { this._log(3, 'INFO', msg, data); }
@ -80,6 +128,24 @@
else this.info(`${msg}${suffix}`); else this.info(`${msg}${suffix}`);
} }
/**
* Core logging sink. Applies gating, buffers the entry, and prints to console.
*
* Gating
* - If debug.enabled is false, nothing is logged.
* - If levelNum > debug.level, the entry is ignored.
*
* Buffering
* - Recent entries kept in memory (debug.maxLines ring buffer) for the debug panel and copy/export.
*
* Console output
* - Printed as: [AI RC <LEVEL>] message [sanitized data]
*
* @param {number} levelNum - Numeric level (1..5)
* @param {string} levelName - Label shown in output (ERROR/WARN/INFO/VERBOSE/TRACE)
* @param {any} msg - Primary message; coerced to string
* @param {any} [data] - Optional context data; sanitized to avoid huge strings/DOM elements
*/
_log(levelNum, levelName, msg, data) { _log(levelNum, levelName, msg, data) {
const enabled = !!this.config.get('debug.enabled'); const enabled = !!this.config.get('debug.enabled');
const level = this.config.get('debug.level') ?? 0; const level = this.config.get('debug.level') ?? 0;
@ -99,6 +165,19 @@
entry.data ? console.log(prefix, msg, entry.data) : console.log(prefix, msg); entry.data ? console.log(prefix, msg, entry.data) : console.log(prefix, msg);
} }
/**
* Best-effort redaction/sanitization of context data before logging.
* - HTMLElement "HTMLElement<TAG>" (prevents dumping live DOM trees)
* - Long strings (>200 chars) truncated with ellipsis to keep logs concise
* - Plain objects shallowly sanitize each value using the same rules
* - Other primitives are returned as-is
*
* This keeps console output readable and reduces accidental leakage of
* large payloads while still conveying useful context.
*
* @param {any} data
* @returns {any} sanitized data suitable for console/JSON
*/
_sanitize(data) { _sanitize(data) {
if (!data) return null; if (!data) return null;
if (data instanceof HTMLElement) return `HTMLElement<${data.tagName}>`; if (data instanceof HTMLElement) return `HTMLElement<${data.tagName}>`;
@ -114,12 +193,29 @@
return data; return data;
} }
/**
* Returns the most recent N logs as plain text, one entry per line.
* Each line format: ISO_TIMESTAMP LEVEL message {jsonData?}
*
* @param {number} [n=50] - Number of lines to include from the tail of the buffer
* @returns {string}
*/
getRecentLogs(n = 50) { getRecentLogs(n = 50) {
return this.buffer.slice(-n).map(e => return this.buffer.slice(-n).map(e =>
`${e.timestamp} ${e.level.padEnd(7)} ${e.message}${e.data ? ' ' + JSON.stringify(e.data) : ''}` `${e.timestamp} ${e.level.padEnd(7)} ${e.message}${e.data ? ' ' + JSON.stringify(e.data) : ''}`
).join('\n'); ).join('\n');
} }
/**
* Sets the runtime log level in config (05) and logs the change.
* Levels:
* 0=off, 1=error, 2=warn, 3=info, 4=verbose, 5=trace
*
* Note: The debug panel level selector typically writes to the same key.
* This method is provided for console/automation convenience.
*
* @param {number} n - Desired level; values are clamped to [0,5]
*/
setLevel(n) { setLevel(n) {
const lv = Math.max(0, Math.min(5, n)); const lv = Math.max(0, Math.min(5, n));
this.config.set('debug.level', lv); this.config.set('debug.level', lv);