167 lines
3.3 KiB
Go
167 lines
3.3 KiB
Go
package logger
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"sync"
|
|
)
|
|
|
|
// FileHook 文件钩子 - 将日志写入文件
|
|
type FileHook struct {
|
|
mu sync.Mutex
|
|
file *os.File
|
|
output io.Writer
|
|
levels []Level
|
|
formatter func(*Entry) string
|
|
}
|
|
|
|
// NewFileHook 创建文件钩子
|
|
func NewFileHook(filename string, levels []Level) (*FileHook, error) {
|
|
file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &FileHook{
|
|
file: file,
|
|
output: file,
|
|
levels: levels,
|
|
formatter: func(e *Entry) string {
|
|
return e.format()
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// Fire 触发钩子
|
|
func (h *FileHook) Fire(entry *Entry) error {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
|
|
_, err := h.output.Write([]byte(h.formatter(entry)))
|
|
return err
|
|
}
|
|
|
|
// Levels 返回支持的日志级别
|
|
func (h *FileHook) Levels() []Level {
|
|
return h.levels
|
|
}
|
|
|
|
// Close 关闭文件钩子
|
|
func (h *FileHook) Close() error {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
return h.file.Close()
|
|
}
|
|
|
|
// ErrorHook 错误钩子 - 专门记录错误日志
|
|
type ErrorHook struct {
|
|
mu sync.Mutex
|
|
output io.Writer
|
|
errors []string
|
|
maxSize int
|
|
}
|
|
|
|
// NewErrorHook 创建错误钩子
|
|
func NewErrorHook(output io.Writer, maxSize int) *ErrorHook {
|
|
return &ErrorHook{
|
|
output: output,
|
|
errors: make([]string, 0, maxSize),
|
|
maxSize: maxSize,
|
|
}
|
|
}
|
|
|
|
// Fire 触发钩子
|
|
func (h *ErrorHook) Fire(entry *Entry) error {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
|
|
msg := fmt.Sprintf("[%s] %s", entry.Time.Format("2006-01-02 15:04:05"), entry.Message)
|
|
|
|
// 添加到缓冲区
|
|
if len(h.errors) >= h.maxSize {
|
|
h.errors = h.errors[1:]
|
|
}
|
|
h.errors = append(h.errors, msg)
|
|
|
|
// 写入输出
|
|
_, err := h.output.Write([]byte(msg + "\n"))
|
|
return err
|
|
}
|
|
|
|
// Levels 返回支持的日志级别
|
|
func (h *ErrorHook) Levels() []Level {
|
|
return []Level{ERROR, FATAL}
|
|
}
|
|
|
|
// GetErrors 获取最近的错误
|
|
func (h *ErrorHook) GetErrors() []string {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
return h.errors
|
|
}
|
|
|
|
// PerformanceHook 性能钩子 - 记录慢操作
|
|
type PerformanceHook struct {
|
|
mu sync.Mutex
|
|
slowOps []map[string]interface{}
|
|
thresholdMs float64
|
|
}
|
|
|
|
// NewPerformanceHook 创建性能钩子
|
|
func NewPerformanceHook(thresholdMs float64) *PerformanceHook {
|
|
return &PerformanceHook{
|
|
slowOps: make([]map[string]interface{}, 0, 100),
|
|
thresholdMs: thresholdMs,
|
|
}
|
|
}
|
|
|
|
// Fire 触发钩子
|
|
func (h *PerformanceHook) Fire(entry *Entry) error {
|
|
// 只记录包含 duration 字段的日志
|
|
if duration, ok := entry.Fields["duration_ms"]; ok {
|
|
var d float64
|
|
switch v := duration.(type) {
|
|
case float64:
|
|
d = v
|
|
case int:
|
|
d = float64(v)
|
|
case int64:
|
|
d = float64(v)
|
|
default:
|
|
return nil
|
|
}
|
|
|
|
if d > h.thresholdMs {
|
|
h.mu.Lock()
|
|
|
|
slowOp := map[string]interface{}{
|
|
"time": entry.Time,
|
|
"operation": entry.Fields["operation"],
|
|
"duration": duration,
|
|
"message": entry.Message,
|
|
}
|
|
|
|
if len(h.slowOps) >= 100 {
|
|
h.slowOps = h.slowOps[1:]
|
|
}
|
|
h.slowOps = append(h.slowOps, slowOp)
|
|
|
|
h.mu.Unlock()
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Levels 返回支持的日志级别
|
|
func (h *PerformanceHook) Levels() []Level {
|
|
return []Level{INFO, WARN, ERROR}
|
|
}
|
|
|
|
// GetSlowOps 获取慢操作列表
|
|
func (h *PerformanceHook) GetSlowOps() []map[string]interface{} {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
return h.slowOps
|
|
}
|