бла бла бла

This commit is contained in:
2026-10-28 15:50:34 +01:00
parent 2e8428de4e
commit fb27de5e7f
21 changed files with 858 additions and 541 deletions
@@ -1,66 +1,89 @@
package com.htopweb.system;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.OperatingSystem;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@Service
public class SystemMetricsService {
private final SystemInfo _systemInfo;
private final HardwareAbstractionLayer _hardware;
private static final Path HOST_ROOT = Path.of("/host/root");
private static final Path HOST_PROC = HOST_ROOT.resolve("proc");
private final OperatingSystem _operatingSystem;
private final CentralProcessor _processor;
private final GlobalMemory _memory;
private long[] _previousCpuTicks;
private CpuTicks _previousHostCpuTicks;
private static final Logger log =
LoggerFactory.getLogger(SystemMetricsService.class);
public SystemMetricsService() {
_systemInfo = new SystemInfo();
_hardware = _systemInfo.getHardware();
_operatingSystem = _systemInfo.getOperatingSystem();
_processor = _hardware.getProcessor();
_memory = _hardware.getMemory();
SystemInfo systemInfo = new SystemInfo();
HardwareAbstractionLayer hardware = systemInfo.getHardware();
_previousCpuTicks = _processor.getSystemCpuLoadTicks();
_operatingSystem = systemInfo.getOperatingSystem();
_processor = hardware.getProcessor();
_memory = hardware.getMemory();
_previousHostCpuTicks = readHostCpuTicks();
}
public synchronized SystemMetricsResponse getMetrics() {
long[] currentCpuTicks = _processor.getSystemCpuLoadTicks();
CpuTicks currentTicks = readHostCpuTicks();
double cpuUsage = 0.0;
double cpuUsage = _processor.getSystemCpuLoadBetweenTicks(
_previousCpuTicks,
currentCpuTicks
);
if (currentTicks != null && _previousHostCpuTicks != null) {
long totalDelta = currentTicks.total() - _previousHostCpuTicks.total();
long idleDelta = currentTicks.idle() - _previousHostCpuTicks.idle();
_previousCpuTicks = currentCpuTicks;
if (Double.isNaN(cpuUsage) || Double.isInfinite(cpuUsage)) {
cpuUsage = 0.0;
if (totalDelta > 0 && idleDelta >= 0 && idleDelta <= totalDelta) {
cpuUsage = (double) (totalDelta - idleDelta) / totalDelta;
}
}
// Task Manager displays system CPU usage in the 0–100% range.
cpuUsage = Math.max(0.0, Math.min(1.0, cpuUsage));
if (currentTicks != null) {
_previousHostCpuTicks = currentTicks;
}
Map<String, Long> hostMemory = readHostMemory();
long totalMemory = hostMemory.getOrDefault("MemTotal", _memory.getTotal());
long availableMemory = hostMemory.getOrDefault(
"MemAvailable",
_memory.getAvailable()
);
availableMemory = Math.max(0L, Math.min(totalMemory, availableMemory));
long totalMemory = _memory.getTotal();
long availableMemory = _memory.getAvailable();
long usedMemory = Math.max(0L, totalMemory - availableMemory);
double memoryUsage = totalMemory > 0
? (double) usedMemory / totalMemory * 100.0
: 0.0;
Map<String, String> osRelease = readHostOsRelease();
return new SystemMetricsResponse(
_operatingSystem.getFamily(),
_operatingSystem.getVersionInfo().getVersion(),
_operatingSystem.getNetworkParams().getHostName(),
getHostOsFamily(osRelease),
getHostOsVersion(osRelease),
readHostHostname(),
_processor.getProcessorIdentifier().getName(),
_processor.getLogicalProcessorCount(),
getLogicalProcessorCount(),
round(cpuUsage * 100.0),
totalMemory,
availableMemory,
@@ -69,7 +92,187 @@ public class SystemMetricsService {
);
}
private CpuTicks readHostCpuTicks() {
Path statFile = HOST_PROC.resolve("stat");
try {
if (!Files.isRegularFile(statFile)
|| !Files.isReadable(statFile)) {
log.warn("Host CPU statistics are unavailable: {}", statFile);
return null;
}
for (String line : Files.readAllLines(statFile)) {
if (!line.startsWith("cpu ")) {
continue;
}
String[] fields = line.trim().split("\\s+");
if (fields.length < 5) {
log.warn("Invalid host CPU statistics in {}", statFile);
return null;
}
long total = 0L;
for (int i = 1; i < fields.length; i++) {
total += Long.parseLong(fields[i]);
}
long idle = Long.parseLong(fields[4]);
if (fields.length > 5) {
idle += Long.parseLong(fields[5]);
}
return new CpuTicks(total, idle);
}
log.warn("Aggregate CPU line not found in {}", statFile);
} catch (IOException | NumberFormatException e) {
log.warn("Failed to read host CPU statistics: {}", e.getMessage());
}
return null;
}
private Map<String, Long> readHostMemory() {
Map<String, Long> values = new HashMap<>();
Path meminfoFile = HOST_PROC.resolve("meminfo");
try {
if (!Files.isRegularFile(meminfoFile)) {
return values;
}
for (String line : Files.readAllLines(meminfoFile)) {
int separator = line.indexOf(':');
if (separator < 0) {
continue;
}
String key = line.substring(0, separator).trim();
if (!key.equals("MemTotal") && !key.equals("MemAvailable")) {
continue;
}
String[] parts = line.substring(separator + 1).trim().split("\\s+");
if (parts.length > 0) {
// Linux meminfo values are reported in kB.
values.put(key, Long.parseLong(parts[0]) * 1024L);
}
}
} catch (IOException | NumberFormatException ignored) {
// Use OSHI values when host meminfo is unavailable.
}
return values;
}
private int getLogicalProcessorCount() {
Path statFile = HOST_PROC.resolve("stat");
try {
if (Files.isRegularFile(statFile)) {
int count = 0;
for (String line : Files.readAllLines(statFile)) {
if (line.matches("^cpu\\d+\\s+.*")) {
count++;
}
}
if (count > 0) {
return count;
}
}
} catch (IOException ignored) {
// Fall back to OSHI.
}
return _processor.getLogicalProcessorCount();
}
private String readHostHostname() {
try {
Path file = HOST_ROOT.resolve("etc/hostname");
if (Files.isRegularFile(file)) {
String hostname = Files.readString(file).trim();
if (!hostname.isBlank()) {
return hostname;
}
}
} catch (IOException ignored) {
// Fall back to OSHI.
}
return _operatingSystem.getNetworkParams().getHostName();
}
private Map<String, String> readHostOsRelease() {
Map<String, String> values = new HashMap<>();
try {
Path file = HOST_ROOT.resolve("etc/os-release");
if (!Files.isRegularFile(file)) {
return values;
}
for (String line : Files.readAllLines(file)) {
int separator = line.indexOf('=');
if (separator <= 0 || line.startsWith("#")) {
continue;
}
String key = line.substring(0, separator).trim();
String value = line.substring(separator + 1).trim();
if (value.length() >= 2
&& ((value.startsWith("\"") && value.endsWith("\""))
|| (value.startsWith("'") && value.endsWith("'")))) {
value = value.substring(1, value.length() - 1);
}
values.put(key, value);
}
} catch (IOException ignored) {
// Fall back to OSHI.
}
return values;
}
private String getHostOsFamily(Map<String, String> osRelease) {
String name = osRelease.get("NAME");
return name != null && !name.isBlank()
? name
: _operatingSystem.getFamily();
}
private String getHostOsVersion(Map<String, String> osRelease) {
String version = osRelease.get("VERSION");
if (version == null || version.isBlank()) {
version = osRelease.get("VERSION_ID");
}
return version != null && !version.isBlank()
? version
: _operatingSystem.getVersionInfo().getVersion();
}
private double round(double value) {
return Math.round(value * 10.0) / 10.0;
}
private record CpuTicks(long total, long idle) {
}
}