feat(logs): 分页显示总页数(新增 /logs/stats,走 index/stats 只读索引)
用户反馈:底部只有「上一页 第 1 页 下一页」,看不到末尾/总页数。
原因:日志结果是 Loki 游标分页(cursor = 纳秒时间戳),本身不返回总数,
前端只能知道"有没有下一页",算不出总页数。
解法:新增 POST /api/v1/logs/stats
→ 调 Loki /loki/api/v1/index/stats(只读 TSDB 索引里的 chunk 元数据)
→ 返回 {streams, chunks, bytes, entries}
→ 前端用 entries / limit 得到总页数
实测成本极低:1h 51ms、24h 30ms(3.28 亿条 / 44.2 GB)。
改动:
1. backend: services.LokiStatsFor + controllers.LogsController.Stats + 路由 /logs/stats
2. frontend: logsApi.stats;查询成功后拉取总数(复用同一 AbortController,
失败静默不影响日志展示);计算 totalPages 传给结果面板
3. LogResultsPanel: 有总数时显示「第 N / M 页」,否则维持「第 N 页」
4. i18n: 新增 results.pageOfTotal(中英)
镜像:lghost/lokistack:latest + v0.1 = sha256:41d6576ec232
This commit is contained in:
1 parent
de376a1284
commit
5d530036e6
8 files changed
+88
-5
No files matched your search
@@ -544,6 +544,44 @@ func lokiHistogramByCount(ctx context.Context, src *models.LogSource, query, ste
|
||||
return buckets, nil
|
||||
}
|
||||
|
||||
// LokiStats 用官方 /loki/api/v1/index/stats 取「条数/字节/块数」。
|
||||
//
|
||||
// 为什么不数日志条数:index/stats 只读 TSDB 索引里的 chunk 元数据,
|
||||
// 不解码日志内容。实测同一 app 24 小时:count_over_time 53s 失败,
|
||||
// index/stats 1.3s。用它来算「共 N 条 / 共 M 页」成本可以忽略。
|
||||
type LokiStats struct {
|
||||
Streams int64 `json:"streams"`
|
||||
Chunks int64 `json:"chunks"`
|
||||
Bytes int64 `json:"bytes"`
|
||||
Entries int64 `json:"entries"`
|
||||
}
|
||||
|
||||
func LokiStatsFor(ctx context.Context, src *models.LogSource, query string, start, end int64) (*LokiStats, error) {
|
||||
if end <= 0 {
|
||||
end = time.Now().UnixNano()
|
||||
}
|
||||
if start <= 0 {
|
||||
start = end - int64(time.Hour)
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(ctx, 20*time.Second)
|
||||
defer cancel()
|
||||
|
||||
q := url.Values{}
|
||||
q.Set("query", query)
|
||||
q.Set("start", strconv.FormatInt(start, 10))
|
||||
q.Set("end", strconv.FormatInt(end, 10))
|
||||
|
||||
body, _, err := lokiProxyGET(ctx, src, "/loki/api/v1/index/stats", q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var st LokiStats
|
||||
if err := json.Unmarshal(body, &st); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &st, nil
|
||||
}
|
||||
|
||||
// MetricSeriesPoint 指标序列上的一个采样点
|
||||
type MetricSeriesPoint struct {
|
||||
Timestamp string `json:"timestamp"`
|
||||
|
||||
Reference in new issue
Block a user