监控网页实现
This commit is contained in:
130
backend/internal/monitor/logs.go
Normal file
130
backend/internal/monitor/logs.go
Normal file
@@ -0,0 +1,130 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user