From 17059bff98672ae6c98372c7efea523a44917e8f Mon Sep 17 00:00:00 2001 From: attacker Date: Sat, 27 Jun 2026 10:28:41 +0000 Subject: [PATCH] =?UTF-8?q?fix(log):=20normalizeTime=20=E2=80=94=20auto-ap?= =?UTF-8?q?pend=20.000ms=20for=20ES=207.2.0=20date=5Ftime=20compat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frontend may send dates without milliseconds (e.g. 2026-06-27T09:09:17Z), which ES 7.2.0 strict_date_optional_time rejects. Backend now detects missing milliseconds and inserts .000 before timezone suffix. --- backend/controller/log_proxy.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/backend/controller/log_proxy.go b/backend/controller/log_proxy.go index 9930f22..dfe0cc1 100644 --- a/backend/controller/log_proxy.go +++ b/backend/controller/log_proxy.go @@ -149,7 +149,28 @@ func (h *LogProxyHandler) QueryES(c *gin.Context) { }, } if req.Start != "" || req.End != "" { - // ES 7.2 date_time 仅接受 .SSSZ 格式;兼容 @timestamp 与 timestamp // Logan.Li + // ES 7.2 date_time 仅接受 .SSSZ 格式(strict_date_optional_time 不含 epoch_millis) + // 兼容各种前端时间格式:补全毫秒 // Logan.Li + normalizeTime := func(s string) string { + if s == "" { + return s + } + // 查找时间部分结束位置(Z 或 +) + tzIdx := strings.IndexAny(s, "Z+") + timePart := s + tzPart := "" + if tzIdx >= 0 { + timePart = s[:tzIdx] + tzPart = s[tzIdx:] + } + // 如果已有毫秒部分(.后跟数字),直接返回 + if dotIdx := strings.LastIndexByte(timePart, '.'); dotIdx >= 0 { + if dotIdx+1 < len(timePart) && timePart[dotIdx+1] >= '0' && timePart[dotIdx+1] <= '9' { + return s + } + } + return timePart + ".000" + tzPart + } rangeCond := map[string]interface{}{ "bool": map[string]interface{}{ "should": []interface{}{ @@ -164,10 +185,10 @@ func (h *LogProxyHandler) QueryES(c *gin.Context) { for _, v := range rng { r := v.(map[string]string) if req.Start != "" { - r["gte"] = req.Start + r["gte"] = normalizeTime(req.Start) } if req.End != "" { - r["lte"] = req.End + r["lte"] = normalizeTime(req.End) } } }