- homepage/:品牌落地页(Hero/特性/快速开始),参考 opsxapi 站点风格,绿色品牌系 - docs/:docsify 文档站 + user-guide 十篇手册(安装/向导/采集/查询/分析/告警/授权/备份/FAQ) - 后端 serveStaticDir 挂载 /docs 与 /homepage(可执行文件相对定位,独立于前端 dist)
107 lines
3.1 KiB
Go
107 lines
3.1 KiB
Go
package metrics
|
|
|
|
import (
|
|
"sort"
|
|
|
|
dto "github.com/prometheus/client_model/go"
|
|
)
|
|
|
|
// PathCount 单个路由模板的累计请求数
|
|
type PathCount struct {
|
|
Path string `json:"path"`
|
|
Count float64 `json:"count"`
|
|
}
|
|
|
|
// Summary 面板自监控快照:从 registry 聚合出的精简结构(/api/v1/system/metrics-summary)
|
|
type Summary struct {
|
|
HTTP struct {
|
|
Total float64 `json:"total"`
|
|
ByStatus map[string]float64 `json:"byStatus"`
|
|
InFlight float64 `json:"inFlight"`
|
|
TopPaths []PathCount `json:"topPaths"`
|
|
} `json:"http"`
|
|
DB struct {
|
|
SizeBytes float64 `json:"sizeBytes"`
|
|
Saves float64 `json:"saves"`
|
|
SaveFailures float64 `json:"saveFailures"`
|
|
Records map[string]float64 `json:"records"`
|
|
} `json:"db"`
|
|
Alerts struct {
|
|
Evaluations map[string]float64 `json:"evaluations"`
|
|
} `json:"alerts"`
|
|
Loki struct {
|
|
Queries map[string]float64 `json:"queries"`
|
|
} `json:"loki"`
|
|
Runtime struct {
|
|
Goroutines float64 `json:"goroutines"`
|
|
GoVersion string `json:"goVersion"`
|
|
Version string `json:"version"`
|
|
} `json:"runtime"`
|
|
}
|
|
|
|
// Snapshot 聚合当前指标为面板结构(聚合失败返回零值,监控页降级展示)
|
|
func Snapshot() Summary {
|
|
s := Summary{}
|
|
s.HTTP.ByStatus = map[string]float64{}
|
|
s.DB.Records = map[string]float64{}
|
|
s.Alerts.Evaluations = map[string]float64{}
|
|
s.Loki.Queries = map[string]float64{}
|
|
|
|
families, err := registry.Gather()
|
|
if err != nil {
|
|
return s
|
|
}
|
|
byPath := map[string]float64{}
|
|
for _, mf := range families {
|
|
for _, m := range mf.GetMetric() {
|
|
labels := labelMap(m)
|
|
switch mf.GetName() {
|
|
case "lokistack_http_requests_total":
|
|
v := m.GetCounter().GetValue()
|
|
s.HTTP.Total += v
|
|
s.HTTP.ByStatus[labels["status"]] += v
|
|
byPath[labels["path"]] += v
|
|
case "lokistack_http_in_flight_requests":
|
|
s.HTTP.InFlight = m.GetGauge().GetValue()
|
|
case "lokistack_db_size_bytes":
|
|
s.DB.SizeBytes = m.GetGauge().GetValue()
|
|
case "lokistack_db_save_total":
|
|
v := m.GetCounter().GetValue()
|
|
s.DB.Saves += v
|
|
if labels["result"] != "success" {
|
|
s.DB.SaveFailures += v
|
|
}
|
|
case "lokistack_db_records":
|
|
s.DB.Records[labels["collection"]] = m.GetGauge().GetValue()
|
|
case "lokistack_alert_evaluations_total":
|
|
s.Alerts.Evaluations[labels["result"]] += m.GetCounter().GetValue()
|
|
case "lokistack_loki_queries_total":
|
|
s.Loki.Queries[labels["result"]] += m.GetCounter().GetValue()
|
|
case "go_goroutines":
|
|
s.Runtime.Goroutines = m.GetGauge().GetValue()
|
|
case "lokistack_build_info":
|
|
s.Runtime.GoVersion = labels["go_version"]
|
|
s.Runtime.Version = labels["version"]
|
|
}
|
|
}
|
|
}
|
|
paths := make([]PathCount, 0, len(byPath))
|
|
for p, c := range byPath {
|
|
paths = append(paths, PathCount{Path: p, Count: c})
|
|
}
|
|
sort.Slice(paths, func(i, j int) bool { return paths[i].Count > paths[j].Count })
|
|
if len(paths) > 8 {
|
|
paths = paths[:8]
|
|
}
|
|
s.HTTP.TopPaths = paths
|
|
return s
|
|
}
|
|
|
|
func labelMap(m *dto.Metric) map[string]string {
|
|
out := map[string]string{}
|
|
for _, lp := range m.GetLabel() {
|
|
out[lp.GetName()] = lp.GetValue()
|
|
}
|
|
return out
|
|
}
|