// ======================================== // FICHIER: js/core/browser-logger.js - VERSION NAVIGATEUR // Système de logging adapté du système ErrorReporting.js pour le navigateur // ======================================== class BrowserLogger { constructor() { this.logs = []; this.maxLogs = 1000; // Limite pour éviter l'explosion mémoire this.logContainer = null; this.isVisible = false; // Niveaux de log avec couleurs this.levels = { TRACE: { value: 10, color: '#6c757d', emoji: '🔍' }, DEBUG: { value: 20, color: '#007bff', emoji: '🐛' }, INFO: { value: 30, color: '#28a745', emoji: 'ℹ️' }, WARN: { value: 40, color: '#ffc107', emoji: '⚠️' }, ERROR: { value: 50, color: '#dc3545', emoji: '❌' } }; this.minLevel = 'DEBUG'; // Niveau minimum affiché this.init(); } init() { // Créer l'interface de log this.createLogUI(); // Intercepter les erreurs globales window.addEventListener('error', (event) => { this.logSh(`Erreur JavaScript: ${event.error.message}`, 'ERROR'); }); window.addEventListener('unhandledrejection', (event) => { this.logSh(`Promise rejetée: ${event.reason}`, 'ERROR'); }); logSh('🚀 BrowserLogger initialisé', 'INFO'); } createLogUI() { // Créer le conteneur de log const logContainer = document.createElement('div'); logContainer.id = 'browser-logger'; logContainer.innerHTML = `

📋 System Logs

${this.formatTime(new Date())} INFO Logger initialisé
`; // Ajouter les styles CSS const style = document.createElement('style'); style.textContent = ` #browser-logger { position: fixed; top: 80px; right: 10px; width: 400px; max-height: 500px; background: #fff; border: 2px solid #007bff; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); font-family: 'Consolas', 'Monaco', monospace; font-size: 12px; z-index: 10000; display: none; } #browser-logger.visible { display: block; } .logger-header { background: #007bff; color: white; padding: 8px 12px; display: flex; justify-content: space-between; align-items: center; border-radius: 6px 6px 0 0; } .logger-header h3 { margin: 0; font-size: 14px; } .logger-controls { display: flex; gap: 5px; align-items: center; } .logger-controls select { padding: 2px 4px; font-size: 11px; border: none; border-radius: 3px; } .logger-controls button { background: rgba(255,255,255,0.2); border: none; color: white; padding: 2px 6px; border-radius: 3px; cursor: pointer; font-size: 12px; } .logger-controls button:hover { background: rgba(255,255,255,0.3); } .logger-content { max-height: 400px; overflow-y: auto; padding: 0; background: #f8f9fa; } .log-entry { padding: 4px 8px; border-bottom: 1px solid #e9ecef; display: flex; gap: 8px; font-size: 11px; line-height: 1.4; } .log-entry:hover { background: #e9ecef; } .log-time { color: #6c757d; min-width: 60px; font-weight: bold; } .log-level { min-width: 50px; font-weight: bold; text-align: center; border-radius: 3px; padding: 1px 4px; } .log-level.trace { background: #f8f9fa; color: #6c757d; } .log-level.debug { background: #cce5ff; color: #007bff; } .log-level.info { background: #d4edda; color: #28a745; } .log-level.warn { background: #fff3cd; color: #856404; } .log-level.error { background: #f8d7da; color: #721c24; } .log-message { flex: 1; word-break: break-word; } .log-message.trace { color: #6c757d; } .log-message.network { color: #17a2b8; font-weight: bold; } .log-message.auth { color: #6610f2; font-weight: bold; } `; document.head.appendChild(style); document.body.appendChild(logContainer); this.logContainer = logContainer; this.logContent = logContainer.querySelector('#logger-content'); // Event listeners document.getElementById('toggle-logger').addEventListener('click', () => { this.toggle(); }); document.getElementById('clear-logs').addEventListener('click', () => { this.clear(); }); document.getElementById('log-level-filter').addEventListener('change', (e) => { this.minLevel = e.target.value; this.refreshDisplay(); }); // Raccourci clavier pour toggle document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.shiftKey && e.key === 'L') { this.toggle(); } }); } formatTime(date) { return date.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit', second: '2-digit' }); } logSh(message, level = 'INFO') { // Sécuriser le level pour éviter les erreurs if (typeof level !== 'string') { level = 'INFO'; } const timestamp = new Date(); const logEntry = { timestamp, level: level.toUpperCase(), message, id: Date.now() + Math.random() }; // Ajouter à la liste des logs this.logs.push(logEntry); // Limiter le nombre de logs en mémoire if (this.logs.length > this.maxLogs) { this.logs.shift(); } // Log aussi dans la console navigateur (gardé pour le debugging) if (level !== 'TRACE' && level !== 'DEBUG') { // Éviter le spam en console const consoleMethod = level.toLowerCase() === 'error' ? 'error' : level.toLowerCase() === 'warn' ? 'warn' : 'log'; console[consoleMethod](`[${this.formatTime(timestamp)}] ${level}: ${message}`); } // Mettre à jour l'affichage si visible if (this.isVisible) { this.addLogToDisplay(logEntry); } return logEntry; } addLogToDisplay(logEntry) { const levelInfo = this.levels[logEntry.level] || this.levels.INFO; // Vérifier si on doit afficher ce niveau if (levelInfo.value < this.levels[this.minLevel].value) { return; } const logElement = document.createElement('div'); logElement.className = `log-entry ${logEntry.level.toLowerCase()}`; logElement.innerHTML = ` ${this.formatTime(logEntry.timestamp)} ${logEntry.level} ${this.formatMessage(logEntry.message)} `; this.logContent.appendChild(logElement); // Auto-scroll vers le bas this.logContent.scrollTop = this.logContent.scrollHeight; // Limiter les éléments DOM affichés const entries = this.logContent.querySelectorAll('.log-entry'); if (entries.length > 200) { entries[0].remove(); } } getMessageClass(message) { if (message.includes('🌐') || message.includes('📡') || message.includes('connexion')) { return 'network'; } if (message.includes('🔐') || message.includes('auth') || message.includes('Headers')) { return 'auth'; } return ''; } formatMessage(message) { // Échapper le HTML mais garder les emojis return message.replace(//g, '>'); } refreshDisplay() { if (!this.isVisible) return; this.logContent.innerHTML = ''; this.logs.forEach(logEntry => { this.addLogToDisplay(logEntry); }); } show() { this.isVisible = true; this.logContainer.classList.add('visible'); this.refreshDisplay(); this.logSh('Logger affiché', 'DEBUG'); } hide() { this.isVisible = false; this.logContainer.classList.remove('visible'); this.logSh('Logger masqué', 'DEBUG'); } toggle() { if (this.isVisible) { this.hide(); } else { this.show(); } } clear() { this.logs = []; if (this.logContent) { this.logContent.innerHTML = ''; } this.logSh('Logs effacés', 'INFO'); } // Méthodes de convenance trace(message) { return this.logSh(message, 'TRACE'); } debug(message) { return this.logSh(message, 'DEBUG'); } info(message) { return this.logSh(message, 'INFO'); } warn(message) { return this.logSh(message, 'WARN'); } error(message) { return this.logSh(message, 'ERROR'); } } // Instance globale window.logger = new BrowserLogger(); // Fonction globale compatible avec le système original window.logSh = (message, level = 'INFO') => { return window.logger.logSh(message, level); }; // Export pour compatibilité if (typeof module !== 'undefined' && module.exports) { module.exports = { BrowserLogger }; }