202 lines
5.1 KiB
Go
202 lines
5.1 KiB
Go
package utils
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"io"
|
||
"log/slog"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"sync"
|
||
)
|
||
|
||
var logLevelMap = map[string]slog.Level{
|
||
"debug": slog.LevelDebug,
|
||
"info": slog.LevelInfo,
|
||
"warn": slog.LevelWarn,
|
||
"error": slog.LevelError,
|
||
}
|
||
|
||
// 自定义格式处理器,以 [时间] [级别] [消息] 格式输出日志
|
||
type CustomFormatHandler struct {
|
||
mu sync.Mutex
|
||
w io.Writer
|
||
level slog.Level
|
||
attrs []slog.Attr
|
||
groups []string
|
||
}
|
||
|
||
// NewCustomFormatHandler 创建一个新的自定义格式处理器
|
||
func NewCustomFormatHandler(w io.Writer, opts *slog.HandlerOptions) *CustomFormatHandler {
|
||
if opts == nil {
|
||
opts = &slog.HandlerOptions{}
|
||
}
|
||
|
||
// 获取日志级别,如果opts.Level是nil则默认为Info
|
||
var level slog.Level
|
||
if opts.Level != nil {
|
||
level = opts.Level.Level()
|
||
} else {
|
||
level = slog.LevelInfo
|
||
}
|
||
|
||
return &CustomFormatHandler{
|
||
w: w,
|
||
level: level,
|
||
}
|
||
}
|
||
|
||
// Enabled 实现 slog.Handler 接口
|
||
func (h *CustomFormatHandler) Enabled(ctx context.Context, level slog.Level) bool {
|
||
return level >= h.level
|
||
}
|
||
|
||
// Handle 实现 slog.Handler 接口,以自定义格式输出日志
|
||
func (h *CustomFormatHandler) Handle(ctx context.Context, record slog.Record) error {
|
||
h.mu.Lock()
|
||
defer h.mu.Unlock()
|
||
|
||
// 时间格式
|
||
timeStr := record.Time.Format("2006-01-02 15:04:05.000")
|
||
|
||
// 日志级别
|
||
var levelStr string
|
||
switch {
|
||
case record.Level >= slog.LevelError:
|
||
levelStr = "ERROR"
|
||
case record.Level >= slog.LevelWarn:
|
||
levelStr = "WARN "
|
||
case record.Level >= slog.LevelInfo:
|
||
levelStr = "INFO "
|
||
default:
|
||
levelStr = "DEBUG"
|
||
}
|
||
|
||
// 构建日志行
|
||
logLine := fmt.Sprintf("[%s] [%s] %s", timeStr, levelStr, record.Message)
|
||
|
||
// 处理其他属性
|
||
var attrs []string
|
||
record.Attrs(func(attr slog.Attr) bool {
|
||
attrs = append(attrs, fmt.Sprintf("%s=%v", attr.Key, attr.Value))
|
||
return true
|
||
})
|
||
|
||
if len(attrs) > 0 {
|
||
logLine += " " + strings.Join(attrs, " ")
|
||
}
|
||
|
||
// 写入日志
|
||
_, err := fmt.Fprintln(h.w, logLine)
|
||
return err
|
||
}
|
||
|
||
// WithAttrs 实现 slog.Handler 接口
|
||
func (h *CustomFormatHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||
h2 := *h
|
||
h2.attrs = append(h.attrs[:], attrs...)
|
||
return &h2
|
||
}
|
||
|
||
// WithGroup 实现 slog.Handler 接口
|
||
func (h *CustomFormatHandler) WithGroup(name string) slog.Handler {
|
||
h2 := *h
|
||
h2.groups = append(h.groups[:], name)
|
||
return &h2
|
||
}
|
||
|
||
// MultiHandler 实现了 slog.Handler 接口,将日志同时发送到多个处理器
|
||
type MultiHandler struct {
|
||
handlers []slog.Handler
|
||
}
|
||
|
||
// Enabled 实现 slog.Handler 接口
|
||
func (h *MultiHandler) Enabled(ctx context.Context, level slog.Level) bool {
|
||
// 如果任何一个处理器启用了该级别,则返回 true
|
||
for _, handler := range h.handlers {
|
||
if handler.Enabled(ctx, level) {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// Handle 实现 slog.Handler 接口
|
||
func (h *MultiHandler) Handle(ctx context.Context, record slog.Record) error {
|
||
// 将记录发送到所有处理器
|
||
for _, handler := range h.handlers {
|
||
if handler.Enabled(ctx, record.Level) {
|
||
if err := handler.Handle(ctx, record); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// WithAttrs 实现 slog.Handler 接口
|
||
func (h *MultiHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||
newHandlers := make([]slog.Handler, len(h.handlers))
|
||
for i, handler := range h.handlers {
|
||
newHandlers[i] = handler.WithAttrs(attrs)
|
||
}
|
||
return &MultiHandler{handlers: newHandlers}
|
||
}
|
||
|
||
// WithGroup 实现 slog.Handler 接口
|
||
func (h *MultiHandler) WithGroup(name string) slog.Handler {
|
||
newHandlers := make([]slog.Handler, len(h.handlers))
|
||
for i, handler := range h.handlers {
|
||
newHandlers[i] = handler.WithGroup(name)
|
||
}
|
||
return &MultiHandler{handlers: newHandlers}
|
||
}
|
||
|
||
// SetupLogger 设置日志输出
|
||
func SetupLogger(logLevel string, logFile string) error {
|
||
// 创建标准错误输出的处理器,使用自定义格式
|
||
stdHandler := NewCustomFormatHandler(os.Stderr, &slog.HandlerOptions{
|
||
Level: logLevelMap[logLevel],
|
||
})
|
||
|
||
// 如果没有指定日志文件,则仅使用标准错误处理器
|
||
if logFile == "" {
|
||
slog.SetDefault(slog.New(stdHandler))
|
||
return nil
|
||
}
|
||
|
||
// 确保日志文件所在目录存在
|
||
logDir := filepath.Dir(logFile)
|
||
if err := os.MkdirAll(logDir, 0755); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 打开日志文件,如果不存在则创建,追加写入模式
|
||
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 创建文件输出的处理器,使用自定义格式
|
||
fileHandler := NewCustomFormatHandler(file, &slog.HandlerOptions{
|
||
Level: logLevelMap[logLevel],
|
||
})
|
||
|
||
// 创建多输出处理器
|
||
multiHandler := &MultiHandler{
|
||
handlers: []slog.Handler{stdHandler, fileHandler},
|
||
}
|
||
|
||
// 设置全局日志处理器
|
||
slog.SetDefault(slog.New(multiHandler))
|
||
return nil
|
||
}
|
||
|
||
// InitDefaultLogger 初始化默认日志处理器
|
||
func InitDefaultLogger(level slog.Level) {
|
||
slog.SetDefault(slog.New(NewCustomFormatHandler(os.Stderr, &slog.HandlerOptions{
|
||
Level: level,
|
||
})))
|
||
}
|