主人 2026-10-03 拍板「注释一律中文」;gateway 至此整包注释中文化完成(本会话共 3 批: 已推库 16 个文件 + 本批剩余文件)。 校验:机械校验(非注释改动行)= 空;剥注释后代码文本逐行比对全等(不一致文件数 0); 全树 go test ./... 58 包 ok / 0 FAIL;交叉编译绿。
138 lines
3.7 KiB
Go
138 lines
3.7 KiB
Go
package gateway
|
||
|
||
import (
|
||
"sync"
|
||
"time"
|
||
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/trace"
|
||
)
|
||
|
||
// defaultTraceBufCap 是环形缓冲在逐出最旧 span 之前持有的已
|
||
// 完成 span 数。编译期常量。
|
||
const defaultTraceBufCap = 512
|
||
|
||
// AdminTraceSpan 是一个已追踪 span 的驼峰式线上结构。它把
|
||
// 前端与 trace 包蛇形命名的 SpanRecord 解耦。
|
||
type AdminTraceSpan struct {
|
||
ID string `json:"id"`
|
||
ParentID string `json:"parentId,omitempty"`
|
||
Name string `json:"name"`
|
||
Kind string `json:"kind"`
|
||
Status string `json:"status"`
|
||
StartedAt string `json:"startedAt"`
|
||
EndedAt string `json:"endedAt,omitempty"`
|
||
DurationNs int64 `json:"durationNs"`
|
||
Props map[string]any `json:"props,omitempty"`
|
||
Events []trace.Event `json:"events,omitempty"`
|
||
}
|
||
|
||
// RingBuffer 是已完成的 trace span 的并发安全有界缓冲。缓冲
|
||
// 满时逐出最旧 span,因此管理面板总能看到
|
||
// 最近的工作而不会无界增长。
|
||
type RingBuffer struct {
|
||
mu sync.RWMutex
|
||
buf []trace.SpanRecord
|
||
next int
|
||
full bool
|
||
cap int
|
||
}
|
||
|
||
// newRingBuffer 构建至多容纳 cap 个 span 的环形缓冲(cap<=0 时用默认值)。
|
||
func newRingBuffer(cap int) *RingBuffer {
|
||
if cap <= 0 {
|
||
cap = defaultTraceBufCap
|
||
}
|
||
return &RingBuffer{buf: make([]trace.SpanRecord, cap), cap: cap}
|
||
}
|
||
|
||
// Append 存储 rec,缓冲满时逐出最旧的。
|
||
func (r *RingBuffer) Append(rec trace.SpanRecord) {
|
||
r.mu.Lock()
|
||
defer r.mu.Unlock()
|
||
r.buf[r.next] = rec
|
||
r.next = (r.next + 1) % r.cap
|
||
if r.next == 0 {
|
||
r.full = true
|
||
}
|
||
}
|
||
|
||
// Snapshot 返回至多 n 条最近 span,最新优先。非正的 n
|
||
// 选用 defaultObsLimit;n 被夹取到 maxObsLimit。
|
||
func (r *RingBuffer) Snapshot(n int) []trace.SpanRecord {
|
||
if n <= 0 {
|
||
n = defaultObsLimit
|
||
}
|
||
if n > maxObsLimit {
|
||
n = maxObsLimit
|
||
}
|
||
r.mu.RLock()
|
||
defer r.mu.RUnlock()
|
||
count := r.next
|
||
if r.full {
|
||
count = r.cap
|
||
}
|
||
if count > n {
|
||
count = n
|
||
}
|
||
out := make([]trace.SpanRecord, 0, count)
|
||
for i := 0; i < count; i++ {
|
||
idx := (r.next - 1 - i + r.cap*2) % r.cap
|
||
out = append(out, r.buf[idx])
|
||
}
|
||
return out
|
||
}
|
||
|
||
// traceSink 把 *RingBuffer 适配为 trace.Writer,使已完成的 span 被
|
||
// 追加进网关的 trace 缓冲。
|
||
type traceSink struct{ b *RingBuffer }
|
||
|
||
// WriteSpan 把 rec 追加进环形缓冲。
|
||
func (s traceSink) WriteSpan(rec trace.SpanRecord) error {
|
||
if s.b == nil {
|
||
return nil
|
||
}
|
||
s.b.Append(rec)
|
||
return nil
|
||
}
|
||
|
||
// MultiTraceWriter 把已完成的 span 扇出到多个 trace.Writer,使一个
|
||
// tracer 能一趟同时记录到网关的环形缓冲与一个 JSONL 文件。nil 的
|
||
// Writer 被跳过。它是主会话用来把 loop tracer 的输出引入
|
||
// 网关而不丢掉 stderr 的组合根辅助件。
|
||
type MultiTraceWriter struct {
|
||
// Writers 是 span 被写入的汇聚点。nil 的 Writer 被跳过。
|
||
Writers []trace.Writer
|
||
}
|
||
|
||
// WriteSpan 把 rec 写入每一个已配置的 Writer。
|
||
func (m MultiTraceWriter) WriteSpan(rec trace.SpanRecord) error {
|
||
for _, w := range m.Writers {
|
||
if w == nil {
|
||
continue
|
||
}
|
||
if err := w.WriteSpan(rec); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// adminSpanOf 把 trace.SpanRecord 映射为驼峰式管理线上结构。
|
||
func adminSpanOf(rec trace.SpanRecord) AdminTraceSpan {
|
||
sp := AdminTraceSpan{
|
||
ID: rec.ID,
|
||
ParentID: rec.ParentID,
|
||
Name: rec.Name,
|
||
Kind: string(rec.Kind),
|
||
Status: string(rec.Status),
|
||
StartedAt: rec.StartedAt.UTC().Format(time.RFC3339),
|
||
DurationNs: rec.Duration.Nanoseconds(),
|
||
Props: rec.Props,
|
||
Events: rec.Events,
|
||
}
|
||
if !rec.EndedAt.IsZero() {
|
||
sp.EndedAt = rec.EndedAt.UTC().Format(time.RFC3339)
|
||
}
|
||
return sp
|
||
}
|