diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f1db4d..20eff4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,12 @@ ### 移除 - 备份恢复功能(含 API / CLI / 手册):日志数据本体的保留与安全由对象存储与 Loki retention 承担,平台侧备份价值有限 +- 平台监控页与 `/api/v1/system/metrics-summary`:原始指标仍经标准 `/api/v1/metrics`(Prometheus 文本格式)暴露,可自行抓取 +- 资源用量弹窗的可选 Prometheus 接入(峰值/限流查询):统一以「未接入 Prometheus:暂无峰值/限流数据」提示,扩容建议基于 metrics-server 实时值 ### 新增 - 落地页(homepage/,`/homepage` 访问):产品介绍、特性、快速开始 - 用户手册文档站(docsify,`/docs` 访问):安装、部署向导、采集、查询、分析、告警、授权、备份、FAQ 十篇 -- 平台自监控(`/monitor`,管理员):请求量/5xx/DB 大小/Goroutines 统计卡,Top 路由、状态码、告警评估、Loki 查询与落盘明细(后端 `/api/v1/system/metrics-summary` 快照端点) ## [2.0.0] - 2026-10-29 diff --git a/backend/controllers/system.go b/backend/controllers/system.go index d34a5fe..d46207f 100644 --- a/backend/controllers/system.go +++ b/backend/controllers/system.go @@ -1,7 +1,6 @@ package controllers import ( - "lokistack/pkg/metrics" "github.com/gin-gonic/gin" @@ -45,7 +44,3 @@ func (ctrl *SystemController) Health(c *gin.Context) { utils.Success(c, services.SelfCheck()) } -// MetricsSummary 平台自监控快照(仅 admin;原始 Prometheus 文本在 /api/v1/metrics) -func (ctrl *SystemController) MetricsSummary(c *gin.Context) { - utils.Success(c, metrics.Snapshot()) -} diff --git a/backend/pkg/metrics/summary.go b/backend/pkg/metrics/summary.go deleted file mode 100644 index 4dc2fa2..0000000 --- a/backend/pkg/metrics/summary.go +++ /dev/null @@ -1,106 +0,0 @@ -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 -} diff --git a/backend/routers/router.go b/backend/routers/router.go index 00d8525..b3e025e 100644 --- a/backend/routers/router.go +++ b/backend/routers/router.go @@ -148,7 +148,6 @@ func SetupRouter() *gin.Engine { system.Use(middleware.AdminAuth()) { system.GET("/self-check", systemCtrl.Health) - system.GET("/metrics-summary", middleware.AdminAuth(), systemCtrl.MetricsSummary) } // 审计日志:仅管理员可查(含他人操作记录) diff --git a/backend/services/deployment_usage.go b/backend/services/deployment_usage.go index 92ad693..43bfeb6 100644 --- a/backend/services/deployment_usage.go +++ b/backend/services/deployment_usage.go @@ -4,9 +4,6 @@ import ( "context" "encoding/json" "fmt" - "net/http" - "net/url" - "os" "strconv" "strings" "time" @@ -19,7 +16,7 @@ import ( // ResourceUsage 是页面上「资源」弹框的数据。 // // 三种部署模式都能采集: -// - k8s-yaml : StatefulSet resources + metrics-server(实时用量)+ 可选 Prometheus(峰值/限流) +// - k8s-yaml : StatefulSet resources + metrics-server(实时用量) // - host-docker : docker stats / docker inspect(容器限额未设则按宿主机内存做参考) // - host-binary : ps 采集进程 CPU%/RSS(无 cgroup 限额) // @@ -45,11 +42,6 @@ type ResourceUsage struct { // 限额是否真的配置了(docker 未加 --memory 时为 false,页面不画百分比) LimitsConfigured bool `json:"limitsConfigured"` - // 可选(需 Prometheus) - CPUPeakMilli *int64 `json:"cpuPeakMilli,omitempty"` - MemPeakBytes *int64 `json:"memPeakBytes,omitempty"` - ThrottlePercent *float64 `json:"throttlePercent,omitempty"` - // 采集受限说明(如缺 metrics.k8s.io 权限、未装 metrics-server、docker 无历史数据) MetricsNote string `json:"metricsNote,omitempty"` @@ -148,7 +140,6 @@ func (s *DeploymentService) k8sUsage(ctx context.Context, d *models.LokiDeployme usage.MetricsNote = "无法解析 metrics-server 返回" } - s.applyPrometheus(usage) usage.buildHints() return usage, nil } @@ -167,29 +158,6 @@ func explainMetricsError(err error) string { } } -// applyPrometheus 补 24h 峰值与 CPU 限流率(未配置 Prometheus 地址则跳过)。 -func (s *DeploymentService) applyPrometheus(u *ResourceUsage) { - base := strings.TrimSpace(os.Getenv("LOKI_USAGE_PROMETHEUS_URL")) - if base == "" || u.Pod == "" { - if u.MetricsNote == "" { - u.MetricsNote = "未配置 Prometheus,暂无 24h 峰值与限流率" - } - return - } - sel := fmt.Sprintf(`pod=%q,namespace=%q,container="loki"`, u.Pod, u.Namespace) - if v, ok := promQueryValue(base, fmt.Sprintf(`max_over_time(sum(rate(container_cpu_usage_seconds_total{%s}[5m]))[24h:1m])`, sel)); ok { - milli := int64(v * 1000) - u.CPUPeakMilli = &milli - } - if v, ok := promQueryValue(base, fmt.Sprintf(`max_over_time(sum(container_memory_working_set_bytes{%s})[24h:1m])`, sel)); ok { - b := int64(v) - u.MemPeakBytes = &b - } - if v, ok := promQueryValue(base, fmt.Sprintf(`100 * sum(rate(container_cpu_cfs_throttled_periods_total{pod=%q,namespace=%q}[15m])) / sum(rate(container_cpu_cfs_periods_total{pod=%q,namespace=%q}[15m]))`, u.Pod, u.Namespace, u.Pod, u.Namespace)); ok { - u.ThrottlePercent = &v - } -} - // ---------- host-docker ---------- func (s *DeploymentService) dockerUsage(ctx context.Context, d *models.LokiDeployment) (*ResourceUsage, error) { @@ -245,7 +213,7 @@ func (s *DeploymentService) dockerUsage(ctx context.Context, d *models.LokiDeplo usage.MetricsNote = "docker stats 读取失败:" + err.Error() } if usage.MetricsNote == "" { - usage.MetricsNote = "Docker 部署无历史峰值;如需 24h 峰值请接入 cAdvisor/Prometheus" + usage.MetricsNote = "未接入 Prometheus:暂无峰值/限流数据" } usage.buildHints() @@ -287,14 +255,9 @@ func (s *DeploymentService) processUsage(ctx context.Context, d *models.LokiDepl // ---------- 共用:扩容建议 ---------- func (u *ResourceUsage) buildHints() { + // 峰值需 Prometheus,平台不接入:扩容建议基于 metrics-server 实时值 cpuRef := u.CPUCurrentMilli - if u.CPUPeakMilli != nil && *u.CPUPeakMilli > cpuRef { - cpuRef = *u.CPUPeakMilli - } memRef := u.MemCurrentBytes - if u.MemPeakBytes != nil && *u.MemPeakBytes > memRef { - memRef = *u.MemPeakBytes - } var notes []string if u.CPULimitMilli > 0 { @@ -319,9 +282,6 @@ func (u *ResourceUsage) buildHints() { notes = append(notes, "内存偏高") } } - if u.ThrottlePercent != nil && *u.ThrottlePercent >= 10 { - notes = append(notes, fmt.Sprintf("CPU 限流 %.0f%%", *u.ThrottlePercent)) - } if !u.Ready { notes = append(notes, "实例未就绪") } @@ -337,40 +297,6 @@ func (u *ResourceUsage) buildHints() { } } -// ---------- Prometheus ---------- - -// promQueryValue 查 Prometheus 瞬时值;未配置或失败返回 ok=false(页面降级)。 -func promQueryValue(base, expr string) (float64, bool) { - client := &http.Client{Timeout: 8 * time.Second} - u := strings.TrimSuffix(base, "/") + "/api/v1/query?query=" + url.QueryEscape(expr) - resp, err := client.Get(u) - if err != nil { - return 0, false - } - defer resp.Body.Close() - if resp.StatusCode >= 400 { - return 0, false - } - var payload struct { - Data struct { - Result []struct { - Value [2]interface{} `json:"value"` - } `json:"result"` - } `json:"data"` - } - if json.NewDecoder(resp.Body).Decode(&payload) != nil || len(payload.Data.Result) == 0 { - return 0, false - } - if len(payload.Data.Result[0].Value) < 2 { - return 0, false - } - raw, ok := payload.Data.Result[0].Value[1].(string) - if !ok { - return 0, false - } - return parseFloatSafe(raw), true -} - // ---------- 单位解析 ---------- // parseQuantityMilli 解析 CPU 用量/限额为毫核。 diff --git a/docs/user-guide/README.md b/docs/user-guide/README.md index 0854556..a43ccc2 100644 --- a/docs/user-guide/README.md +++ b/docs/user-guide/README.md @@ -8,7 +8,7 @@ LokiStack 把 Grafana Loki 日志聚合的部署、采集、查询、分析与 - **采集日志**:Promtail / Fluent Bit 采集策略可视化配置,命名空间多选、app 标签来源四级回退、敏感路径拦截。 - **查询与分析**:LogQL 高亮补全、快捷查询、Live Tail;分析页自动聚合日志量、错误与 Ingress 访问指标。 - **告警**:内置九条应用日志规则,绑定默认通道后填入飞书 Webhook 即可接收;支持冷却与风暴抑制。 -- **运维底座**:凭证加密存储、操作审计、Prometheus 自监控指标。 +- **运维底座**:凭证加密存储、操作审计、标准 Prometheus 指标端点(/api/v1/metrics)。 ## 下一步 diff --git a/frontend/src/i18n/domains.ts b/frontend/src/i18n/domains.ts index 9fe491c..e5c2ca9 100644 --- a/frontend/src/i18n/domains.ts +++ b/frontend/src/i18n/domains.ts @@ -15,8 +15,6 @@ import zhAnalysis from './locales/zh/analysis' import enAnalysis from './locales/en/analysis' import zhLogs from './locales/zh/logs' import enLogs from './locales/en/logs' -import zhMonitor from './locales/zh/monitor' -import enMonitor from './locales/en/monitor' import zhSettings from './locales/zh/settings' import enSettings from './locales/en/settings' import zhAudit from './locales/zh/audit' @@ -33,8 +31,6 @@ const DOMAIN_BUNDLES: ReadonlyArray<[string, string, object]> = [ ['en', 'analysis', enAnalysis], ['zh', 'logs', zhLogs], ['en', 'logs', enLogs], - ['zh', 'monitor', zhMonitor], - ['en', 'monitor', enMonitor], ['zh', 'settings', zhSettings], ['en', 'settings', enSettings], ['zh', 'audit', zhAudit], diff --git a/frontend/src/i18n/locales/en/common.ts b/frontend/src/i18n/locales/en/common.ts index 75d5a0e..42538c1 100644 --- a/frontend/src/i18n/locales/en/common.ts +++ b/frontend/src/i18n/locales/en/common.ts @@ -17,7 +17,6 @@ export default { logs: 'Log Query', alerts: 'Alerts', analysis: 'Log Analysis', - monitor: 'Monitor', settings: 'General', ldap: 'LDAP', registry: 'Image Registry', diff --git a/frontend/src/i18n/locales/en/deployments.ts b/frontend/src/i18n/locales/en/deployments.ts index 8560aee..10f7d05 100644 --- a/frontend/src/i18n/locales/en/deployments.ts +++ b/frontend/src/i18n/locales/en/deployments.ts @@ -123,7 +123,6 @@ export default { ready: 'Ready', notReady: 'Not ready', restarts: 'Restarts: {{count}}', - throttle: 'CPU throttled {{percent}}%', promMissing: 'Prometheus not configured: no peak/throttle data', cpu: 'CPU', memory: 'Memory', diff --git a/frontend/src/i18n/locales/en/monitor.ts b/frontend/src/i18n/locales/en/monitor.ts deleted file mode 100644 index 537fc33..0000000 --- a/frontend/src/i18n/locales/en/monitor.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Platform self-monitoring — registered via i18n/domains.ts -export default { - title: 'Platform Monitor', - subtitle: 'Runtime metrics of the platform itself: requests, DB saves, alert engine and runtime (raw Prometheus metrics at /api/v1/metrics)', - adminOnly: { - title: 'Admin only', - desc: 'Runtime metrics are available to administrators.', - }, - refresh: 'Refresh', - loadFailed: 'Failed to load metrics', - empty: 'No data yet', - stats: { - requests: 'HTTP requests', - errors5xx: '5xx errors', - dbSize: 'Database size', - goroutines: 'Goroutines', - }, - topPaths: { - title: 'Top routes by requests', - subtitle: 'Cumulative requests grouped by route template', - path: 'Route', - count: 'Requests', - }, - breakdown: { - title: 'Breakdown', - subtitle: 'Status codes / alert evaluations / Loki queries / DB saves', - byStatus: 'HTTP status codes', - alerts: 'Alert rule evaluations', - loki: 'Queries against Loki', - db: 'DB saves', - dbSaves: 'Saves', - dbFailures: 'Save failures', - }, - result: { - success: 'Success', - error: 'Failed', - fired: 'Fired', - skipped: 'No match', - cooldown: 'Cooldown suppressed', - }, - buildInfo: 'Version {{version}} · Go {{go}}', -} diff --git a/frontend/src/i18n/locales/zh/common.ts b/frontend/src/i18n/locales/zh/common.ts index 17f542b..919c83b 100644 --- a/frontend/src/i18n/locales/zh/common.ts +++ b/frontend/src/i18n/locales/zh/common.ts @@ -17,7 +17,6 @@ export default { logs: '日志查询', alerts: '日志告警', analysis: '日志分析', - monitor: '平台监控', settings: '通用配置', ldap: 'LDAP 接入', registry: '默认镜像源', diff --git a/frontend/src/i18n/locales/zh/deployments.ts b/frontend/src/i18n/locales/zh/deployments.ts index a596771..17a4434 100644 --- a/frontend/src/i18n/locales/zh/deployments.ts +++ b/frontend/src/i18n/locales/zh/deployments.ts @@ -122,7 +122,6 @@ export default { ready: '就绪', notReady: '未就绪', restarts: '重启 {{count}} 次', - throttle: 'CPU 限流 {{percent}}%', promMissing: '未接入 Prometheus:暂无峰值/限流数据', cpu: 'CPU', memory: '内存', diff --git a/frontend/src/i18n/locales/zh/monitor.ts b/frontend/src/i18n/locales/zh/monitor.ts deleted file mode 100644 index 29511ca..0000000 --- a/frontend/src/i18n/locales/zh/monitor.ts +++ /dev/null @@ -1,42 +0,0 @@ -// 平台自监控页 — 经 i18n/domains.ts 注册 -export default { - title: '平台监控', - subtitle: '平台自身运行指标:请求、数据落盘、告警引擎与运行时(原始 Prometheus 指标见 /api/v1/metrics)', - adminOnly: { - title: '仅管理员可访问', - desc: '平台运行指标面向管理员开放。', - }, - refresh: '刷新', - loadFailed: '加载监控数据失败', - empty: '暂无数据', - stats: { - requests: 'HTTP 请求总数', - errors5xx: '5xx 错误数', - dbSize: '数据库大小', - goroutines: 'Goroutines', - }, - topPaths: { - title: '请求量 Top 路由', - subtitle: '按路由模板聚合的累计请求数', - path: '路由', - count: '请求数', - }, - breakdown: { - title: '分布明细', - subtitle: '状态码 / 告警评估 / Loki 查询 / 数据落盘', - byStatus: 'HTTP 状态码', - alerts: '告警规则评估', - loki: '对 Loki 的查询', - db: '数据落盘', - dbSaves: '落盘次数', - dbFailures: '落盘失败', - }, - result: { - success: '成功', - error: '失败', - fired: '已触发', - skipped: '未命中', - cooldown: '冷却抑制', - }, - buildInfo: '版本 {{version}} · Go {{go}}', -} diff --git a/frontend/src/pages/deployments/components/DeploymentUsageDialog.tsx b/frontend/src/pages/deployments/components/DeploymentUsageDialog.tsx index 852ea03..fafa055 100644 --- a/frontend/src/pages/deployments/components/DeploymentUsageDialog.tsx +++ b/frontend/src/pages/deployments/components/DeploymentUsageDialog.tsx @@ -22,9 +22,6 @@ interface Usage { memCurrentBytes: number memRequestBytes: number memLimitBytes: number - cpuPeakMilli?: number - memPeakBytes?: number - throttlePercent?: number cpuSuggest?: string memSuggest?: string summary: string @@ -34,12 +31,11 @@ const gb = (bytes: number) => (bytes / 1024 ** 3).toFixed(2) const cores = (milli: number) => (milli / 1000).toFixed(2) /** 用条形容使用率;超 90% 红、70% 黄、其余绿 */ -function UsageBar({ label, current, limit, format, peak }: { +function UsageBar({ label, current, limit, format }: { label: string current: number limit: number format: (v: number) => string - peak?: number }) { const ratio = limit > 0 ? Math.min(1, current / limit) : 0 const tone = ratio >= 0.9 ? 'bg-destructive' : ratio >= 0.7 ? 'bg-warning' : 'bg-success' @@ -49,7 +45,6 @@ function UsageBar({ label, current, limit, format, peak }: { {label} {format(current)} / {format(limit)}({(ratio * 100).toFixed(0)}%) - {peak !== undefined && peak > 0 && 峰值 {format(peak)}}
@@ -120,12 +115,7 @@ export const DeploymentUsageDialog = memo(function DeploymentUsageDialog({ deplo {usage.source} {t('usage.restarts', { count: usage.restarts })} - {usage.throttlePercent !== undefined && ( - = 10 ? 'rounded bg-warning/15 px-2 py-0.5 text-warning' : 'text-muted-foreground'}> - {t('usage.throttle', { percent: usage.throttlePercent.toFixed(1) })} - - )} - {usage.throttlePercent === undefined && {t('usage.promMissing')}} + {t('usage.promMissing')}
{usage.limitsConfigured ? ( @@ -134,14 +124,12 @@ export const DeploymentUsageDialog = memo(function DeploymentUsageDialog({ deplo label={t('usage.cpu')} current={usage.cpuCurrentMilli} limit={usage.cpuLimitMilli} - peak={usage.cpuPeakMilli} format={v => `${cores(v)} 核`} /> `${gb(v)} GiB`} /> diff --git a/frontend/src/pages/monitor/index.tsx b/frontend/src/pages/monitor/index.tsx deleted file mode 100644 index 4505501..0000000 --- a/frontend/src/pages/monitor/index.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import { memo, useCallback, useEffect, useRef, useState } from 'react' -import { useTranslation } from 'react-i18next' -import '@/i18n/domains' -import { Activity, Database, Gauge, Loader2, RefreshCw } from 'lucide-react' -import { Button } from '@/components/ui/button' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { PageContainer } from '@/components/PageContainer' -import { EmptyState } from '@/components/EmptyState' -import { ErrorState } from '@/components/ErrorState' -import { LoadingSpinner } from '@/components/LoadingSpinner' -import { StatCard } from '@/components/StatCard' -import { http } from '@/api/http' -import { getUser } from '@/lib/auth-storage' - -interface PathCount { path: string; count: number } -interface Summary { - http: { total: number; byStatus: Record; inFlight: number; topPaths: PathCount[] } - db: { sizeBytes: number; saves: number; saveFailures: number; records: Record } - alerts: { evaluations: Record } - loki: { queries: Record } - runtime: { goroutines: number; goVersion: string; version: string } -} - -const fmtBytes = (n: number) => { - if (n >= 1 << 30) return `${(n / (1 << 30)).toFixed(2)} GB` - if (n >= 1 << 20) return `${(n / (1 << 20)).toFixed(1)} MB` - if (n >= 1 << 10) return `${(n / (1 << 10)).toFixed(1)} KB` - return `${n} B` -} - -/** 平台自监控(admin):聚合 /metrics 为可读快照 — 请求/DB/告警引擎/运行时 */ -const MonitorPage = memo(function MonitorPage() { - const { t } = useTranslation('monitor') - const isAdmin = getUser()?.role === 'admin' - const [data, setData] = useState(null) - const [loading, setLoading] = useState(false) - const [error, setError] = useState('') - const versionRef = useRef(0) - - const load = useCallback(() => { - const v = ++versionRef.current - setLoading(true) - setError('') - http.get('/system/metrics-summary') - .then(result => { if (v === versionRef.current) setData(result) }) - .catch(err => { if (v === versionRef.current) setError(err instanceof Error ? err.message : t('loadFailed')) }) - .finally(() => { if (v === versionRef.current) setLoading(false) }) - }, [t]) - - useEffect(() => { - if (isAdmin) load() - }, [isAdmin, load]) - - if (!isAdmin) { - return ( - - - - ) - } - - const statusEntries = data ? Object.entries(data.http.byStatus).sort(([a], [b]) => a.localeCompare(b)) : [] - const err5xx = statusEntries.filter(([code]) => code.startsWith('5')).reduce((acc, [, v]) => acc + v, 0) - - return ( - - {loading ? : } - {t('refresh')} - - } - > - {error ? ( - - ) : loading && !data ? ( - - ) : !data ? null : ( - <> -
- - 0 ? 'text-destructive' : 'text-muted-foreground'} iconBg={err5xx > 0 ? 'bg-destructive/10' : 'bg-muted'} /> - - -
- -
- - - {t('topPaths.title')} -

{t('topPaths.subtitle')}

-
- - {data.http.topPaths.length === 0 ? ( -

{t('empty')}

- ) : ( - - - - - - {data.http.topPaths.map(item => ( - - - - - ))} - -
{t('topPaths.path')}{t('topPaths.count')}
{item.path}{item.count.toLocaleString()}
- )} -
-
- - - - {t('breakdown.title')} -

{t('breakdown.subtitle')}

-
- -
-

{t('breakdown.byStatus')}

- {statusEntries.length === 0 ?

{t('empty')}

: statusEntries.map(([code, count]) => ( -
- {code} - {count.toLocaleString()} -
- ))} -
-
-

{t('breakdown.alerts')}

- {Object.entries(data.alerts.evaluations).map(([result, count]) => ( -
- {t(`result.${result}`, result)} - {count.toLocaleString()} -
- ))} -
-
-

{t('breakdown.loki')}

- {Object.entries(data.loki.queries).map(([result, count]) => ( -
- {t(`result.${result}`, result)} - {count.toLocaleString()} -
- ))} -
-
-

{t('breakdown.db')}

-
{t('breakdown.dbSaves')}{data.db.saves.toLocaleString()}
-
0 ? 'text-destructive' : 'text-muted-foreground'}>{t('breakdown.dbFailures')}{data.db.saveFailures.toLocaleString()}
-
-

{t('buildInfo', { version: data.runtime.version || '-', go: data.runtime.goVersion || '-' })}

-
-
-
- - )} -
- ) -}) - -export default MonitorPage diff --git a/frontend/src/router/routes.tsx b/frontend/src/router/routes.tsx index f5cc1bb..8233d87 100644 --- a/frontend/src/router/routes.tsx +++ b/frontend/src/router/routes.tsx @@ -15,7 +15,6 @@ import { ScrollText, BellRing, BarChart3, - Activity, History, Boxes, ShieldCheck, @@ -39,7 +38,6 @@ const LogsPage = lazy(() => import('@/pages/logs')); const AlertsPage = lazy(() => import('@/pages/alerts')); const UsersPage = lazy(() => import('@/pages/users')); const AnalysisPage = lazy(() => import('@/pages/analysis')); -const MonitorPage = lazy(() => import('@/pages/monitor')); const AuditPage = lazy(() => import('@/pages/audit')); export const routes: AppRoute[] = [ @@ -72,7 +70,6 @@ export const routes: AppRoute[] = [ // ── 日志查询 / 日志分析:高频入口,保持独立菜单项(不折叠)── { path: '/logs', component: LogsPage, auth: true, meta: { title: 'menu.logs', icon: ScrollText, order: 5 } }, { path: '/analysis', component: AnalysisPage, auth: true, meta: { title: 'menu.analysis', icon: BarChart3, order: 6, adminOnly: true } }, - { path: '/monitor', component: MonitorPage, auth: true, meta: { title: 'menu.monitor', icon: Activity, order: 6.5, adminOnly: true } }, // ── 告警:独立入口(要盯的,不能被折叠) ── // 告警仅管理员:普通用户按「查询授权」只看指定的日志(菜单只剩日志查询)。 diff --git a/homepage/index.html b/homepage/index.html index bf2ed40..00970ce 100644 --- a/homepage/index.html +++ b/homepage/index.html @@ -70,7 +70,7 @@

工程级可靠性

-

Credential 加密存储、操作审计、备份恢复、Prometheus 自监控指标、CI 门禁与测试覆盖,按生产标准构建。

+

凭证加密存储、操作审计、标准 Prometheus 指标端点、CI 门禁与测试覆盖,按生产标准构建。