feat(observability): 管理面板可观测性接真实数据——metrics/trace/audit 三端点 + 审计持久化
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- observability.go/observability_metrics.go/observability_trace.go/observability_audit.go:
  拆分保证 ≤500行/函数≤80。metrics 并发安全 MetricsCollector(方法/路径/状态计数、平均/最大延迟、
  近1s QPS窗口);trace 并发安全 RingBuffer(默认512, newest-first)+traceSink+MultiTraceWriter;
  audit AuditStore 接口+内存回退+SQLite 持久化(NewSQLiteAuditStore 参数化 SQL+audit_logs 表)。
- server.go:Deps.AuditStore + Server.obs + 3 路由 GET /admin/observability/{metrics,trace,audit};
  ObserveSpan/TraceSink 注入点;middleware logging recordMetric;audit 落库(仅 slog→Append)。
- 前端 Obs.tsx:metrics 接 4 张真实 StatCard+请求分布、trace 接 span 列表(展开 props/events)、
  audit 从后端拉(前端内存审计作回退);api.ts/types.ts 加 obs 端点/类型(AdminObservabilityMetrics/
  AdminTraceSpan/AuditRecord.id 放宽)。成本指标不伪造(保留'—'+注明)。
- wire.go 收口:Deps.AuditStore 注入 gateway.NewSQLiteAuditStore(ctx, a.db)(审计真落库),
  未注入回退内存。
- Docs/api-client.md §2/v0.6。

实机验证:三端点 200,metrics 返回 totalRequests:4/qps:4/perPath/statusCounts:{200:4}。
go build/vet/test 全绿 + 前端 tsc。trace 数据源对接(gw.TraceSink→loop tracer)因 gw/tracer
构造顺序留作可选后置(端点已就绪, 未对接 span 空)。
This commit is contained in:
Aska committed 2026-09-06 21:02:46 +08:00
1 parent 76134ed47e
commit e0a543cc37
12 files changed
+803 -22

No files matched your search

+10
View File
@@ -191,6 +191,11 @@ type Deps struct {
// RAG backs the admin knowledge-base RAG module. Optional; list/search
// return empty when unset, and write endpoints report a clear 501.
RAG RagStore
// AuditStore persists the admin audit trail (observability → audit). When nil
// the gateway degrades to an in-memory store so the endpoint still returns
// data; the composition root injects NewSQLiteAuditStore over a.db for real
// persistence. Optional.
AuditStore AuditStore
// Streaming marks the injected Loop as streaming-capable (its OnStream is
// wired to publish ws.stream_chunk). When set the hub skips its own single
// final stream_chunk emission, since deltas already stream through OnStream.
@@ -225,6 +230,7 @@ type Server struct {
users UserStore
backthink BackthinkStore
rag RagStore
obs *observability
voice VoiceService
streaming bool
frontend fs.FS
@@ -259,6 +265,7 @@ func New(cfg *config.Config, deps Deps) (*Server, error) {
users: deps.Users,
backthink: deps.Backthink,
rag: deps.RAG,
obs: newObservability(deps),
streaming: deps.Streaming,
frontend: deps.Frontend,
webhooks: deps.Webhooks,
@@ -303,6 +310,9 @@ func (s *Server) Handler() http.Handler {
mux.Handle("GET /api/v1/admin/rag", adminAuth(http.HandlerFunc(s.adminListRag)))
mux.Handle("POST /api/v1/admin/rag/query", adminAuth(http.HandlerFunc(s.adminSearchRag)))
mux.Handle("POST /api/v1/admin/rag/delete", adminAuth(http.HandlerFunc(s.adminDeleteRag)))
mux.Handle("GET /api/v1/admin/observability/metrics", adminAuth(http.HandlerFunc(s.adminObservabilityMetrics)))
mux.Handle("GET /api/v1/admin/observability/trace", adminAuth(http.HandlerFunc(s.adminObservabilityTrace)))
mux.Handle("GET /api/v1/admin/observability/audit", adminAuth(http.HandlerFunc(s.adminObservabilityAudit)))
mux.Handle("POST /api/v1/admin/plugins/policy", s.auth.Authorize(auth.RoleOwner)(http.HandlerFunc(s.adminSetPolicy)))
// External webhook callbacks (e.g. the webhook channel) are mounted without