Files
unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/service/SystemMetricsService.java
dahoud 347d89cc02 feat(backend): consolidation finale Spec 001 LCB-FT + Flyway V1-V5
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>
2026-03-16 05:15:17 +00:00

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();
}
}