This commit is contained in:
181
services/reportService.js
Normal file
181
services/reportService.js
Normal file
@@ -0,0 +1,181 @@
|
||||
const BaseService = require('./BaseService');
|
||||
const cron = require('node-cron');
|
||||
const os = require('os');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const ip = require('ip');
|
||||
const si = require('systeminformation');
|
||||
const fetch = require('node-fetch');
|
||||
const packageJson = require('../package.json');
|
||||
|
||||
class ReportManagerService extends BaseService {
|
||||
constructor() {
|
||||
// Configuration par défaut
|
||||
const defaultConfig = {
|
||||
enabled: 'off',
|
||||
endpoint: 'https://cdn-apollon-p198-61m1.dinawo.fr/api/report/receive',
|
||||
cronSchedule: '0 0 * * *' // Par défaut, une fois par jour à minuit
|
||||
};
|
||||
|
||||
super('reportManager', defaultConfig);
|
||||
this.job = null;
|
||||
}
|
||||
|
||||
async _startImplementation() {
|
||||
if (this.job) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Valider le cron schedule
|
||||
const schedule = this.config.cronSchedule || this.defaultConfig.cronSchedule;
|
||||
if (!cron.validate(schedule)) {
|
||||
throw new Error(`Schedule cron invalide: ${schedule}`);
|
||||
}
|
||||
|
||||
this.job = cron.schedule(schedule, () => this.generateAndSendReport());
|
||||
this.logger.info(`Service de rapport programmé avec le planning: ${schedule}`);
|
||||
}
|
||||
|
||||
async _stopImplementation() {
|
||||
if (this.job) {
|
||||
this.job.stop();
|
||||
this.job = null;
|
||||
}
|
||||
}
|
||||
|
||||
formatUptime(uptime) {
|
||||
const days = Math.floor(uptime / (24 * 60 * 60));
|
||||
uptime %= (24 * 60 * 60);
|
||||
const hours = Math.floor(uptime / (60 * 60));
|
||||
uptime %= (60 * 60);
|
||||
const minutes = Math.floor(uptime / 60);
|
||||
return `${days}d ${hours}h ${minutes}m`;
|
||||
}
|
||||
|
||||
async getInternalErrors() {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() - 1);
|
||||
const previousDate = date.toISOString().split('T')[0];
|
||||
const logFile = path.join(__dirname, '..', 'logs', `log-${previousDate}.log`);
|
||||
|
||||
try {
|
||||
const logs = fs.readFileSync(logFile, 'utf-8');
|
||||
return logs.split('\n').filter(line => /\[38;5;9mInternal-Error/.test(line));
|
||||
} catch (err) {
|
||||
this.logger.error('Erreur lors de la lecture des logs:', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async generateReport() {
|
||||
try {
|
||||
const internalErrors = await this.getInternalErrors();
|
||||
|
||||
if (internalErrors.length === 0) {
|
||||
this.logger.info('Pas d\'erreurs internes dans les logs d\'hier. Pas de rapport généré.');
|
||||
return null;
|
||||
}
|
||||
|
||||
const loadavg = os.loadavg().map(load => (load / os.cpus().length) * 100);
|
||||
|
||||
const osInfo = {
|
||||
type: os.type(),
|
||||
platform: os.platform(),
|
||||
arch: os.arch(),
|
||||
release: os.release(),
|
||||
uptime: this.formatUptime(os.uptime()),
|
||||
loadavg: loadavg
|
||||
};
|
||||
|
||||
const networkInterfaces = os.networkInterfaces();
|
||||
const diskUsage = await si.fsSize();
|
||||
const cpuTemperature = await si.cpuTemperature();
|
||||
const userInfo = os.userInfo();
|
||||
|
||||
const systemInfo = {
|
||||
memoryInfo: ((os.totalmem() - os.freemem()) / os.totalmem() * 100).toFixed(2),
|
||||
cpuInfo: (os.cpus().length / os.cpus().length * 100).toFixed(2),
|
||||
diskInfo: diskUsage.map(disk => ({
|
||||
fs: disk.fs,
|
||||
type: disk.type,
|
||||
size: disk.size,
|
||||
used: disk.used,
|
||||
available: disk.available,
|
||||
use: disk.use
|
||||
})),
|
||||
ipAddress: ip.address(),
|
||||
cdnVersion: packageJson.version,
|
||||
osInfo: osInfo,
|
||||
userInfo: {
|
||||
username: userInfo.username,
|
||||
homedir: userInfo.homedir,
|
||||
shell: userInfo.shell
|
||||
},
|
||||
errors: internalErrors,
|
||||
networkInterfaces: networkInterfaces,
|
||||
serverUptime: os.uptime(),
|
||||
systemLoad: loadavg,
|
||||
cpuTemperature: cpuTemperature
|
||||
};
|
||||
|
||||
const reportDate = new Date();
|
||||
reportDate.setDate(reportDate.getDate() - 1);
|
||||
const reportFileName = `report_${reportDate.toISOString().split('T')[0]}_${ip.address()}.json`;
|
||||
|
||||
// Sauvegarder le rapport localement
|
||||
const reportDir = path.join(__dirname, '..', 'report');
|
||||
if (!fs.existsSync(reportDir)) {
|
||||
fs.mkdirSync(reportDir, { recursive: true });
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(reportDir, reportFileName),
|
||||
JSON.stringify(systemInfo, null, 2)
|
||||
);
|
||||
|
||||
return systemInfo;
|
||||
} catch (error) {
|
||||
this.logger.error('Erreur lors de la génération du rapport:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async generateAndSendReport() {
|
||||
try {
|
||||
const report = await this.generateReport();
|
||||
|
||||
if (!report) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.info("Envoi du rapport...");
|
||||
|
||||
const response = await fetch(this.config.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(report)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Erreur HTTP! statut: ${response.status}`);
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
this.logger.info('Rapport envoyé avec succès. Réponse:', responseData);
|
||||
|
||||
return responseData;
|
||||
} catch (error) {
|
||||
this.logger.error('Échec de l\'envoi du rapport:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode pour forcer l'envoi d'un rapport immédiatement
|
||||
async forceSendReport() {
|
||||
return this.generateAndSendReport();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new ReportManagerService();
|
||||
Reference in New Issue
Block a user