1.30 k8s pods查询
This commit is contained in:
parent
daeb880bff
commit
2a9b896f3f
@ -123,11 +123,24 @@ public class K8sDeploymentApiController extends BaseController<K8sDeployment, K8
|
||||
|
||||
@Operation(
|
||||
summary = "查询Pod日志(引用点模式)",
|
||||
description = "基于Kubernetes Dashboard的引用点系统查询日志,支持无重复轮询和前后翻页。\n" +
|
||||
"初始加载:referenceTimestamp=newest, offsetFrom=-100, offsetTo=1\n" +
|
||||
"轮询刷新:使用上次返回的selection作为参数\n" +
|
||||
"向前翻页:offsetFrom=-200, offsetTo=-100\n" +
|
||||
"向后翻页:offsetFrom=100, offsetTo=200"
|
||||
description = "基于Kubernetes Dashboard的引用点系统查询日志,支持无重复轮询和前后翻页。\n\n" +
|
||||
"**初始加载(获取最新100行)**:\n" +
|
||||
"- referenceTimestamp=newest\n" +
|
||||
"- offsetFrom=-100\n" +
|
||||
"- 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")
|
||||
public Response<com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse> getPodLogs(
|
||||
|
||||
@ -25,9 +25,16 @@ public class K8sPodLogsResponse {
|
||||
private String containerName;
|
||||
|
||||
/**
|
||||
* 日志选择器(用于下次请求)
|
||||
* 用于向前翻页的引用点选择器
|
||||
* 使用此选择器可以获取更早的日志
|
||||
*/
|
||||
private K8sLogSelection selection;
|
||||
private K8sLogSelection referenceForPrevious;
|
||||
|
||||
/**
|
||||
* 用于向后翻页/轮询的引用点选择器
|
||||
* 使用此选择器可以获取更新的日志(轮询时使用)
|
||||
*/
|
||||
private K8sLogSelection referenceForNext;
|
||||
|
||||
/**
|
||||
* 日志行列表
|
||||
|
||||
@ -627,7 +627,7 @@ public class K8sServiceIntegrationImpl extends BaseExternalSystemIntegration imp
|
||||
false, // previous(是否查询上一个容器的日志)
|
||||
effectiveSinceSeconds, // sinceSeconds(使用智能默认值)
|
||||
effectiveTail, // tail(使用智能默认值)
|
||||
false // timestamps
|
||||
true // timestamps(必须启用,用于引用点系统)
|
||||
);
|
||||
|
||||
int logLength = logs != null ? logs.length() : 0;
|
||||
|
||||
@ -151,8 +151,8 @@ public class K8sPodServiceImpl implements IK8sPodService {
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND));
|
||||
|
||||
// 4. 调用K8s API获取原始日志(获取足够多的日志以支持切片)
|
||||
// 使用较大的tail值确保能够覆盖请求的范围
|
||||
Integer effectiveTail = Math.max(1000, Math.abs(offsetFrom) + Math.abs(offsetTo) + 100);
|
||||
// 使用较大的tail值和缓冲区确保能够覆盖请求的范围
|
||||
Integer effectiveTail = Math.max(2000, Math.abs(offsetFrom) + Math.abs(offsetTo) + 500);
|
||||
String rawLogs = k8sServiceIntegration.getPodLogs(
|
||||
externalSystem,
|
||||
namespace.getNamespaceName(),
|
||||
@ -180,7 +180,8 @@ public class K8sPodServiceImpl implements IK8sPodService {
|
||||
return new com.qqchen.deploy.backend.deploy.dto.K8sPodLogsResponse(
|
||||
podName,
|
||||
container != null ? container : "default",
|
||||
result.getSelection(),
|
||||
result.getReferenceForPrevious(),
|
||||
result.getReferenceForNext(),
|
||||
result.getLogs(),
|
||||
result.isTruncated()
|
||||
);
|
||||
|
||||
@ -23,11 +23,11 @@ public class K8sLogParser {
|
||||
|
||||
/**
|
||||
* K8s日志时间戳正则表达式
|
||||
* 匹配RFC3339格式:2025-12-13T23:27:18.124567890Z
|
||||
* 或常规格式:2025-12-13 23:27:18.124
|
||||
* 只匹配RFC3339格式:2025-12-13T23:27:18.124567890Z
|
||||
* 这是K8s API返回的标准格式(当timestamps=true时)
|
||||
*/
|
||||
private static final Pattern TIMESTAMP_PATTERN = Pattern.compile(
|
||||
"^(\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}\\.\\d+Z?)\\s"
|
||||
"^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d+Z)\\s"
|
||||
);
|
||||
|
||||
/**
|
||||
@ -131,14 +131,16 @@ public class K8sLogParser {
|
||||
*/
|
||||
public static LogSliceResult selectLogs(List<K8sLogLine> lines, K8sLogSelection selection) {
|
||||
if (lines == null || lines.isEmpty()) {
|
||||
return new LogSliceResult(Collections.emptyList(), selection, false);
|
||||
K8sLogSelection emptySelection = new K8sLogSelection("newest", -100, 0);
|
||||
return new LogSliceResult(Collections.emptyList(), emptySelection, emptySelection, false);
|
||||
}
|
||||
|
||||
// 查找引用点索引
|
||||
int referenceIndex = findReferenceIndex(lines, selection.getReferenceTimestamp());
|
||||
if (referenceIndex == -1) {
|
||||
log.warn("引用点未找到: {}", selection.getReferenceTimestamp());
|
||||
return new LogSliceResult(Collections.emptyList(), selection, false);
|
||||
K8sLogSelection emptySelection = new K8sLogSelection("newest", -100, 0);
|
||||
return new LogSliceResult(Collections.emptyList(), emptySelection, emptySelection, false);
|
||||
}
|
||||
|
||||
// 计算切片范围
|
||||
@ -164,22 +166,29 @@ public class K8sLogParser {
|
||||
// 确保范围有效
|
||||
if (fromIndex >= toIndex || fromIndex < 0 || toIndex > lines.size()) {
|
||||
log.warn("无效的切片范围: fromIndex={}, toIndex={}, size={}", fromIndex, toIndex, lines.size());
|
||||
return new LogSliceResult(Collections.emptyList(), selection, false);
|
||||
K8sLogSelection emptySelection = new K8sLogSelection("newest", -100, 0);
|
||||
return new LogSliceResult(Collections.emptyList(), emptySelection, emptySelection, false);
|
||||
}
|
||||
|
||||
// 切片
|
||||
List<K8sLogLine> result = lines.subList(fromIndex, toIndex);
|
||||
|
||||
// 创建新的引用点(使用返回结果的中间行)
|
||||
// 参考Kubernetes Dashboard: 使用实际返回日志的中间位置
|
||||
int resultMiddleIndex = fromIndex + (toIndex - fromIndex) / 2;
|
||||
K8sLogSelection newSelection = new K8sLogSelection(
|
||||
lines.get(resultMiddleIndex).getTimestamp(),
|
||||
fromIndex - resultMiddleIndex,
|
||||
toIndex - resultMiddleIndex
|
||||
// 创建两个引用点选择器
|
||||
// 1. 用于向前翻页:使用返回结果的第一行作为引用点
|
||||
K8sLogSelection referenceForPrevious = new K8sLogSelection(
|
||||
lines.get(fromIndex).getTimestamp(),
|
||||
-100, // 向前100行
|
||||
0 // 到引用点(不包含)
|
||||
);
|
||||
|
||||
return new LogSliceResult(new ArrayList<>(result), newSelection, truncated);
|
||||
// 2. 用于向后翻页/轮询:使用返回结果的最后一行作为引用点
|
||||
K8sLogSelection referenceForNext = new K8sLogSelection(
|
||||
lines.get(toIndex - 1).getTimestamp(),
|
||||
1, // 从引用点的下一行开始(不包含引用点,避免重复)
|
||||
101 // 向后100行
|
||||
);
|
||||
|
||||
return new LogSliceResult(new ArrayList<>(result), referenceForPrevious, referenceForNext, truncated);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -187,12 +196,15 @@ public class K8sLogParser {
|
||||
*/
|
||||
public static class LogSliceResult {
|
||||
private final List<K8sLogLine> logs;
|
||||
private final K8sLogSelection selection;
|
||||
private final K8sLogSelection referenceForPrevious;
|
||||
private final K8sLogSelection referenceForNext;
|
||||
private final boolean truncated;
|
||||
|
||||
public LogSliceResult(List<K8sLogLine> logs, K8sLogSelection selection, boolean truncated) {
|
||||
public LogSliceResult(List<K8sLogLine> logs, K8sLogSelection referenceForPrevious,
|
||||
K8sLogSelection referenceForNext, boolean truncated) {
|
||||
this.logs = logs;
|
||||
this.selection = selection;
|
||||
this.referenceForPrevious = referenceForPrevious;
|
||||
this.referenceForNext = referenceForNext;
|
||||
this.truncated = truncated;
|
||||
}
|
||||
|
||||
@ -200,8 +212,12 @@ public class K8sLogParser {
|
||||
return logs;
|
||||
}
|
||||
|
||||
public K8sLogSelection getSelection() {
|
||||
return selection;
|
||||
public K8sLogSelection getReferenceForPrevious() {
|
||||
return referenceForPrevious;
|
||||
}
|
||||
|
||||
public K8sLogSelection getReferenceForNext() {
|
||||
return referenceForNext;
|
||||
}
|
||||
|
||||
public boolean isTruncated() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user