Class_generator/js/core/browser-logger.js
StillHammer 1f8688c4aa Fix WebSocket logging system and add comprehensive network features
- Fix WebSocket server to properly broadcast logs to all connected clients
- Integrate professional logging system with real-time WebSocket interface
- Add network status indicator with DigitalOcean Spaces connectivity
- Implement AWS Signature V4 authentication for private bucket access
- Add JSON content loader with backward compatibility to JS modules
- Restore navigation breadcrumb system with comprehensive logging
- Add multiple content formats: JSON + JS with automatic discovery
- Enhance top bar with logger toggle and network status indicator
- Remove deprecated temp-games module and clean up unused files

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-15 23:05:14 +08:00

355 lines
11 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ========================================
// 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 = `
<div class="logger-header">
<h3>📋 System Logs</h3>
<div class="logger-controls">
<select id="log-level-filter">
<option value="TRACE">TRACE</option>
<option value="DEBUG" selected>DEBUG</option>
<option value="INFO">INFO</option>
<option value="WARN">WARN</option>
<option value="ERROR">ERROR</option>
</select>
<button id="clear-logs">🗑️</button>
<button id="toggle-logger">❌</button>
</div>
</div>
<div class="logger-content" id="logger-content">
<div class="log-entry info">
<span class="log-time">${this.formatTime(new Date())}</span>
<span class="log-level">INFO</span>
<span class="log-message">Logger initialisé</span>
</div>
</div>
`;
// 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') {
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 = `
<span class="log-time">${this.formatTime(logEntry.timestamp)}</span>
<span class="log-level ${logEntry.level.toLowerCase()}">${logEntry.level}</span>
<span class="log-message ${this.getMessageClass(logEntry.message)}">${this.formatMessage(logEntry.message)}</span>
`;
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, '&lt;').replace(/>/g, '&gt;');
}
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 };
}