Merge pull request 'v1.0.2' (#6) from dev into master

Reviewed-on: #6
This commit was merged in pull request #6.
This commit is contained in:
2026-04-13 10:28:11 +00:00
4 changed files with 88 additions and 19 deletions

View File

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.imyeyu.api.modules.system.bean.DockerStatusStore; import com.imyeyu.api.modules.system.bean.DockerStatusStore;
import com.imyeyu.api.modules.system.util.DockerEngineClient; import com.imyeyu.api.modules.system.util.DockerEngineClient;
import com.imyeyu.java.TimiJava;
import com.imyeyu.utils.Time; import com.imyeyu.utils.Time;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -15,12 +16,13 @@ import org.springframework.scheduling.support.PeriodicTrigger;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* Docker 鐘舵€侀噰闆嗕换鍔? * Docker 容器状态采集任务
* *
* @author Codex * @author Codex
* @since 2026-04-06 * @since 2026-04-06
@@ -56,19 +58,27 @@ public class DockerStatusTask implements SchedulingConfigurer {
try { try {
ArrayNode containers = (ArrayNode) dockerEngineClient.getJson("/containers/json", DockerEngineClient.query("all", "true")); ArrayNode containers = (ArrayNode) dockerEngineClient.getJson("/containers/json", DockerEngineClient.query("all", "true"));
long now = Time.now(); long now = Time.now();
synchronized (dockerStatusStore) { Map<String, DockerStatusStore.Container> collectedContainers = new LinkedHashMap<>();
Set<String> activeIds = new HashSet<>(); for (JsonNode summary : containers) {
for (JsonNode summary : containers) { try {
try { String containerId = getAsString(summary, "Id");
String containerId = getAsString(summary, "Id"); DockerStatusStore.Container container = new DockerStatusStore.Container();
activeIds.add(containerId); if (TimiJava.isEmpty(container)) {
DockerStatusStore.Container container = dockerStatusStore.getContainers().computeIfAbsent(containerId, key -> new DockerStatusStore.Container()); continue;
updateContainerSummary(container, summary);
updateContainerInspect(containerId, container);
updateContainerStats(containerId, container, now);
} catch (Exception e) {
log.error("collect docker container item error", e);
} }
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())); 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) { private void updateContainerSummary(DockerStatusStore.Container container, JsonNode summary) {
container.setId(getAsString(summary, "Id")); container.setId(getAsString(summary, "Id"));
container.setName(trimContainerName(readFirstArrayText(summary, "Names"))); container.setName(trimContainerName(readFirstArrayText(summary, "Names")));
@@ -108,8 +151,8 @@ public class DockerStatusTask implements SchedulingConfigurer {
if (memoryUsageBytes != null && memoryLimitBytes != null && 0 < memoryLimitBytes) { if (memoryUsageBytes != null && memoryLimitBytes != null && 0 < memoryLimitBytes) {
memoryPercent = memoryUsageBytes * 100D / memoryLimitBytes; memoryPercent = memoryUsageBytes * 100D / memoryLimitBytes;
} }
Long networkRxBytes = 0L; long networkRxBytes = 0L;
Long networkTxBytes = 0L; long networkTxBytes = 0L;
JsonNode networks = getAsObject(stats, "networks"); JsonNode networks = getAsObject(stats, "networks");
if (networks != null) { if (networks != null) {
for (Map.Entry<String, JsonNode> item : (Iterable<Map.Entry<String, JsonNode>>) networks::fields) { 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); networkTxBytes += getAsLong(network, "tx_bytes", 0L);
} }
} }
Long blockReadBytes = 0L; long blockReadBytes = 0L;
Long blockWriteBytes = 0L; long blockWriteBytes = 0L;
JsonNode blkioStats = getAsObject(stats, "blkio_stats"); JsonNode blkioStats = getAsObject(stats, "blkio_stats");
ArrayNode ioServiceBytes = blkioStats == null ? null : getAsArray(blkioStats, "io_service_bytes_recursive"); ArrayNode ioServiceBytes = blkioStats == null ? null : getAsArray(blkioStats, "io_service_bytes_recursive");
if (ioServiceBytes != null) { if (ioServiceBytes != null) {
@@ -134,7 +177,6 @@ public class DockerStatusTask implements SchedulingConfigurer {
} }
} }
Integer pids = getNestedInteger(stats, "pids_stats", "current"); Integer pids = getNestedInteger(stats, "pids_stats", "current");
container.setCpuPercent(cpuPercent); container.setCpuPercent(cpuPercent);
container.setMemoryUsageBytes(memoryUsageBytes); container.setMemoryUsageBytes(memoryUsageBytes);
container.setMemoryLimitBytes(memoryLimitBytes); container.setMemoryLimitBytes(memoryLimitBytes);

View File

@@ -28,7 +28,7 @@ public class UpsStatusTask implements SchedulingConfigurer {
private final UpsStatusClient upsStatusClient; private final UpsStatusClient upsStatusClient;
private final UpsStatusStore upsStatusStore; private final UpsStatusStore upsStatusStore;
@Value("${ups.collect-enabled:true}") @Value("${ups.collect-enabled:false}")
private boolean collectEnabled; private boolean collectEnabled;
@Value("${ups.collect-rate-ms:60000}") @Value("${ups.collect-rate-ms:60000}")

View File

@@ -18,6 +18,7 @@ import java.net.http.HttpResponse;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.Duration; import java.time.Duration;
import java.util.LinkedHashMap; 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) { private String buildRequestPath(String path, Map<String, String> queryParams) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("/"); builder.append("/");

View File

@@ -1,5 +1,9 @@
server: server:
shutdown: graceful shutdown: graceful
# 压缩
compression:
enable: true
min-response-size: 10KB
# 开发环境语言,激活开发配置时,多语言系统始终使用此语言环境 # 开发环境语言,激活开发配置时,多语言系统始终使用此语言环境
dev: dev: