199 lines
4.0 KiB
Go
199 lines
4.0 KiB
Go
package logger
|
||
|
||
import (
|
||
"fmt"
|
||
"strconv"
|
||
"strings"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
// LogEntry 日志条目
|
||
type LogEntry struct {
|
||
Timestamp time.Time `json:"timestamp"`
|
||
Level string `json:"level"`
|
||
Message string `json:"message"`
|
||
Email string `json:"email,omitempty"`
|
||
Module string `json:"module,omitempty"`
|
||
}
|
||
|
||
// 日志存储
|
||
var (
|
||
logs = make([]LogEntry, 0, 1000)
|
||
logsMu sync.RWMutex
|
||
listeners = make(map[string]chan LogEntry)
|
||
listMu sync.RWMutex
|
||
)
|
||
|
||
// AddListener 添加日志监听器
|
||
func AddListener(id string) chan LogEntry {
|
||
listMu.Lock()
|
||
defer listMu.Unlock()
|
||
ch := make(chan LogEntry, 100)
|
||
listeners[id] = ch
|
||
return ch
|
||
}
|
||
|
||
// RemoveListener 移除日志监听器
|
||
func RemoveListener(id string) {
|
||
listMu.Lock()
|
||
defer listMu.Unlock()
|
||
if ch, ok := listeners[id]; ok {
|
||
close(ch)
|
||
delete(listeners, id)
|
||
}
|
||
}
|
||
|
||
// broadcast 广播日志
|
||
func broadcast(entry LogEntry) {
|
||
listMu.RLock()
|
||
defer listMu.RUnlock()
|
||
for _, ch := range listeners {
|
||
select {
|
||
case ch <- entry:
|
||
default:
|
||
}
|
||
}
|
||
}
|
||
|
||
// log 记录日志
|
||
func log(level, message, email, module string) {
|
||
entry := LogEntry{
|
||
Timestamp: time.Now(),
|
||
Level: level,
|
||
Message: message,
|
||
Email: email,
|
||
Module: module,
|
||
}
|
||
|
||
logsMu.Lock()
|
||
if len(logs) >= 1000 {
|
||
logs = logs[100:]
|
||
}
|
||
logs = append(logs, entry)
|
||
logsMu.Unlock()
|
||
|
||
broadcast(entry)
|
||
|
||
// 打印到控制台 (带时间戳和颜色)
|
||
timestamp := entry.Timestamp.Format("15:04:05")
|
||
|
||
// ANSI 颜色代码
|
||
colorReset := "\033[0m"
|
||
colorGray := "\033[90m"
|
||
colorGreen := "\033[32m"
|
||
colorRed := "\033[31m"
|
||
colorYellow := "\033[33m"
|
||
colorCyan := "\033[36m"
|
||
|
||
// Team 颜色列表(用于区分不同 Team)
|
||
teamColors := []string{
|
||
"\033[38;5;39m", // 亮蓝
|
||
"\033[38;5;208m", // 橙色
|
||
"\033[38;5;141m", // 紫色
|
||
"\033[38;5;48m", // 青绿
|
||
"\033[38;5;197m", // 粉红
|
||
"\033[38;5;226m", // 亮黄
|
||
"\033[38;5;87m", // 青色
|
||
"\033[38;5;156m", // 浅绿
|
||
"\033[38;5;219m", // 浅粉
|
||
"\033[38;5;117m", // 天蓝
|
||
}
|
||
|
||
// 从消息中提取 Team 编号
|
||
teamColor := ""
|
||
if strings.Contains(message, "[Team ") {
|
||
start := strings.Index(message, "[Team ")
|
||
if start >= 0 {
|
||
end := strings.Index(message[start:], "]")
|
||
if end > 0 {
|
||
teamStr := message[start+6 : start+end]
|
||
if teamNum, err := strconv.Atoi(teamStr); err == nil && teamNum > 0 {
|
||
teamColor = teamColors[(teamNum-1)%len(teamColors)]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
prefix := ""
|
||
color := ""
|
||
switch level {
|
||
case "info":
|
||
prefix = "INFO"
|
||
color = colorCyan
|
||
case "success":
|
||
prefix = "SUCCESS"
|
||
color = colorGreen
|
||
case "error":
|
||
prefix = "ERROR"
|
||
color = colorRed
|
||
case "warning":
|
||
prefix = "WARN"
|
||
color = colorYellow
|
||
}
|
||
|
||
// 如果是 Team 相关日志,消息使用 Team 颜色
|
||
msgColor := colorReset
|
||
if teamColor != "" {
|
||
msgColor = teamColor
|
||
}
|
||
|
||
if email != "" {
|
||
fmt.Printf("%s%s%s %s[%s]%s [%s] %s - %s%s%s\n",
|
||
colorGray, timestamp, colorReset,
|
||
color, prefix, colorReset,
|
||
module, email, msgColor, message, colorReset)
|
||
} else {
|
||
fmt.Printf("%s%s%s %s[%s]%s [%s] %s%s%s\n",
|
||
colorGray, timestamp, colorReset,
|
||
color, prefix, colorReset,
|
||
module, msgColor, message, colorReset)
|
||
}
|
||
}
|
||
|
||
// Info 记录信息日志
|
||
func Info(message, email, module string) {
|
||
log("info", message, email, module)
|
||
}
|
||
|
||
// Success 记录成功日志
|
||
func Success(message, email, module string) {
|
||
log("success", message, email, module)
|
||
}
|
||
|
||
// Error 记录错误日志
|
||
func Error(message, email, module string) {
|
||
log("error", message, email, module)
|
||
}
|
||
|
||
// Warning 记录警告日志
|
||
func Warning(message, email, module string) {
|
||
log("warning", message, email, module)
|
||
}
|
||
|
||
// GetLogs 获取日志
|
||
func GetLogs(limit int) []LogEntry {
|
||
logsMu.RLock()
|
||
defer logsMu.RUnlock()
|
||
|
||
if limit <= 0 || limit > len(logs) {
|
||
limit = len(logs)
|
||
}
|
||
|
||
start := len(logs) - limit
|
||
if start < 0 {
|
||
start = 0
|
||
}
|
||
|
||
result := make([]LogEntry, limit)
|
||
copy(result, logs[start:])
|
||
return result
|
||
}
|
||
|
||
// ClearLogs 清空日志
|
||
func ClearLogs() {
|
||
logsMu.Lock()
|
||
defer logsMu.Unlock()
|
||
logs = make([]LogEntry, 0, 1000)
|
||
}
|