Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 523edffc4e | |||
|
|
3cc371c53e | ||
| c7ddb1a8b0 | |||
|
|
b46e9079d5 | ||
|
|
dc20070bf8 |
2
pom.xml
2
pom.xml
@@ -11,7 +11,7 @@
|
||||
|
||||
<groupId>com.imyeyu.timiserverapi</groupId>
|
||||
<artifactId>TimiServerAPI</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<version>1.0.1</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>TimiServerAPI</name>
|
||||
<description>imyeyu.com API</description>
|
||||
|
||||
@@ -348,10 +348,10 @@ public class ServerStatus implements TimiJava {
|
||||
private String mountPoint;
|
||||
|
||||
/** 分区总空间 */
|
||||
private long totalBytes;
|
||||
private long total;
|
||||
|
||||
/** 分区已用空间 */
|
||||
private Long usedBytes;
|
||||
private Long used;
|
||||
|
||||
/** 磁盘传输耗时 */
|
||||
private long transferTimeMs;
|
||||
|
||||
@@ -26,17 +26,17 @@ public class DockerController {
|
||||
|
||||
private final DockerService dockerService;
|
||||
|
||||
@GetMapping("/containers")
|
||||
@GetMapping("/container")
|
||||
public List<DockerContainerSummaryView> listContainers() {
|
||||
return dockerService.listContainers();
|
||||
}
|
||||
|
||||
@GetMapping("/containers/{containerId}/status")
|
||||
@GetMapping("/container/{containerId}/status")
|
||||
public DockerContainerStatusView getContainerStatus(@PathVariable String containerId) {
|
||||
return dockerService.getContainerStatus(containerId);
|
||||
}
|
||||
|
||||
@GetMapping("/containers/{containerId}/history")
|
||||
@GetMapping("/container/{containerId}/history")
|
||||
public DockerContainerHistoryView getContainerHistory(@PathVariable String containerId, @RequestParam(required = false) String window) {
|
||||
return dockerService.getContainerHistory(containerId, window);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,6 @@ public class StatusServiceImplement implements StatusService {
|
||||
SystemStatusDataView.OS os = new SystemStatusDataView.OS();
|
||||
os.setName(serverStatus.getOs().getName());
|
||||
os.setBootAt(serverStatus.getOs().getBootAt());
|
||||
os.setUptimeMs(Math.max(0, serverTime - serverStatus.getOs().getBootAt()));
|
||||
snapshot.setOs(os);
|
||||
}
|
||||
if (selectedMetrics.contains(Metric.CPU)) {
|
||||
@@ -80,8 +79,8 @@ public class StatusServiceImplement implements StatusService {
|
||||
cpu.setModel(serverStatus.getCpu().getName());
|
||||
cpu.setPhysicalCores(serverStatus.getCpu().getCoreCount());
|
||||
cpu.setLogicalCores(serverStatus.getCpu().getLogicalCount());
|
||||
cpu.setUsagePercent(lastDouble(serverStatus.getCpu().getUsed()));
|
||||
cpu.setSystemPercent(lastDouble(serverStatus.getCpu().getSystem()));
|
||||
cpu.setUsageTotal(lastDouble(serverStatus.getCpu().getUsed()));
|
||||
cpu.setUsageSystem(lastDouble(serverStatus.getCpu().getSystem()));
|
||||
cpu.setTemperatureCelsius(serverStatus.getCpu().getTemperature());
|
||||
snapshot.setCpu(cpu);
|
||||
}
|
||||
@@ -91,7 +90,6 @@ public class StatusServiceImplement implements StatusService {
|
||||
Long swapUsedBytes = lastLong(serverStatus.getMemory().getSwapUsed());
|
||||
memory.setTotalBytes(serverStatus.getMemory().getSize());
|
||||
memory.setUsedBytes(usedBytes);
|
||||
memory.setUsagePercent(toPercent(usedBytes, serverStatus.getMemory().getSize()));
|
||||
memory.setSwapTotalBytes(serverStatus.getMemory().getSwapSize());
|
||||
memory.setSwapUsedBytes(swapUsedBytes);
|
||||
snapshot.setMemory(memory);
|
||||
@@ -160,9 +158,9 @@ public class StatusServiceImplement implements StatusService {
|
||||
item.setPartitionType(partition.getPartitionType());
|
||||
item.setUuid(partition.getUuid());
|
||||
item.setMountPoint(partition.getMountPoint());
|
||||
item.setTotalBytes(partition.getTotalBytes());
|
||||
item.setUsedBytes(partition.getUsedBytes());
|
||||
item.setUsagePercent(toPercent(partition.getUsedBytes(), partition.getTotalBytes()));
|
||||
item.setTotal(partition.getTotal());
|
||||
item.setUsed(partition.getUsed());
|
||||
item.setUsagePercent(toPercent(partition.getUsed(), partition.getTotal()));
|
||||
item.setTransferTimeMs(partition.getTransferTimeMs());
|
||||
storagePartitions.add(item);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public class UpsServiceImplement implements UpsService {
|
||||
private final UpsStatusTask upsStatusTask;
|
||||
private final UpsStatusStore upsStatusStore;
|
||||
|
||||
@Value("${ups.collect-rate-ms:60000}")
|
||||
@Value("${ups.collect-rate-ms:3000}")
|
||||
private long collectRateMs;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.imyeyu.api.modules.system.bean.DockerStatusStore;
|
||||
import com.imyeyu.api.modules.system.util.DockerEngineClient;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.utils.Time;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -15,12 +16,13 @@ import org.springframework.scheduling.support.PeriodicTrigger;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Docker 鐘舵€侀噰闆嗕换鍔?
|
||||
* Docker 容器状态采集任务
|
||||
*
|
||||
* @author Codex
|
||||
* @since 2026-04-06
|
||||
@@ -56,19 +58,27 @@ public class DockerStatusTask implements SchedulingConfigurer {
|
||||
try {
|
||||
ArrayNode containers = (ArrayNode) dockerEngineClient.getJson("/containers/json", DockerEngineClient.query("all", "true"));
|
||||
long now = Time.now();
|
||||
synchronized (dockerStatusStore) {
|
||||
Set<String> activeIds = new HashSet<>();
|
||||
for (JsonNode summary : containers) {
|
||||
try {
|
||||
String containerId = getAsString(summary, "Id");
|
||||
activeIds.add(containerId);
|
||||
DockerStatusStore.Container container = dockerStatusStore.getContainers().computeIfAbsent(containerId, key -> new DockerStatusStore.Container());
|
||||
updateContainerSummary(container, summary);
|
||||
updateContainerInspect(containerId, container);
|
||||
updateContainerStats(containerId, container, now);
|
||||
} catch (Exception e) {
|
||||
log.error("collect docker container item error", e);
|
||||
Map<String, DockerStatusStore.Container> collectedContainers = new LinkedHashMap<>();
|
||||
for (JsonNode summary : containers) {
|
||||
try {
|
||||
String containerId = getAsString(summary, "Id");
|
||||
DockerStatusStore.Container container = new DockerStatusStore.Container();
|
||||
if (TimiJava.isEmpty(container)) {
|
||||
continue;
|
||||
}
|
||||
updateContainerSummary(container, summary);
|
||||
updateContainerInspect(containerId, container);
|
||||
updateContainerStats(containerId, container, now);
|
||||
collectedContainers.put(container.getId(), container);
|
||||
} catch (Exception e) {
|
||||
log.error("collect docker container item error", e);
|
||||
}
|
||||
}
|
||||
synchronized (dockerStatusStore) {
|
||||
Set<String> activeIds = new HashSet<>(collectedContainers.keySet());
|
||||
for (Map.Entry<String, DockerStatusStore.Container> item : collectedContainers.entrySet()) {
|
||||
DockerStatusStore.Container container = dockerStatusStore.getContainers().computeIfAbsent(item.getKey(), key -> new DockerStatusStore.Container());
|
||||
applyCollectedContainer(container, item.getValue());
|
||||
}
|
||||
dockerStatusStore.getContainers().entrySet().removeIf(item -> !activeIds.contains(item.getKey()));
|
||||
}
|
||||
@@ -77,6 +87,39 @@ public class DockerStatusTask implements SchedulingConfigurer {
|
||||
}
|
||||
}
|
||||
|
||||
private void applyCollectedContainer(DockerStatusStore.Container target, DockerStatusStore.Container source) {
|
||||
target.setId(source.getId());
|
||||
target.setName(source.getName());
|
||||
target.setImage(source.getImage());
|
||||
target.setImageId(source.getImageId());
|
||||
target.setCreatedAt(source.getCreatedAt());
|
||||
target.setState(source.getState());
|
||||
target.setStatus(source.getStatus());
|
||||
target.setHealthStatus(source.getHealthStatus());
|
||||
target.setStartedAt(source.getStartedAt());
|
||||
target.setFinishedAt(source.getFinishedAt());
|
||||
target.setExitCode(source.getExitCode());
|
||||
target.setRestartCount(source.getRestartCount());
|
||||
target.setOomKilled(source.isOomKilled());
|
||||
target.setCpuPercent(source.getCpuPercent());
|
||||
target.setMemoryUsageBytes(source.getMemoryUsageBytes());
|
||||
target.setMemoryLimitBytes(source.getMemoryLimitBytes());
|
||||
target.setMemoryPercent(source.getMemoryPercent());
|
||||
target.setNetworkRxBytes(source.getNetworkRxBytes());
|
||||
target.setNetworkTxBytes(source.getNetworkTxBytes());
|
||||
target.setBlockReadBytes(source.getBlockReadBytes());
|
||||
target.setBlockWriteBytes(source.getBlockWriteBytes());
|
||||
target.setPids(source.getPids());
|
||||
target.setUpdatedAt(source.getUpdatedAt());
|
||||
DockerStatusStore.Point point = source.getHistory().peekLast();
|
||||
if (point != null) {
|
||||
target.getHistory().addLast(point);
|
||||
while (historyLimit < target.getHistory().size()) {
|
||||
target.getHistory().pollFirst();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateContainerSummary(DockerStatusStore.Container container, JsonNode summary) {
|
||||
container.setId(getAsString(summary, "Id"));
|
||||
container.setName(trimContainerName(readFirstArrayText(summary, "Names")));
|
||||
@@ -108,8 +151,8 @@ public class DockerStatusTask implements SchedulingConfigurer {
|
||||
if (memoryUsageBytes != null && memoryLimitBytes != null && 0 < memoryLimitBytes) {
|
||||
memoryPercent = memoryUsageBytes * 100D / memoryLimitBytes;
|
||||
}
|
||||
Long networkRxBytes = 0L;
|
||||
Long networkTxBytes = 0L;
|
||||
long networkRxBytes = 0L;
|
||||
long networkTxBytes = 0L;
|
||||
JsonNode networks = getAsObject(stats, "networks");
|
||||
if (networks != null) {
|
||||
for (Map.Entry<String, JsonNode> item : (Iterable<Map.Entry<String, JsonNode>>) networks::fields) {
|
||||
@@ -118,8 +161,8 @@ public class DockerStatusTask implements SchedulingConfigurer {
|
||||
networkTxBytes += getAsLong(network, "tx_bytes", 0L);
|
||||
}
|
||||
}
|
||||
Long blockReadBytes = 0L;
|
||||
Long blockWriteBytes = 0L;
|
||||
long blockReadBytes = 0L;
|
||||
long blockWriteBytes = 0L;
|
||||
JsonNode blkioStats = getAsObject(stats, "blkio_stats");
|
||||
ArrayNode ioServiceBytes = blkioStats == null ? null : getAsArray(blkioStats, "io_service_bytes_recursive");
|
||||
if (ioServiceBytes != null) {
|
||||
@@ -134,7 +177,6 @@ public class DockerStatusTask implements SchedulingConfigurer {
|
||||
}
|
||||
}
|
||||
Integer pids = getNestedInteger(stats, "pids_stats", "current");
|
||||
|
||||
container.setCpuPercent(cpuPercent);
|
||||
container.setMemoryUsageBytes(memoryUsageBytes);
|
||||
container.setMemoryLimitBytes(memoryLimitBytes);
|
||||
|
||||
@@ -38,10 +38,10 @@ public class CpuStatusCollector extends AbstractDequeStatusCollector {
|
||||
long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - lastCpuTicks[CentralProcessor.TickType.IRQ.getIndex()];
|
||||
long softIrq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - lastCpuTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
|
||||
long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - lastCpuTicks[CentralProcessor.TickType.STEAL.getIndex()];
|
||||
long total = user + nice + sys + idle + ioWait + irq + softIrq + steal;
|
||||
double total = user + nice + sys + idle + ioWait + irq + softIrq + steal;
|
||||
if (0 < total) {
|
||||
putDeque(context, context.getStatus().getCpu().getSystem(), 100D * sys / total);
|
||||
putDeque(context, context.getStatus().getCpu().getUsed(), 100 - 100D * idle / total);
|
||||
putDeque(context, context.getStatus().getCpu().getSystem(), sys / total);
|
||||
putDeque(context, context.getStatus().getCpu().getUsed(), 1 - idle / total);
|
||||
}
|
||||
}
|
||||
lastCpuTicks = ticks;
|
||||
|
||||
@@ -38,13 +38,13 @@ public class StorageStatusCollector implements StatusCollector {
|
||||
item.setPartitionType(partition.getType());
|
||||
item.setUuid(partition.getUuid());
|
||||
item.setMountPoint(partition.getMountPoint());
|
||||
item.setTotalBytes(partition.getSize());
|
||||
item.setTotal(partition.getSize());
|
||||
item.setTransferTimeMs(diskStore.getTransferTime());
|
||||
|
||||
OSFileStore fileStore = matchFileStore(partition, fileStoreMap);
|
||||
if (fileStore != null) {
|
||||
fileStore.updateAttributes();
|
||||
item.setUsedBytes(fileStore.getTotalSpace() - fileStore.getUsableSpace());
|
||||
item.setUsed(fileStore.getTotalSpace() - fileStore.getUsableSpace());
|
||||
}
|
||||
context.getStatus().getStoragePartitions().add(item);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.net.http.HttpResponse;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -73,6 +74,28 @@ public class DockerEngineClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 Docker Engine 当前是否可访问。
|
||||
*
|
||||
* @return 可访问返回 true,不可访问返回 false
|
||||
*/
|
||||
public boolean isAvailable() {
|
||||
if (host.startsWith("unix://")) {
|
||||
String socketPath = host.substring("unix://".length());
|
||||
return Files.exists(Path.of(socketPath));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Docker Engine 主机配置。
|
||||
*
|
||||
* @return 主机配置字符串
|
||||
*/
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
private String buildRequestPath(String path, Map<String, String> queryParams) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("/");
|
||||
|
||||
@@ -101,9 +101,6 @@ public class SystemStatusDataView {
|
||||
|
||||
/** 启动时间 */
|
||||
private long bootAt;
|
||||
|
||||
/** 运行时长 */
|
||||
private long uptimeMs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,10 +122,10 @@ public class SystemStatusDataView {
|
||||
private int logicalCores;
|
||||
|
||||
/** 总占用 */
|
||||
private Double usagePercent;
|
||||
private Double usageTotal;
|
||||
|
||||
/** 系统占用 */
|
||||
private Double systemPercent;
|
||||
private Double usageSystem;
|
||||
|
||||
/** 温度 */
|
||||
private double temperatureCelsius;
|
||||
@@ -149,9 +146,6 @@ public class SystemStatusDataView {
|
||||
/** 已用内存 */
|
||||
private Long usedBytes;
|
||||
|
||||
/** 使用率 */
|
||||
private Double usagePercent;
|
||||
|
||||
/** 交换分区总量 */
|
||||
private long swapTotalBytes;
|
||||
|
||||
@@ -364,10 +358,10 @@ public class SystemStatusDataView {
|
||||
private String mountPoint;
|
||||
|
||||
/** 分区总空间 */
|
||||
private long totalBytes;
|
||||
private long total;
|
||||
|
||||
/** 已用空间 */
|
||||
private Long usedBytes;
|
||||
private Long used;
|
||||
|
||||
/** 使用率 */
|
||||
private Double usagePercent;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
server:
|
||||
shutdown: graceful
|
||||
# 压缩
|
||||
compression:
|
||||
enable: true
|
||||
min-response-size: 10KB
|
||||
|
||||
# 开发环境语言,激活开发配置时,多语言系统始终使用此语言环境
|
||||
dev:
|
||||
|
||||
Reference in New Issue
Block a user