1.30 k8s pods查询

This commit is contained in:
dengqichen 2025-12-14 13:38:50 +08:00
parent 4e87fc1b98
commit dfbf8e4f0a
3 changed files with 48 additions and 57 deletions

View File

@ -123,24 +123,10 @@ public class K8sDeploymentApiController extends BaseController<K8sDeployment, K8
@Operation( @Operation(
summary = "查询Pod日志引用点模式", summary = "查询Pod日志引用点模式",
description = "基于Kubernetes Dashboard的引用点系统查询日志支持无重复轮询和前后翻页。\n\n" + description = "基于引用点系统查询日志,支持无重复轮询和前后翻页。\n\n" +
"**初始加载获取最新100行**\n" + "**初始加载**referenceTimestamp=newest, logCount=500\n\n" +
"- referenceTimestamp=newest\n" + "**向上加载历史日志**referenceTimestamp=上次的referenceForPrevious.referenceTimestamp, direction=prev, logCount=500\n\n" +
"- offsetFrom=-100\n" + "**向下加载/轮询新日志**referenceTimestamp=上次的referenceForNext.referenceTimestamp, direction=next, logCount=100"
"- offsetTo=0\n\n" +
"**轮询刷新(获取新日志)**\n" +
"- 使用上次返回的 referenceForNext.referenceTimestamp\n" +
"- 使用上次返回的 referenceForNext.offsetFrom (固定为0)\n" +
"- 使用上次返回的 referenceForNext.offsetTo (固定为100)\n\n" +
"**向前翻页(获取更早的日志)**\n" +
"- 使用上次返回的 referenceForPrevious.referenceTimestamp\n" +
"- 使用上次返回的 referenceForPrevious.offsetFrom (固定为-100)\n" +
"- 使用上次返回的 referenceForPrevious.offsetTo (固定为0)\n\n" +
"**响应字段说明**\n" +
"- referenceForPrevious: 用于向前翻页的选择器\n" +
"- referenceForNext: 用于向后翻页/轮询的选择器\n" +
"- logs: 当前返回的日志行列表\n" +
"- truncated: 是否因边界限制被截断"
) )
@GetMapping("/{deploymentId}/pods/{podName}/logs") @GetMapping("/{deploymentId}/pods/{podName}/logs")
public Response<com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse> getPodLogs( public Response<com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse> getPodLogs(
@ -148,10 +134,10 @@ public class K8sDeploymentApiController extends BaseController<K8sDeployment, K8
@Parameter(description = "Pod名称", required = true) @PathVariable String podName, @Parameter(description = "Pod名称", required = true) @PathVariable String podName,
@Parameter(description = "容器名称(可选,默认第一个容器)") @RequestParam(required = false) String container, @Parameter(description = "容器名称(可选,默认第一个容器)") @RequestParam(required = false) String container,
@Parameter(description = "引用点时间戳newest/oldest/具体时间戳)", required = false) @RequestParam(required = false, defaultValue = "newest") String referenceTimestamp, @Parameter(description = "引用点时间戳newest/oldest/具体时间戳)", required = false) @RequestParam(required = false, defaultValue = "newest") String referenceTimestamp,
@Parameter(description = "起始偏移量(相对于引用点)", required = false) @RequestParam(required = false, defaultValue = "-100") Integer offsetFrom, @Parameter(description = "方向prev向上加载历史日志next向下加载新日志", required = false) @RequestParam(required = false, defaultValue = "next") String direction,
@Parameter(description = "结束偏移量(相对于引用点)", required = false) @RequestParam(required = false, defaultValue = "1") Integer offsetTo @Parameter(description = "每次加载的行数默认100", required = false) @RequestParam(required = false, defaultValue = "100") Integer logCount
) { ) {
return Response.success(k8sPodService.getPodLogsWithReference(deploymentId, podName, container, referenceTimestamp, offsetFrom, offsetTo)); return Response.success(k8sPodService.getPodLogsWithReference(deploymentId, podName, container, referenceTimestamp, direction, logCount));
} }
@Operation(summary = "重启Deployment", description = "通过更新annotation触发Deployment滚动重启") @Operation(summary = "重启Deployment", description = "通过更新annotation触发Deployment滚动重启")

