feat(observability): 日志聚合后端 — logger环形缓冲 + GET /admin/observability/logs
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- internal/logger/ring.go: Entry{time,level,source,msg} + RingBuffer(2000,满覆盖最旧,不阻塞)+ringHandler(slog旁路,Enabled委托内层,sourceOf提取source=再回落Scoped); Options.Ring非nil才包
- gateway/observability_logs.go: GET /admin/observability/logs?level=&limit= (writeAuth owner/admin) → {data:[{time(RFC3339 UTC),level,source,msg}]} 最新在前; level阈值过滤(warn=warn+error,已标注取舍); limit缺省200上限1000; 未知level400/未注入501
- routes.go注册 + observability.go SetLogBuffer(atomic.Pointer) + cmd/cyrene main.go/wireGatewayLogBuffer接线(logger先于gateway)
- 控制台/文件输出零变化; 记录只源自已产出日志,不额外打印敏感
- Docs/api-client v0.35; 测试(ring 10 + observability_logs 8 + cmd端到端2); build/vet/test绿(56)+win/darwin交叉编译
This commit is contained in:
AskaEth committed 2026-10-03 15:22:03 +08:00
1 parent 79589b5c9f
commit 025dd1796b
11 files changed
+850 -6

No files matched your search

+15
View File
@@ -5,6 +5,7 @@ import (
"os"
"sync"
"git.yeij.top/AskaEth/Cyrene_v2/internal/logger"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/trace"
"git.yeij.top/AskaEth/Cyrene_v2/internal/services/gateway"
)
@@ -81,6 +82,20 @@ func (f *traceFanout) WriteSpan(rec trace.SpanRecord) error {
return firstErr
}
// wireGatewayLogBuffer hands the composition root's log ring buffer to the
// gateway, so GET /api/v1/admin/observability/logs serves the recent backend log
// tail. The logger is built before the gateway (its records must be captured
// from the first log line), so the buffer is injected here, the first moment the
// gateway exists — like wireGatewayTraceSink does for spans. It is a no-op on a
// boot without a gateway.
func wireGatewayLogBuffer(a *app, buf *logger.RingBuffer) {
if a == nil || a.gw == nil || buf == nil {
return
}
a.gw.SetLogBuffer(buf)
a.log.Info("observability log buffer wired", "capacity", buf.Len())
}
// gatewaySpanSink adapts *gateway.Server to trace.Writer through its ObserveSpan
// entry point, so an emitted span lands in the admin panel's trace ring buffer
// AND in the LLM/subagent metric counters (ObserveSpan appends to the buffer and