File size: 2,765 Bytes
9aab84d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package internal

import (
	"context"
	"fmt"
	"io"
	"log/slog"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"
)

var (
	logger   *slog.Logger
	logLevel = new(slog.LevelVar)
	logOnce  sync.Once
)

type colorHandler struct {
	writer io.Writer
	level  *slog.LevelVar
}

var levelColorMap = map[slog.Level]string{
	slog.LevelDebug: "\033[36m", // 青色
	slog.LevelInfo:  "\033[32m", // 绿色
	slog.LevelWarn:  "\033[33m", // 黄色
	slog.LevelError: "\033[31m", // 红色
}

var levelNameMap = map[slog.Level]string{
	slog.LevelDebug: "DEBUG",
	slog.LevelInfo:  "INFO",
	slog.LevelWarn:  "WARN",
	slog.LevelError: "ERROR",
}

const resetColor = "\033[0m"

func (h *colorHandler) Enabled(_ context.Context, level slog.Level) bool {
	return level >= h.level.Level()
}

func (h *colorHandler) Handle(_ context.Context, r slog.Record) error {
	timestamp := r.Time.Format("2006/01/02 15:04:05")
	caller := "unknown.go"
	if r.PC != 0 {
		frames := runtime.CallersFrames([]uintptr{r.PC})
		f, _ := frames.Next()
		if f.File != "" {
			caller = filepath.Base(f.File)
		}
	}
	color := levelColorMap[r.Level]
	name := levelNameMap[r.Level]
	if name == "" {
		name = r.Level.String()
	}
	fmt.Fprintf(h.writer, "%s [%s] %s[%s]%s %s\n", timestamp, caller, color, name, resetColor, r.Message)
	return nil
}

func (h *colorHandler) WithAttrs(_ []slog.Attr) slog.Handler { return h }
func (h *colorHandler) WithGroup(_ string) slog.Handler      { return h }

func InitLogger() {
	logOnce.Do(func() {
		logLevel.Set(slog.LevelInfo)
	})

	if Cfg != nil && Cfg.DebugLogging {
		logLevel.Set(slog.LevelDebug)
	}

	if Cfg != nil && Cfg.LogLevel != "" {
		switch strings.ToLower(Cfg.LogLevel) {
		case "debug":
			logLevel.Set(slog.LevelDebug)
		case "warn":
			logLevel.Set(slog.LevelWarn)
		case "error":
			logLevel.Set(slog.LevelError)
		default:
			logLevel.Set(slog.LevelInfo)
		}
	}

	logger = slog.New(&colorHandler{writer: os.Stdout, level: logLevel})
	slog.SetDefault(logger)
}

func logMsg(level slog.Level, format string, v ...interface{}) {
	if !logger.Enabled(context.Background(), level) {
		return
	}
	var pcs [1]uintptr
	runtime.Callers(3, pcs[:])
	r := slog.NewRecord(time.Now(), level, fmt.Sprintf(format, v...), pcs[0])
	_ = logger.Handler().Handle(context.Background(), r)
}

func LogDebug(format string, v ...interface{}) {
	logMsg(slog.LevelDebug, format, v...)
}

func LogInfo(format string, v ...interface{}) {
	logMsg(slog.LevelInfo, format, v...)
}

func LogWarn(format string, v ...interface{}) {
	logMsg(slog.LevelWarn, format, v...)
}

func LogError(format string, v ...interface{}) {
	logMsg(slog.LevelError, format, v...)
}