Download internal/panel/ring.go from a3216/gcli2api: direct link, hf CLI and curl.
- Browser
- Download file 2.85 kB
-
https://huggingface.co/spaces/a3216/gcli2api/resolve/main/internal/panel/ring.go
- Command line
-
hf download hf://spaces/a3216/gcli2api/internal/panel/ring.go
-
curl -L -o ring.go https://huggingface.co/spaces/a3216/gcli2api/resolve/main/internal/panel/ring.go
2.85 kB
| // ring.go 固定容量的结构化日志环形缓冲(并发安全,实现 io.Writer)。 | |
| // main 把 log 包输出与 chat 表格日志经 MultiWriter 镜像进来,面板 | |
| // /panel/api/logs 读取快照;超出容量的旧行按 FIFO 淘汰。 | |
| // | |
| // 每行入环时按前缀规则归类频道(chat=对话请求表格行 / task=任务动作 / | |
| // sys=系统与其它),面板日志视图按频道筛选——对话流量大时任务结果不被冲掉。 | |
| package panel | |
| import ( | |
| "regexp" | |
| "strings" | |
| "sync" | |
| "time" | |
| ) | |
| // 日志频道。 | |
| const ( | |
| ChChat = "chat" | |
| ChTask = "task" | |
| ChSys = "sys" | |
| ) | |
| // LogEntry 单条日志(时间戳取写入时刻;log 包行的行首日期时间已被剥离)。 | |
| type LogEntry struct { | |
| TS time.Time `json:"ts"` | |
| Ch string `json:"ch"` | |
| Text string `json:"text"` | |
| } | |
| // taskPrefixes 任务动作日志的行首标识(scheduler 与 panel 的既有口径)。 | |
| var taskPrefixes = []string{ | |
| "school ", "streak-bonus ", "travel ", "blackcat ", "lottery ", | |
| "checkin ", "activity ", "keepalive ", "balance ", "user-resource ", | |
| "panel: 任务", "panel: 一键", "panel: checkin", "panel: 手动", | |
| "panel: 队列", "panel: 券码", | |
| } | |
| // tsPrefixRe log 包默认 flags(日期 时间)产生的行首时间戳。 | |
| var tsPrefixRe = regexp.MustCompile(`^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} `) | |
| // classifyLine 按行首特征归类频道。 | |
| func classifyLine(line string) string { | |
| if strings.HasPrefix(line, "| #") { // chat 表格日志(server/logging.go logChatRow) | |
| return ChChat | |
| } | |
| for _, p := range taskPrefixes { | |
| if strings.HasPrefix(line, p) { | |
| return ChTask | |
| } | |
| } | |
| return ChSys | |
| } | |
| // Ring 日志环形缓冲。 | |
| type Ring struct { | |
| mu sync.Mutex | |
| entries []LogEntry | |
| cap int | |
| } | |
| // NewRing 构建容量为 capacity 的日志环(非正值回退 500)。 | |
| func NewRing(capacity int) *Ring { | |
| if capacity <= 0 { | |
| capacity = 500 | |
| } | |
| return &Ring{cap: capacity} | |
| } | |
| // Write 按 \n 切分入环(实现 io.Writer)。空行丢弃;超容量淘汰最旧行。 | |
| func (r *Ring) Write(p []byte) (int, error) { | |
| now := time.Now() | |
| r.mu.Lock() | |
| defer r.mu.Unlock() | |
| for _, line := range strings.Split(strings.TrimRight(string(p), "\r\n"), "\n") { | |
| if line == "" { | |
| continue | |
| } | |
| text := tsPrefixRe.ReplaceAllString(line, "") | |
| r.entries = append(r.entries, LogEntry{TS: now, Ch: classifyLine(text), Text: text}) | |
| if overflow := len(r.entries) - r.cap; overflow > 0 { | |
| r.entries = r.entries[overflow:] | |
| } | |
| } | |
| return len(p), nil | |
| } | |
| // Snapshot 按写入顺序返回缓冲内全部条目(拷贝,调用方可安全持有)。 | |
| func (r *Ring) Snapshot() []LogEntry { | |
| r.mu.Lock() | |
| defer r.mu.Unlock() | |
| out := make([]LogEntry, len(r.entries)) | |
| copy(out, r.entries) | |
| return out | |
| } | |