|
2 | 2 | package logger
|
3 | 3 |
|
4 | 4 | import (
|
5 |
| - "context" |
6 |
| - "fmt" |
7 |
| - "log/slog" |
8 | 5 | "os"
|
9 |
| - "runtime" |
10 | 6 | "strconv"
|
11 | 7 | "time"
|
12 | 8 |
|
13 |
| - "github.com/lmittmann/tint" |
| 9 | + "github.com/go-logr/logr" |
| 10 | + "github.com/go-logr/zapr" |
14 | 11 | "github.com/spf13/viper"
|
| 12 | + "go.uber.org/zap" |
| 13 | + "go.uber.org/zap/zapcore" |
15 | 14 | )
|
16 | 15 |
|
17 |
| -// Log is a global logger instance |
18 |
| -var log Logger |
19 |
| - |
20 | 16 | // Debug logs a message at debug level using the singleton logger.
|
21 |
| -func Debug(msg string, args ...any) { |
22 |
| - log.Debug(msg, args...) |
| 17 | +func Debug(msg string) { |
| 18 | + zap.S().Debug(msg) |
23 | 19 | }
|
24 | 20 |
|
25 | 21 | // Debugf logs a message at debug level using the singleton logger.
|
26 | 22 | func Debugf(msg string, args ...any) {
|
27 |
| - log.Debugf(msg, args...) |
| 23 | + zap.S().Debugf(msg, args...) |
| 24 | +} |
| 25 | + |
| 26 | +// Debugw logs a message at debug level using the singleton logger with additional key-value pairs. |
| 27 | +func Debugw(msg string, keysAndValues ...any) { |
| 28 | + zap.S().Debugw(msg, keysAndValues...) |
28 | 29 | }
|
29 | 30 |
|
30 | 31 | // Info logs a message at info level using the singleton logger.
|
31 |
| -func Info(msg string, args ...any) { |
32 |
| - log.Info(msg, args...) |
| 32 | +func Info(msg string) { |
| 33 | + zap.S().Info(msg) |
33 | 34 | }
|
34 | 35 |
|
35 | 36 | // Infof logs a message at info level using the singleton logger.
|
36 | 37 | func Infof(msg string, args ...any) {
|
37 |
| - log.Infof(msg, args...) |
| 38 | + zap.S().Infof(msg, args...) |
| 39 | +} |
| 40 | + |
| 41 | +// Infow logs a message at info level using the singleton logger with additional key-value pairs. |
| 42 | +func Infow(msg string, keysAndValues ...any) { |
| 43 | + zap.S().Infow(msg, keysAndValues...) |
38 | 44 | }
|
39 | 45 |
|
40 | 46 | // Warn logs a message at warning level using the singleton logger.
|
41 |
| -func Warn(msg string, args ...any) { |
42 |
| - log.Warn(msg, args...) |
| 47 | +func Warn(msg string) { |
| 48 | + zap.S().Warn(msg) |
43 | 49 | }
|
44 | 50 |
|
45 | 51 | // Warnf logs a message at warning level using the singleton logger.
|
46 | 52 | func Warnf(msg string, args ...any) {
|
47 |
| - log.Warnf(msg, args...) |
| 53 | + zap.S().Warnf(msg, args...) |
| 54 | +} |
| 55 | + |
| 56 | +// Warnw logs a message at warning level using the singleton logger with additional key-value pairs. |
| 57 | +func Warnw(msg string, keysAndValues ...any) { |
| 58 | + zap.S().Warnw(msg, keysAndValues...) |
48 | 59 | }
|
49 | 60 |
|
50 | 61 | // Error logs a message at error level using the singleton logger.
|
51 |
| -func Error(msg string, args ...any) { |
52 |
| - log.Error(msg, args...) |
| 62 | +func Error(msg string) { |
| 63 | + zap.S().Error(msg) |
53 | 64 | }
|
54 | 65 |
|
55 | 66 | // Errorf logs a message at error level using the singleton logger.
|
56 | 67 | func Errorf(msg string, args ...any) {
|
57 |
| - log.Errorf(msg, args...) |
| 68 | + zap.S().Errorf(msg, args...) |
| 69 | +} |
| 70 | + |
| 71 | +// Errorw logs a message at error level using the singleton logger with additional key-value pairs. |
| 72 | +func Errorw(msg string, keysAndValues ...any) { |
| 73 | + zap.S().Errorw(msg, keysAndValues...) |
58 | 74 | }
|
59 | 75 |
|
60 | 76 | // Panic logs a message at error level using the singleton logger and panics the program.
|
61 | 77 | func Panic(msg string) {
|
62 |
| - log.Panic(msg) |
| 78 | + zap.S().Panic(msg) |
63 | 79 | }
|
64 | 80 |
|
65 | 81 | // Panicf logs a message at error level using the singleton logger and panics the program.
|
66 | 82 | func Panicf(msg string, args ...any) {
|
67 |
| - log.Panicf(msg, args...) |
| 83 | + zap.S().Panicf(msg, args...) |
68 | 84 | }
|
69 | 85 |
|
70 |
| -// Logger provides a unified interface for logging |
71 |
| -type Logger interface { |
72 |
| - Debug(msg string, args ...any) |
73 |
| - Debugf(msg string, args ...any) |
74 |
| - Info(msg string, args ...any) |
75 |
| - Infof(msg string, args ...any) |
76 |
| - Warn(msg string, args ...any) |
77 |
| - Warnf(msg string, args ...any) |
78 |
| - Error(msg string, args ...any) |
79 |
| - Errorf(msg string, args ...any) |
80 |
| - Panic(msg string) |
81 |
| - Panicf(msg string, args ...any) |
| 86 | +// Panicw logs a message at error level using the singleton logger with additional key-value pairs and panics the program. |
| 87 | +func Panicw(msg string, keysAndValues ...any) { |
| 88 | + zap.S().Panicw(msg, keysAndValues...) |
82 | 89 | }
|
83 | 90 |
|
84 |
| -// Implementation using slog |
85 |
| -type slogLogger struct { |
86 |
| - logger *slog.Logger |
| 91 | +// DPanic logs a message at error level using the singleton logger and panics the program. |
| 92 | +func DPanic(msg string) { |
| 93 | + zap.S().DPanic(msg) |
87 | 94 | }
|
88 | 95 |
|
89 |
| -func (l *slogLogger) Debugf(msg string, args ...any) { |
90 |
| - l.logger.Debug(fmt.Sprintf(msg, args...)) |
| 96 | +// DPanicf logs a message at error level using the singleton logger and panics the program. |
| 97 | +func DPanicf(msg string, args ...any) { |
| 98 | + zap.S().DPanicf(msg, args...) |
91 | 99 | }
|
92 | 100 |
|
93 |
| -func (l *slogLogger) Infof(msg string, args ...any) { |
94 |
| - l.logger.Info(fmt.Sprintf(msg, args...)) |
| 101 | +// DPanicw logs a message at error level using the singleton logger with additional key-value pairs and panics the program. |
| 102 | +func DPanicw(msg string, keysAndValues ...any) { |
| 103 | + zap.S().DPanicw(msg, keysAndValues...) |
95 | 104 | }
|
96 | 105 |
|
97 |
| -func (l *slogLogger) Warnf(msg string, args ...any) { |
98 |
| - l.logger.Warn(fmt.Sprintf(msg, args...)) |
| 106 | +// Fatal logs a message at error level using the singleton logger and exits the program. |
| 107 | +func Fatal(msg string) { |
| 108 | + zap.S().Fatal(msg) |
99 | 109 | }
|
100 | 110 |
|
101 |
| -func (l *slogLogger) Errorf(msg string, args ...any) { |
102 |
| - l.logger.Error(fmt.Sprintf(msg, args...)) |
| 111 | +// Fatalf logs a message at error level using the singleton logger and exits the program. |
| 112 | +func Fatalf(msg string, args ...any) { |
| 113 | + zap.S().Fatalf(msg, args...) |
103 | 114 | }
|
104 | 115 |
|
105 |
| -func (l *slogLogger) Panicf(msg string, args ...any) { |
106 |
| - l.Panic(fmt.Sprintf(msg, args...)) |
| 116 | +// Fatalw logs a message at error level using the singleton logger with additional key-value pairs and exits the program. |
| 117 | +func Fatalw(msg string, keysAndValues ...any) { |
| 118 | + zap.S().Fatalw(msg, keysAndValues...) |
107 | 119 | }
|
108 | 120 |
|
109 |
| -func (l *slogLogger) Debug(msg string, args ...any) { |
110 |
| - l.logger.Debug(msg, args...) |
111 |
| -} |
112 |
| - |
113 |
| -func (l *slogLogger) Info(msg string, args ...any) { |
114 |
| - l.logger.Info(msg, args...) |
115 |
| -} |
116 |
| - |
117 |
| -func (l *slogLogger) Warn(msg string, args ...any) { |
118 |
| - l.logger.Warn(msg, args...) |
119 |
| -} |
120 |
| - |
121 |
| -func (l *slogLogger) Error(msg string, args ...any) { |
122 |
| - l.logger.Error(msg, args...) |
123 |
| -} |
124 |
| - |
125 |
| -func (l *slogLogger) Panic(msg string) { |
126 |
| - var pcs [1]uintptr |
127 |
| - runtime.Callers(2, pcs[:]) // skip [Callers, Panic] |
128 |
| - record := slog.NewRecord(time.Now(), slog.LevelError, msg, pcs[0]) |
129 |
| - _ = l.logger.Handler().Handle(context.Background(), record) |
130 |
| - panic(msg) |
131 |
| -} |
132 |
| - |
133 |
| -func unstructuredLogs() bool { |
134 |
| - unstructuredLogs, err := strconv.ParseBool(os.Getenv("UNSTRUCTURED_LOGS")) |
135 |
| - if err != nil { |
136 |
| - // at this point if the error is not nil, the env var wasn't set, or is "" |
137 |
| - // which means we just default to outputting unstructured logs. |
138 |
| - return true |
139 |
| - } |
140 |
| - return unstructuredLogs |
| 121 | +// NewLogr returns a logr.Logger which uses zap logger |
| 122 | +func NewLogr() logr.Logger { |
| 123 | + return zapr.NewLogger(zap.L()) |
141 | 124 | }
|
142 | 125 |
|
143 | 126 | // Initialize creates and configures the appropriate logger.
|
144 | 127 | // If the UNSTRUCTURED_LOGS is set to true, it will output plain log message
|
145 | 128 | // with only time and LogLevelType (INFO, DEBUG, ERROR, WARN)).
|
146 | 129 | // Otherwise it will create a standard structured slog logger
|
147 | 130 | func Initialize() {
|
| 131 | + var config zap.Config |
148 | 132 | if unstructuredLogs() {
|
149 |
| - w := os.Stderr |
150 |
| - |
151 |
| - handler := tint.NewHandler(w, &tint.Options{ |
152 |
| - Level: getLogLevel(), |
153 |
| - TimeFormat: time.Kitchen, |
154 |
| - }) |
155 |
| - |
156 |
| - slogger := slog.New(handler) |
157 |
| - |
158 |
| - slog.SetDefault(slogger) |
159 |
| - log = &slogLogger{logger: slogger} |
| 133 | + config = zap.NewDevelopmentConfig() |
| 134 | + config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder |
| 135 | + config.EncoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout(time.Kitchen) |
| 136 | + config.OutputPaths = []string{"stderr"} |
160 | 137 | } else {
|
161 |
| - w := os.Stdout |
162 |
| - |
163 |
| - handler := slog.NewJSONHandler(w, &slog.HandlerOptions{ |
164 |
| - Level: getLogLevel(), |
165 |
| - }) |
166 |
| - |
167 |
| - slogger := slog.New(handler) |
168 |
| - |
169 |
| - slog.SetDefault(slogger) |
170 |
| - log = &slogLogger{logger: slogger} |
| 138 | + config = zap.NewProductionConfig() |
| 139 | + config.OutputPaths = []string{"stdout"} |
171 | 140 | }
|
172 |
| -} |
173 | 141 |
|
174 |
| -// GetLogger returns a context-specific logger |
175 |
| -func GetLogger(component string) Logger { |
176 |
| - if slogger, ok := log.(*slogLogger); ok { |
177 |
| - return &slogLogger{ |
178 |
| - logger: slogger.logger.With("component", component), |
179 |
| - } |
| 142 | + // Set log level based on current debug flag |
| 143 | + if viper.GetBool("debug") { |
| 144 | + config.Level = zap.NewAtomicLevelAt(zap.DebugLevel) |
| 145 | + } else { |
| 146 | + config.Level = zap.NewAtomicLevelAt(zap.InfoLevel) |
180 | 147 | }
|
181 | 148 |
|
182 |
| - return log |
| 149 | + zap.ReplaceGlobals(zap.Must(config.Build())) |
183 | 150 | }
|
184 | 151 |
|
185 |
| -// getLogLevel returns the appropriate slog.Level based on the debug flag |
186 |
| -func getLogLevel() slog.Level { |
187 |
| - var level slog.Level |
188 |
| - if viper.GetBool("debug") { |
189 |
| - level = slog.LevelDebug |
190 |
| - } else { |
191 |
| - level = slog.LevelInfo |
| 152 | +func unstructuredLogs() bool { |
| 153 | + unstructuredLogs, err := strconv.ParseBool(os.Getenv("UNSTRUCTURED_LOGS")) |
| 154 | + if err != nil { |
| 155 | + // at this point if the error is not nil, the env var wasn't set, or is "" |
| 156 | + // which means we just default to outputting unstructured logs. |
| 157 | + return true |
192 | 158 | }
|
193 |
| - return level |
| 159 | + return unstructuredLogs |
194 | 160 | }
|
0 commit comments