131 lines
2.5 KiB
Go
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
|
|
}
|