package models import "time" // AppVolumeSnapshot 按小时留存「每个应用」的日志量(条数)。 // // 为什么必须落库: // // Loki 的 index/volume 只支持 namespace 级聚合(3.4 实测 aggregateBy=app 不生效), // 所以"按应用排行"只能读日志内容,成本 ∝ 时间范围: // 5 分钟 ≈ 1.3GB ≈ 10 秒 // 15 分钟 ≈ 3.9GB ≈ 20 秒 // 6 小时 ≈ 92GB ≈ 5~8 分钟 ← 页面根本等不了 // 24 小时 ≈ 370GB ≈ 不可用 // 把 per-app 数据按小时在后台算好存起来,长范围排行就变成读库(毫秒级)。 // // 采集方式:每小时第 5 分钟抓「上一个完整小时」,一条 // // sum by (app, namespace)(count_over_time({...}[1h])) // // 查询在后台跑,慢一点无所谓;页面永远读库。 type AppVolumeSnapshot struct { ID uint `json:"id"` // Hour 小时桶,格式 YYYY-MM-DDTHH(本地时区,按整点对齐) Hour string `json:"hour"` SourceID uint `json:"sourceId"` Namespace string `json:"namespace"` App string `json:"app"` // Entries 该小时的日志条数(count_over_time,要读日志内容,成本高但准确) Entries int64 `json:"entries"` // Bytes 该小时的日志体积(字节,来自 index/volume 索引接口) // // 为什么不跟 Entries 用同一条查询:按 app 取体积在 Loki 里没有"一次扫全集群"的 // 索引聚合(index/volume 的返回只带 selector 里出现的 label),所以只能一个 app // 调一次;换来的是 80ms/次的索引查询,而不是重扫整小时日志内容(约 50s)。 // 老快照(本字段上线前抓的)Bytes=0,前端据此把"体积未知"和"体积真的是 0"分开。 Bytes int64 `json:"bytes"` // Partial 该小时数据是否不完整(如平台停了一段时间后才回补,超出 Loki 保留期) Partial bool `json:"partial"` CapturedAt time.Time `json:"capturedAt"` }