UNPKG

design-agent

Version:

Universal AI Design Review Agent - CLI tool for scanning code for design drift

290 lines (241 loc) 6.61 kB
/** * Logging utilities for design agent * Provides structured logging with different levels and outputs */ export class Logger { constructor(options = {}) { this.level = options.level || 'info'; this.output = options.output || 'console'; this.format = options.format || 'text'; this.includeTimestamp = options.includeTimestamp !== false; this.includeContext = options.includeContext !== false; this.levels = { error: 0, warn: 1, info: 2, debug: 3 }; } log(level, message, context = {}) { if (this.levels[level] > this.levels[this.level]) { return; } const logEntry = this.createLogEntry(level, message, context); switch (this.output) { case 'console': this.logToConsole(logEntry); break; case 'file': this.logToFile(logEntry); break; case 'json': this.logToJson(logEntry); break; } } createLogEntry(level, message, context) { const entry = { level, message, timestamp: new Date().toISOString() }; if (this.includeContext && Object.keys(context).length > 0) { entry.context = context; } return entry; } logToConsole(entry) { const prefix = this.getConsolePrefix(entry.level); const message = this.format === 'json' ? JSON.stringify(entry, null, 2) : `${prefix} ${entry.message}`; switch (entry.level) { case 'error': console.error(message); break; case 'warn': console.warn(message); break; case 'info': console.info(message); break; case 'debug': console.debug(message); break; } } logToFile(entry) { // In a real implementation, this would write to a file // For now, we'll just log to console this.logToConsole(entry); } logToJson(entry) { console.log(JSON.stringify(entry)); } getConsolePrefix(level) { const prefixes = { error: '❌', warn: '⚠️', info: 'ℹ️', debug: '🐛' }; return prefixes[level] || '📝'; } error(message, context) { this.log('error', message, context); } warn(message, context) { this.log('warn', message, context); } info(message, context) { this.log('info', message, context); } debug(message, context) { this.log('debug', message, context); } } export function createLogger(options = {}) { return new Logger(options); } export function createProgressLogger(total, options = {}) { const logger = createLogger(options); let current = 0; return { update(increment = 1) { current += increment; const percentage = Math.round((current / total) * 100); logger.info(`Progress: ${current}/${total} (${percentage}%)`); }, complete() { logger.info(`Progress: ${total}/${total} (100%) - Complete!`); }, reset() { current = 0; } }; } export function createFileLogger(filePath, options = {}) { const logger = createLogger({ ...options, output: 'file' }); return { ...logger, filePath }; } export function createJsonLogger(options = {}) { return createLogger({ ...options, format: 'json' }); } export function createSilentLogger() { return createLogger({ level: 'error' }); } export function createVerboseLogger() { return createLogger({ level: 'debug' }); } export function logPerformance(operation, fn, logger) { const start = Date.now(); try { const result = fn(); const duration = Date.now() - start; logger.info(`Operation completed: ${operation}`, { duration: `${duration}ms`, operation }); return result; } catch (error) { const duration = Date.now() - start; logger.error(`Operation failed: ${operation}`, { duration: `${duration}ms`, operation, error: error.message }); throw error; } } export function logMemoryUsage(logger) { const usage = process.memoryUsage(); logger.debug('Memory usage', { rss: `${Math.round(usage.rss / 1024 / 1024)}MB`, heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`, heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`, external: `${Math.round(usage.external / 1024 / 1024)}MB` }); } export function logEnvironment(logger) { logger.info('Environment info', { nodeVersion: process.version, platform: process.platform, arch: process.arch, cwd: process.cwd(), env: process.env.NODE_ENV || 'development' }); } export function logConfig(logger, config) { logger.debug('Configuration loaded', { project: config.project, adapters: config.adapters?.length || 0, scanPaths: config.scanPaths?.length || 0, checks: Object.keys(config.checks || {}).length }); } export function logFindings(logger, findings) { const bySeverity = findings.reduce((acc, finding) => { acc[finding.severity] = (acc[finding.severity] || 0) + 1; return acc; }, {}); logger.info('Scan results', { total: findings.length, critical: bySeverity.critical || 0, major: bySeverity.major || 0, minor: bySeverity.minor || 0 }); } export function logAdapterExecution(logger, adapter, file, success, duration) { if (success) { logger.debug(`Adapter executed: ${adapter}`, { file, duration: `${duration}ms` }); } else { logger.warn(`Adapter failed: ${adapter}`, { file, duration: `${duration}ms` }); } } export function logError(logger, error, context = {}) { logger.error('Error occurred', { message: error.message, name: error.name, stack: error.stack, ...context }); } export function createAuditLogger(options = {}) { const logger = createLogger(options); return { startScan(config) { logger.info('Design agent scan started', { project: config.project, adapters: config.adapters, scanPaths: config.scanPaths }); }, endScan(findings, duration) { logger.info('Design agent scan completed', { findings: findings.length, duration: `${duration}ms` }); }, fileProcessed(file, findings) { logger.debug('File processed', { file, findings: findings.length }); }, adapterExecuted(adapter, file, success, duration) { logAdapterExecution(logger, adapter, file, success, duration); }, error(error, context) { logError(logger, error, context); } }; }