Some checks failed
SourceFinder CI/CD Pipeline / Code Quality & Linting (push) Has been cancelled
SourceFinder CI/CD Pipeline / Unit Tests (push) Has been cancelled
SourceFinder CI/CD Pipeline / Security Tests (push) Has been cancelled
SourceFinder CI/CD Pipeline / Integration Tests (push) Has been cancelled
SourceFinder CI/CD Pipeline / Performance Tests (push) Has been cancelled
SourceFinder CI/CD Pipeline / Code Coverage Report (push) Has been cancelled
SourceFinder CI/CD Pipeline / Build & Deployment Validation (16.x) (push) Has been cancelled
SourceFinder CI/CD Pipeline / Build & Deployment Validation (18.x) (push) Has been cancelled
SourceFinder CI/CD Pipeline / Build & Deployment Validation (20.x) (push) Has been cancelled
SourceFinder CI/CD Pipeline / Regression Tests (push) Has been cancelled
SourceFinder CI/CD Pipeline / Security Audit (push) Has been cancelled
SourceFinder CI/CD Pipeline / Notify Results (push) Has been cancelled
- Architecture modulaire avec injection de dépendances - Système de scoring intelligent multi-facteurs (spécificité, fraîcheur, qualité, réutilisation) - Moteur anti-injection 4 couches (preprocessing, patterns, sémantique, pénalités) - API REST complète avec validation et rate limiting - Repository JSON avec index mémoire et backup automatique - Provider LLM modulaire pour génération de contenu - Suite de tests complète (Jest) : * Tests unitaires pour sécurité et scoring * Tests d'intégration API end-to-end * Tests de sécurité avec simulation d'attaques * Tests de performance et charge - Pipeline CI/CD avec GitHub Actions - Logging structuré et monitoring - Configuration ESLint et environnement de test 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
179 lines
6.3 KiB
JavaScript
179 lines
6.3 KiB
JavaScript
#!/usr/bin/env node
|
|
// tools/log-server.js - Serveur simple pour visualiser les logs
|
|
const express = require('express');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const { exec } = require('child_process');
|
|
|
|
const app = express();
|
|
const PORT = 3001;
|
|
|
|
// Servir les fichiers statiques depuis la racine du projet
|
|
app.use(express.static(path.join(__dirname, '..')));
|
|
|
|
// Route pour servir les fichiers de log
|
|
app.use('/logs', express.static(path.join(__dirname, '..', 'logs')));
|
|
|
|
// Liste des fichiers de log disponibles
|
|
app.get('/api/logs', (req, res) => {
|
|
try {
|
|
const logsDir = path.join(__dirname, '..', 'logs');
|
|
const files = fs.readdirSync(logsDir)
|
|
.filter(file => file.endsWith('.log'))
|
|
.map(file => {
|
|
const filePath = path.join(logsDir, file);
|
|
const stats = fs.statSync(filePath);
|
|
return {
|
|
name: file,
|
|
size: stats.size,
|
|
modified: stats.mtime.toISOString(),
|
|
url: `http://localhost:${PORT}/tools/logs-viewer.html?file=${file}`
|
|
};
|
|
})
|
|
.sort((a, b) => new Date(b.modified) - new Date(a.modified));
|
|
|
|
res.json({ files });
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// Page d'accueil avec liste des logs
|
|
app.get('/', (req, res) => {
|
|
res.send(`
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Log Viewer Server</title>
|
|
<style>
|
|
body { font-family: Arial, sans-serif; margin: 40px; background: #f5f5f5; }
|
|
h1 { color: #333; }
|
|
.log-list { background: white; padding: 20px; border-radius: 5px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
|
.log-item {
|
|
padding: 10px;
|
|
border-bottom: 1px solid #eee;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
.log-item:hover { background: #f8f9fa; }
|
|
.log-name { font-weight: bold; color: #2c5aa0; }
|
|
.log-info { font-size: 0.9em; color: #666; }
|
|
.view-btn {
|
|
background: #007bff;
|
|
color: white;
|
|
padding: 5px 15px;
|
|
text-decoration: none;
|
|
border-radius: 3px;
|
|
font-size: 0.9em;
|
|
}
|
|
.view-btn:hover { background: #0056b3; }
|
|
.realtime-btn {
|
|
background: #28a745;
|
|
color: white;
|
|
padding: 10px 20px;
|
|
text-decoration: none;
|
|
border-radius: 5px;
|
|
display: inline-block;
|
|
margin-bottom: 20px;
|
|
}
|
|
.realtime-btn:hover { background: #218838; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>📊 SEO Generator - Log Viewer</h1>
|
|
|
|
<a href="/tools/logs-viewer.html" class="realtime-btn">🔴 Logs en temps réel</a>
|
|
|
|
<div class="log-list">
|
|
<h2>Fichiers de log disponibles</h2>
|
|
<div id="logFiles">Chargement...</div>
|
|
</div>
|
|
|
|
<script>
|
|
async function loadLogFiles() {
|
|
try {
|
|
const response = await fetch('/api/logs');
|
|
const data = await response.json();
|
|
|
|
const container = document.getElementById('logFiles');
|
|
if (data.files.length === 0) {
|
|
container.innerHTML = '<p>Aucun fichier de log trouvé</p>';
|
|
return;
|
|
}
|
|
|
|
container.innerHTML = data.files.map(file => {
|
|
const sizeKB = Math.round(file.size / 1024);
|
|
const date = new Date(file.modified).toLocaleString('fr-FR');
|
|
|
|
return \`
|
|
<div class="log-item">
|
|
<div>
|
|
<div class="log-name">\${file.name}</div>
|
|
<div class="log-info">\${sizeKB} KB • \${date}</div>
|
|
</div>
|
|
<a href="\${file.url}" class="view-btn" target="_blank">Voir</a>
|
|
</div>
|
|
\`;
|
|
}).join('');
|
|
} catch (error) {
|
|
document.getElementById('logFiles').innerHTML =
|
|
'<p style="color: red;">Erreur: ' + error.message + '</p>';
|
|
}
|
|
}
|
|
|
|
loadLogFiles();
|
|
</script>
|
|
</body>
|
|
</html>
|
|
`);
|
|
});
|
|
|
|
// Fonction pour ouvrir automatiquement le dernier log
|
|
function openLatestLog() {
|
|
try {
|
|
const logsDir = path.join(__dirname, '..', 'logs');
|
|
const files = fs.readdirSync(logsDir)
|
|
.filter(file => file.endsWith('.log'))
|
|
.map(file => {
|
|
const filePath = path.join(logsDir, file);
|
|
const stats = fs.statSync(filePath);
|
|
return {
|
|
name: file,
|
|
modified: stats.mtime
|
|
};
|
|
})
|
|
.sort((a, b) => b.modified - a.modified);
|
|
|
|
if (files.length > 0) {
|
|
const latestFile = files[0].name;
|
|
const url = `http://localhost:${PORT}/tools/logs-viewer.html?file=${latestFile}`;
|
|
|
|
// Ouvrir dans le navigateur par défaut
|
|
// Utiliser powershell Start-Process pour ouvrir l'URL dans le navigateur
|
|
const command = 'powershell.exe Start-Process';
|
|
|
|
exec(`${command} "${url}"`, (error) => {
|
|
if (error) {
|
|
console.log(`⚠️ Impossible d'ouvrir automatiquement: ${error.message}`);
|
|
console.log(`🌐 Ouvrez manuellement: ${url}`);
|
|
} else {
|
|
console.log(`🌐 Ouverture automatique du dernier log: ${latestFile}`);
|
|
}
|
|
});
|
|
} else {
|
|
console.log(`📊 Aucun log disponible - accédez à http://localhost:${PORT}/tools/logs-viewer.html`);
|
|
}
|
|
} catch (error) {
|
|
console.log(`⚠️ Erreur lors de l'ouverture: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
app.listen(PORT, () => {
|
|
console.log(`🚀 Log server running at http://localhost:${PORT}`);
|
|
console.log(`📊 Logs viewer: http://localhost:${PORT}/tools/logs-viewer.html`);
|
|
console.log(`📁 Logs directory: ${path.join(__dirname, '..', 'logs')}`);
|
|
|
|
// Attendre un peu que le serveur soit prêt, puis ouvrir le navigateur
|
|
setTimeout(openLatestLog, 1000);
|
|
}); |