Files
2026-04-09 00:14:57 +08:00

131 lines
2.5 KiB
Go

package monitor
import (
"fmt"
"log"
"strings"
"sync"
"time"
)
type LogEntry struct {
Time string `json:"time"`
Level string `json:"level"`
Message string `json:"message"`
}
type logHub struct {
mutex sync.RWMutex
entries []LogEntry
maxEntries int
subscribers map[chan LogEntry]struct{}
}
var hub = &logHub{
maxEntries: 1000,
subscribers: make(map[chan LogEntry]struct{}),
}
func Init(maxEntries int) {
if maxEntries > 0 {
hub.maxEntries = maxEntries
}
}
func Infof(format string, args ...interface{}) {
appendEntry("info", fmt.Sprintf(format, args...))
}
func Warnf(format string, args ...interface{}) {
appendEntry("warn", fmt.Sprintf(format, args...))
}
func Errorf(format string, args ...interface{}) {
appendEntry("error", fmt.Sprintf(format, args...))
}
func Auditf(format string, args ...interface{}) {
appendEntry("audit", fmt.Sprintf(format, args...))
}
func appendEntry(level, message string) {
entry := LogEntry{
Time: time.Now().Format(time.RFC3339),
Level: strings.ToLower(level),
Message: message,
}
log.Printf("[%s] %s", strings.ToUpper(entry.Level), entry.Message)
hub.mutex.Lock()
hub.entries = append(hub.entries, entry)
if len(hub.entries) > hub.maxEntries {
hub.entries = hub.entries[len(hub.entries)-hub.maxEntries:]
}
for ch := range hub.subscribers {
select {
case ch <- entry:
default:
}
}
hub.mutex.Unlock()
}
func Subscribe() chan LogEntry {
ch := make(chan LogEntry, 100)
hub.mutex.Lock()
hub.subscribers[ch] = struct{}{}
hub.mutex.Unlock()
return ch
}
func Unsubscribe(ch chan LogEntry) {
hub.mutex.Lock()
if _, ok := hub.subscribers[ch]; ok {
delete(hub.subscribers, ch)
close(ch)
}
hub.mutex.Unlock()
}
func Query(level, keyword string, page, pageSize int) ([]LogEntry, int) {
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 20
}
if pageSize > 200 {
pageSize = 200
}
level = strings.TrimSpace(strings.ToLower(level))
keyword = strings.TrimSpace(strings.ToLower(keyword))
hub.mutex.RLock()
defer hub.mutex.RUnlock()
filtered := make([]LogEntry, 0, len(hub.entries))
for _, e := range hub.entries {
if level != "" && e.Level != level {
continue
}
if keyword != "" && !strings.Contains(strings.ToLower(e.Message), keyword) {
continue
}
filtered = append(filtered, e)
}
total := len(filtered)
start := (page - 1) * pageSize
if start >= total {
return []LogEntry{}, total
}
end := start + pageSize
if end > total {
end = total
}
return filtered[start:end], total
}