Migrations Flyway (consolidées) : - V1 : Schéma complet (69 tables, 1322 lignes) - V2 : Colonnes BaseEntity (cree_par, modifie_par) - V3 : Colonnes métier manquantes (adresses, alert_configuration) - V4 : Correction system_logs (renommage colonnes, ajout timestamp) - V5 : Nettoyage alert_configuration (suppression colonnes obsolètes) - Suppression V2-V6 obsolètes (fragmentés) Entités LCB-FT : - AlerteLcbFt : Alertes anti-blanchiment - AlertConfiguration : Configuration alertes - SystemAlert : Alertes système - SystemLog : Logs techniques (DÉJÀ COMMITÉE avec super.onCreate fix) Services LCB-FT (T015, T016) : - AlerteLcbFtService + Resource : Dashboard alertes admin - AlertMonitoringService : Surveillance transactions - SystemLoggingService : Logs centralisés - FileStorageService : Upload documents Repositories : - AlerteLcbFtRepository - AlertConfigurationRepository - SystemAlertRepository - SystemLogRepository Tests : - GlobalExceptionMapperTest : 17 erreurs corrigées (toResponse()) Spec 001 : 27/27 tâches (100%) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
383 lines
12 KiB
Java
383 lines
12 KiB
Java
package dev.lions.unionflow.server.service;
|
|
|
|
import dev.lions.unionflow.server.api.dto.logs.response.SystemMetricsResponse;
|
|
import dev.lions.unionflow.server.entity.Membre;
|
|
import dev.lions.unionflow.server.repository.MembreRepository;
|
|
import io.agroal.api.AgroalDataSource;
|
|
import io.quarkus.runtime.StartupEvent;
|
|
import jakarta.enterprise.context.ApplicationScoped;
|
|
import jakarta.enterprise.event.Observes;
|
|
import jakarta.inject.Inject;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
|
|
|
import javax.sql.DataSource;
|
|
import java.io.File;
|
|
import java.lang.management.ManagementFactory;
|
|
import java.lang.management.MemoryMXBean;
|
|
import java.lang.management.OperatingSystemMXBean;
|
|
import java.sql.Connection;
|
|
import java.sql.SQLException;
|
|
import java.time.LocalDateTime;
|
|
import java.time.ZoneId;
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
/**
|
|
* Service pour récupérer les métriques système réelles
|
|
*/
|
|
@Slf4j
|
|
@ApplicationScoped
|
|
public class SystemMetricsService {
|
|
|
|
@Inject
|
|
MembreRepository membreRepository;
|
|
|
|
@Inject
|
|
DataSource dataSource;
|
|
|
|
@ConfigProperty(name = "quarkus.application.name")
|
|
String applicationName;
|
|
|
|
@ConfigProperty(name = "quarkus.application.version")
|
|
String applicationVersion;
|
|
|
|
@ConfigProperty(name = "quarkus.oidc.auth-server-url", defaultValue = "http://localhost:8180/realms/unionflow")
|
|
String authServerUrl;
|
|
|
|
// Compteurs pour les métriques
|
|
private final AtomicLong apiRequestsCount = new AtomicLong(0);
|
|
private final AtomicLong apiRequestsLastHour = new AtomicLong(0);
|
|
private final AtomicLong apiRequestsToday = new AtomicLong(0);
|
|
private long startTimeMillis;
|
|
private LocalDateTime startTime;
|
|
|
|
/**
|
|
* Initialisation au démarrage
|
|
*/
|
|
void onStart(@Observes StartupEvent event) {
|
|
startTimeMillis = System.currentTimeMillis();
|
|
startTime = LocalDateTime.now();
|
|
log.info("SystemMetricsService initialized at {}", startTime);
|
|
}
|
|
|
|
/**
|
|
* Récupérer toutes les métriques système
|
|
*/
|
|
public SystemMetricsResponse getSystemMetrics() {
|
|
log.debug("Collecting system metrics...");
|
|
|
|
return SystemMetricsResponse.builder()
|
|
// Métriques CPU
|
|
.cpuUsagePercent(getCpuUsage())
|
|
.availableProcessors(Runtime.getRuntime().availableProcessors())
|
|
.systemLoadAverage(getSystemLoadAverage())
|
|
|
|
// Métriques mémoire
|
|
.totalMemoryBytes(getTotalMemory())
|
|
.usedMemoryBytes(getUsedMemory())
|
|
.freeMemoryBytes(getFreeMemory())
|
|
.maxMemoryBytes(getMaxMemory())
|
|
.memoryUsagePercent(getMemoryUsagePercent())
|
|
.totalMemoryFormatted(SystemMetricsResponse.formatBytes(getTotalMemory()))
|
|
.usedMemoryFormatted(SystemMetricsResponse.formatBytes(getUsedMemory()))
|
|
.freeMemoryFormatted(SystemMetricsResponse.formatBytes(getFreeMemory()))
|
|
|
|
// Métriques disque
|
|
.totalDiskBytes(getTotalDiskSpace())
|
|
.usedDiskBytes(getUsedDiskSpace())
|
|
.freeDiskBytes(getFreeDiskSpace())
|
|
.diskUsagePercent(getDiskUsagePercent())
|
|
.totalDiskFormatted(SystemMetricsResponse.formatBytes(getTotalDiskSpace()))
|
|
.usedDiskFormatted(SystemMetricsResponse.formatBytes(getUsedDiskSpace()))
|
|
.freeDiskFormatted(SystemMetricsResponse.formatBytes(getFreeDiskSpace()))
|
|
|
|
// Métriques utilisateurs
|
|
.activeUsersCount(getActiveUsersCount())
|
|
.totalUsersCount(getTotalUsersCount())
|
|
.activeSessionsCount(getActiveSessionsCount())
|
|
.failedLoginAttempts24h(getFailedLoginAttempts())
|
|
|
|
// Métriques API
|
|
.apiRequestsLastHour(apiRequestsLastHour.get())
|
|
.apiRequestsToday(apiRequestsToday.get())
|
|
.averageResponseTimeMs(getAverageResponseTime())
|
|
.totalRequestsCount(apiRequestsCount.get())
|
|
|
|
// Métriques base de données
|
|
.dbConnectionPoolSize(getDbConnectionPoolSize())
|
|
.dbActiveConnections(getDbActiveConnections())
|
|
.dbIdleConnections(getDbIdleConnections())
|
|
.dbHealthy(isDatabaseHealthy())
|
|
|
|
// Métriques erreurs et logs (simulées pour l'instant, à implémenter avec vrai système de logs)
|
|
.criticalErrorsCount(0)
|
|
.warningsCount(0)
|
|
.infoLogsCount(0)
|
|
.debugLogsCount(0)
|
|
.totalLogsCount(0L)
|
|
|
|
// Métriques réseau (simulées, nécessiterait monitoring avancé)
|
|
.networkBytesReceivedPerSec(0.0)
|
|
.networkBytesSentPerSec(0.0)
|
|
.networkInFormatted("0 B/s")
|
|
.networkOutFormatted("0 B/s")
|
|
|
|
// Métriques système
|
|
.systemStatus(getSystemStatus())
|
|
.uptimeMillis(getUptimeMillis())
|
|
.uptimeFormatted(SystemMetricsResponse.formatUptime(getUptimeMillis()))
|
|
.startTime(startTime)
|
|
.currentTime(LocalDateTime.now())
|
|
.javaVersion(System.getProperty("java.version"))
|
|
.quarkusVersion(getQuarkusVersion())
|
|
.applicationVersion(applicationVersion)
|
|
|
|
// Métriques maintenance (à implémenter avec vrai système de backup)
|
|
.lastBackup(null)
|
|
.nextScheduledMaintenance(null)
|
|
.lastMaintenance(null)
|
|
|
|
// URLs
|
|
.apiBaseUrl(getApiBaseUrl())
|
|
.authServerUrl(authServerUrl)
|
|
.cdnUrl(null)
|
|
|
|
// Cache (à implémenter)
|
|
.totalCacheSizeBytes(0L)
|
|
.totalCacheSizeFormatted("0 B")
|
|
.totalCacheEntries(0)
|
|
|
|
.build();
|
|
}
|
|
|
|
// ==================== MÉTHODES DE CALCUL DES MÉTRIQUES ====================
|
|
|
|
/**
|
|
* CPU Usage (estimation basée sur la charge système)
|
|
*/
|
|
private Double getCpuUsage() {
|
|
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
|
|
double loadAvg = osBean.getSystemLoadAverage();
|
|
int processors = osBean.getAvailableProcessors();
|
|
|
|
if (loadAvg < 0) {
|
|
return 0.0; // Non disponible sur certains OS
|
|
}
|
|
|
|
// Calcul approximatif : (load average / nb processeurs) * 100
|
|
return Math.min(100.0, (loadAvg / processors) * 100.0);
|
|
}
|
|
|
|
/**
|
|
* System Load Average
|
|
*/
|
|
private Double getSystemLoadAverage() {
|
|
return ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage();
|
|
}
|
|
|
|
/**
|
|
* Mémoire totale
|
|
*/
|
|
private Long getTotalMemory() {
|
|
return Runtime.getRuntime().totalMemory();
|
|
}
|
|
|
|
/**
|
|
* Mémoire utilisée
|
|
*/
|
|
private Long getUsedMemory() {
|
|
Runtime runtime = Runtime.getRuntime();
|
|
return runtime.totalMemory() - runtime.freeMemory();
|
|
}
|
|
|
|
/**
|
|
* Mémoire libre
|
|
*/
|
|
private Long getFreeMemory() {
|
|
return Runtime.getRuntime().freeMemory();
|
|
}
|
|
|
|
/**
|
|
* Mémoire maximale
|
|
*/
|
|
private Long getMaxMemory() {
|
|
return Runtime.getRuntime().maxMemory();
|
|
}
|
|
|
|
/**
|
|
* Pourcentage mémoire utilisée
|
|
*/
|
|
private Double getMemoryUsagePercent() {
|
|
Runtime runtime = Runtime.getRuntime();
|
|
long used = runtime.totalMemory() - runtime.freeMemory();
|
|
long max = runtime.maxMemory();
|
|
return (used * 100.0) / max;
|
|
}
|
|
|
|
/**
|
|
* Espace disque total
|
|
*/
|
|
private Long getTotalDiskSpace() {
|
|
File root = new File("/");
|
|
return root.getTotalSpace();
|
|
}
|
|
|
|
/**
|
|
* Espace disque utilisé
|
|
*/
|
|
private Long getUsedDiskSpace() {
|
|
File root = new File("/");
|
|
return root.getTotalSpace() - root.getFreeSpace();
|
|
}
|
|
|
|
/**
|
|
* Espace disque libre
|
|
*/
|
|
private Long getFreeDiskSpace() {
|
|
File root = new File("/");
|
|
return root.getFreeSpace();
|
|
}
|
|
|
|
/**
|
|
* Pourcentage disque utilisé
|
|
*/
|
|
private Double getDiskUsagePercent() {
|
|
File root = new File("/");
|
|
long total = root.getTotalSpace();
|
|
long free = root.getFreeSpace();
|
|
if (total == 0) return 0.0;
|
|
return ((total - free) * 100.0) / total;
|
|
}
|
|
|
|
/**
|
|
* Nombre d'utilisateurs actifs (avec sessions actives)
|
|
*/
|
|
private Integer getActiveUsersCount() {
|
|
// TODO: Implémenter avec vrai système de sessions
|
|
// Pour l'instant, compte les membres actifs
|
|
try {
|
|
return (int) membreRepository.count("actif = true");
|
|
} catch (Exception e) {
|
|
log.error("Error getting active users count", e);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Nombre total d'utilisateurs
|
|
*/
|
|
private Integer getTotalUsersCount() {
|
|
try {
|
|
return (int) membreRepository.count();
|
|
} catch (Exception e) {
|
|
log.error("Error getting total users count", e);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Nombre de sessions actives
|
|
*/
|
|
private Integer getActiveSessionsCount() {
|
|
// TODO: Implémenter avec vrai système de sessions Keycloak
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Tentatives de login échouées (24h)
|
|
*/
|
|
private Integer getFailedLoginAttempts() {
|
|
// TODO: Implémenter avec vrai système d'audit
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Temps de réponse moyen API
|
|
*/
|
|
private Double getAverageResponseTime() {
|
|
// TODO: Implémenter avec vrai système de métriques
|
|
return 0.0;
|
|
}
|
|
|
|
/**
|
|
* Taille du pool de connexions DB
|
|
*/
|
|
private Integer getDbConnectionPoolSize() {
|
|
if (dataSource instanceof AgroalDataSource agroalDataSource) {
|
|
return agroalDataSource.getConfiguration().connectionPoolConfiguration().maxSize();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Connexions DB actives
|
|
*/
|
|
private Integer getDbActiveConnections() {
|
|
if (dataSource instanceof AgroalDataSource agroalDataSource) {
|
|
return (int) agroalDataSource.getMetrics().activeCount();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Connexions DB en attente
|
|
*/
|
|
private Integer getDbIdleConnections() {
|
|
if (dataSource instanceof AgroalDataSource agroalDataSource) {
|
|
return (int) agroalDataSource.getMetrics().availableCount();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* État santé base de données
|
|
*/
|
|
private Boolean isDatabaseHealthy() {
|
|
try (Connection conn = dataSource.getConnection()) {
|
|
return conn.isValid(5); // 5 secondes timeout
|
|
} catch (SQLException e) {
|
|
log.error("Database health check failed", e);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Statut système
|
|
*/
|
|
private String getSystemStatus() {
|
|
// TODO: Implémenter logique plus sophistiquée
|
|
return "OPERATIONAL";
|
|
}
|
|
|
|
/**
|
|
* Uptime en millisecondes
|
|
*/
|
|
private Long getUptimeMillis() {
|
|
return System.currentTimeMillis() - startTimeMillis;
|
|
}
|
|
|
|
/**
|
|
* Version Quarkus
|
|
*/
|
|
private String getQuarkusVersion() {
|
|
return io.quarkus.runtime.annotations.QuarkusMain.class.getPackage().getImplementationVersion();
|
|
}
|
|
|
|
/**
|
|
* URL base API
|
|
*/
|
|
private String getApiBaseUrl() {
|
|
// TODO: Récupérer depuis configuration
|
|
return "http://localhost:8085";
|
|
}
|
|
|
|
/**
|
|
* Incrémenter le compteur de requêtes API
|
|
*/
|
|
public void incrementApiRequestCount() {
|
|
apiRequestsCount.incrementAndGet();
|
|
apiRequestsLastHour.incrementAndGet();
|
|
apiRequestsToday.incrementAndGet();
|
|
}
|
|
}
|