104 lines
2.0 KiB
Go
104 lines
2.0 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// LogEntry 日志条目
|
|
type LogEntry struct {
|
|
Time time.Time `json:"time"`
|
|
Level string `json:"level"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
// LogBuffer 环形日志缓冲区
|
|
type LogBuffer struct {
|
|
mu sync.RWMutex
|
|
entries []LogEntry
|
|
maxSize int
|
|
writer io.Writer // 原始输出(控制台)
|
|
}
|
|
|
|
var LogBuf = NewLogBuffer(2000)
|
|
|
|
func NewLogBuffer(maxSize int) *LogBuffer {
|
|
return &LogBuffer{
|
|
entries: make([]LogEntry, 0, maxSize),
|
|
maxSize: maxSize,
|
|
writer: os.Stderr,
|
|
}
|
|
}
|
|
|
|
// Write 实现 io.Writer 接口, 用于 log.SetOutput
|
|
func (b *LogBuffer) Write(p []byte) (n int, err error) {
|
|
// 写入原始输出
|
|
b.writer.Write(p)
|
|
|
|
msg := string(p)
|
|
level := "INFO"
|
|
switch {
|
|
case contains(msg, "FAIL") || contains(msg, "Error") || contains(msg, "error"):
|
|
level = "ERROR"
|
|
case contains(msg, "WARN") || contains(msg, "warn"):
|
|
level = "WARN"
|
|
}
|
|
|
|
b.mu.Lock()
|
|
b.entries = append(b.entries, LogEntry{
|
|
Time: time.Now(),
|
|
Level: level,
|
|
Message: msg,
|
|
})
|
|
// 超过上限则截掉前半部分
|
|
if len(b.entries) > b.maxSize {
|
|
b.entries = b.entries[len(b.entries)-b.maxSize:]
|
|
}
|
|
b.mu.Unlock()
|
|
|
|
return len(p), nil
|
|
}
|
|
|
|
// Get 获取最近 n 条日志
|
|
func (b *LogBuffer) Get(n int) []LogEntry {
|
|
b.mu.RLock()
|
|
defer b.mu.RUnlock()
|
|
|
|
total := len(b.entries)
|
|
if n <= 0 || n > total {
|
|
n = total
|
|
}
|
|
result := make([]LogEntry, n)
|
|
copy(result, b.entries[total-n:])
|
|
return result
|
|
}
|
|
|
|
// Count 日志总数
|
|
func (b *LogBuffer) Count() int {
|
|
b.mu.RLock()
|
|
defer b.mu.RUnlock()
|
|
return len(b.entries)
|
|
}
|
|
|
|
func contains(s, sub string) bool {
|
|
return len(s) >= len(sub) && (s == sub || len(s) > 0 && findSubstring(s, sub))
|
|
}
|
|
|
|
func findSubstring(s, sub string) bool {
|
|
for i := 0; i <= len(s)-len(sub); i++ {
|
|
if s[i:i+len(sub)] == sub {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Logf 写入一条格式化日志到缓冲区
|
|
func Logf(format string, args ...interface{}) {
|
|
msg := fmt.Sprintf(format, args...)
|
|
LogBuf.Write([]byte(msg + "\n"))
|
|
}
|