View File

@ -60,12 +60,12 @@ public interface IK8sPodService {
* @param deploymentId Deployment ID * @param deploymentId Deployment ID
* @param podName Pod名称 * @param podName Pod名称
* @param container 容器名称可选 * @param container 容器名称可选
* @param referenceTimestamp 引用点时间戳 * @param referenceTimestamp 引用点时间戳newest/oldest/具体时间戳
* @param offsetFrom 起始偏移量 * @param direction 方向prev向上(历史日志)next向下(新日志)
* @param offsetTo 结束偏移量 * @param logCount 每次加载的行数
* @return Pod日志响应 * @return Pod日志响应
*/ */
com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse getPodLogsWithReference( com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse getPodLogsWithReference(
Long deploymentId, String podName, String container, Long deploymentId, String podName, String container,
String referenceTimestamp, Integer offsetFrom, Integer offsetTo); String referenceTimestamp, String direction, Integer logCount);
} }

View File

@ -133,10 +133,10 @@ public class K8sPodServiceImpl implements IK8sPodService {
@Override @Override
public com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse getPodLogsWithReference( public com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse getPodLogsWithReference(
Long deploymentId, String podName, String container, Long deploymentId, String podName, String container,
String referenceTimestamp, Integer offsetFrom, Integer offsetTo) { String referenceTimestamp, String direction, Integer logCount) {
log.info("查询Pod日志引用点模式deploymentId: {}, podName: {}, container: {}, referenceTimestamp: {}, offsetFrom: {}, offsetTo: {}", log.info("查询Pod日志引用点模式deploymentId: {}, podName: {}, container: {}, referenceTimestamp: {}, direction: {}, logCount: {}",
deploymentId, podName, container, referenceTimestamp, offsetFrom, offsetTo); deploymentId, podName, container, referenceTimestamp, direction, logCount);
// 1. 查询K8sDeployment // 1. 查询K8sDeployment
K8sDeployment deployment = k8sDeploymentRepository.findById(deploymentId) K8sDeployment deployment = k8sDeploymentRepository.findById(deploymentId)
@ -150,37 +150,52 @@ public class K8sPodServiceImpl implements IK8sPodService {
ExternalSystem externalSystem = externalSystemRepository.findById(deployment.getExternalSystemId()) ExternalSystem externalSystem = externalSystemRepository.findById(deployment.getExternalSystemId())
.orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND)); .orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND));
// 4. 调用K8s API获取原始日志获取足够多的日志以支持切片 // 4. 计算有效的日志行数默认100行
// 使用较大的tail值和缓冲区确保能够覆盖请求的范围 int effectiveLogCount = (logCount != null && logCount > 0) ? logCount : 100;
Integer effectiveTail = Math.max(10000, Math.abs(offsetFrom) + Math.abs(offsetTo) + 2000);
// 5. 根据direction计算offsetFrom和offsetTo
int offsetFrom;
int offsetTo;
if ("prev".equalsIgnoreCase(direction)) {
// 向上加载历史日志
offsetFrom = -effectiveLogCount;
offsetTo = 0;
} else {
// 向下加载新日志next或默认
offsetFrom = 0;
offsetTo = effectiveLogCount;
}
// 6. 调用K8s API获取原始日志
Integer effectiveTail = Math.max(10000, effectiveLogCount + 2000);
String rawLogs = k8sServiceIntegration.getPodLogs( String rawLogs = k8sServiceIntegration.getPodLogs(
externalSystem, externalSystem,
namespace.getNamespaceName(), namespace.getNamespaceName(),
podName, podName,
container, container,
effectiveTail, effectiveTail,
null, // 不使用sinceSeconds获取更多历史日志 null,
false false
); );
// 5. 解析日志 // 7. 解析日志
List<com.qqchen.deploy.backend.deploy.dto.K8sLogLine> logLines = List<com.qqchen.deploy.backend.deploy.dto.K8sLogLine> logLines =
com.qqchen.deploy.backend.deploy.utils.K8sLogParser.parseLogLines(rawLogs); com.qqchen.deploy.backend.deploy.utils.K8sLogParser.parseLogLines(rawLogs);
log.debug("解析到 {} 行日志", logLines.size()); log.debug("解析到 {} 行日志", logLines.size());
// 6. 创建选择器 // 8. 创建选择器
com.qqchen.deploy.backend.deploy.dto.K8sLogSelection selection = com.qqchen.deploy.backend.deploy.dto.K8sLogSelection selection =
new com.qqchen.deploy.backend.deploy.dto.K8sLogSelection( new com.qqchen.deploy.backend.deploy.dto.K8sLogSelection(
referenceTimestamp, offsetFrom, offsetTo); referenceTimestamp, offsetFrom, offsetTo);
// 7. 切片日志 // 9. 切片日志
com.qqchen.deploy.backend.deploy.utils.K8sLogParser.LogSliceResult result = com.qqchen.deploy.backend.deploy.utils.K8sLogParser.LogSliceResult result =
com.qqchen.deploy.backend.deploy.utils.K8sLogParser.selectLogs(logLines, selection); com.qqchen.deploy.backend.deploy.utils.K8sLogParser.selectLogs(logLines, selection);
// 8. 如果返回空日志直接返回空响应引用点可能已丢失 // 10. 如果返回空日志直接返回空响应
if (result.getLogs().isEmpty()) { if (result.getLogs().isEmpty()) {
log.warn("引用点定位失败返回空日志。referenceTimestamp: {}", referenceTimestamp); log.warn("引用点定位失败或无更多日志referenceTimestamp: {}, direction: {}", referenceTimestamp, direction);
return new com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse( return new com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse(
podName, podName,
@ -192,32 +207,22 @@ public class K8sPodServiceImpl implements IK8sPodService {
); );
} }
// 9. 使用中点策略计算新的引用点Kubernetes Dashboard策略 // 11. 计算新的引用点使用返回结果的第一行和最后一行
// 中点引用点不容易因为日志增删而丢失 String firstTimestamp = result.getLogs().get(0).getTimestamp();
int midIndex = result.getLogs().size() / 2; String lastTimestamp = result.getLogs().get(result.getLogs().size() - 1).getTimestamp();
String midTimestamp = result.getLogs().get(midIndex).getTimestamp();
log.debug("返回 {} 行日志,中点索引: {}, 中点时间戳: {}", log.debug("返回 {} 行日志,第一行时间戳: {}, 最后一行时间戳: {}",
result.getLogs().size(), midIndex, midTimestamp); result.getLogs().size(), firstTimestamp, lastTimestamp);
// 10. 构建referenceForPrevious向前翻页 // 12. 构建referenceForPrevious用于向上加载使用第一行时间戳
com.qqchen.deploy.backend.deploy.dto.K8sLogSelection referenceForPrevious = com.qqchen.deploy.backend.deploy.dto.K8sLogSelection referenceForPrevious =
new com.qqchen.deploy.backend.deploy.dto.K8sLogSelection( new com.qqchen.deploy.backend.deploy.dto.K8sLogSelection(firstTimestamp, -effectiveLogCount, 0);
midTimestamp,
-midIndex - 100, // 从中点向前100行
-midIndex
);
// 11. 构建referenceForNext向后翻页 // 13. 构建referenceForNext用于向下加载使用最后一行时间戳
int remainingAfterMid = result.getLogs().size() - midIndex;
com.qqchen.deploy.backend.deploy.dto.K8sLogSelection referenceForNext = com.qqchen.deploy.backend.deploy.dto.K8sLogSelection referenceForNext =
new com.qqchen.deploy.backend.deploy.dto.K8sLogSelection( new com.qqchen.deploy.backend.deploy.dto.K8sLogSelection(lastTimestamp, 1, effectiveLogCount + 1);
midTimestamp,
remainingAfterMid, // 从中点向后
remainingAfterMid + 100 // 向后100行
);
// 12. 构建响应 // 14. 构建响应
return new com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse( return new com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse(
podName, podName,
container != null ? container : "default", container != null ? container : "default",