github.com/lastbackend/toolkit@v0.0.0-20241020043710-cafa37b95aad/pkg/runtime/logger/zap/zap.go (about) 1 /* 2 Copyright [2014] - [2023] The Last.Backend authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package zap 18 19 import ( 20 "fmt" 21 "os" 22 23 "github.com/lastbackend/toolkit/pkg/runtime" 24 "github.com/lastbackend/toolkit/pkg/runtime/logger" 25 "github.com/lastbackend/toolkit/pkg/runtime/logger/empty" 26 "go.uber.org/fx/fxevent" 27 "go.uber.org/zap" 28 "go.uber.org/zap/zapcore" 29 30 "sync" 31 ) 32 33 type zapLogger struct { 34 sync.RWMutex 35 logger *zap.SugaredLogger 36 opts logger.Options 37 empty logger.Logger 38 } 39 40 func NewLogger(runtime runtime.Runtime, fields logger.Fields) logger.Logger { 41 42 l := &zapLogger{ 43 empty: empty.NewLogger(), 44 } 45 46 runtime.Config().Parse(&l.opts, "") 47 if l.opts.CallerSkipCount == 0 { 48 l.opts.CallerSkipCount = 1 49 } 50 51 // info level enabler 52 infoLevel := zap.LevelEnablerFunc(func(level zapcore.Level) bool { 53 return level == zapcore.InfoLevel 54 }) 55 56 // error and fatal level enabler 57 errorFatalLevel := zap.LevelEnablerFunc(func(level zapcore.Level) bool { 58 return level == zapcore.ErrorLevel || level == zapcore.FatalLevel 59 }) 60 61 // write syncers 62 stdoutSyncer := zapcore.Lock(os.Stdout) 63 stderrSyncer := zapcore.Lock(os.Stderr) 64 65 encoderConfig := zap.NewProductionEncoderConfig() 66 encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder 67 68 encoder := zapcore.NewConsoleEncoder(encoderConfig) 69 if l.opts.JSONFormat { 70 encoder = zapcore.NewJSONEncoder(encoderConfig) 71 } 72 73 zapOptions := make([]zap.Option, 0) 74 zapOptions = append(zapOptions, zap.AddCallerSkip(l.opts.CallerSkipCount)) 75 zapOptions = append(zapOptions, zap.AddCaller()) 76 77 // tee core 78 core := zapcore.NewTee( 79 zapcore.NewCore( 80 encoder, 81 stdoutSyncer, 82 infoLevel, 83 ), 84 zapcore.NewCore( 85 encoder, 86 stderrSyncer, 87 errorFatalLevel, 88 ), 89 ) 90 91 l.logger = zap.New(core, zapOptions...).Sugar().With() 92 93 return l 94 } 95 96 func (l *zapLogger) Debug(args ...interface{}) { 97 l.logger.Debug(args...) 98 } 99 100 func (l *zapLogger) Debugf(format string, args ...interface{}) { 101 l.logger.Debugf(format, args...) 102 } 103 104 func (l *zapLogger) Info(args ...interface{}) { 105 l.logger.Info(args...) 106 } 107 108 func (l *zapLogger) Infof(format string, args ...interface{}) { 109 l.logger.Infof(format, args...) 110 } 111 112 func (l *zapLogger) Warn(args ...interface{}) { 113 l.logger.Warn(args...) 114 } 115 116 func (l *zapLogger) Warnf(format string, args ...interface{}) { 117 l.logger.Warnf(format, args...) 118 } 119 120 func (l *zapLogger) Error(args ...interface{}) { 121 l.logger.Error(args...) 122 } 123 124 func (l *zapLogger) Errorf(format string, args ...interface{}) { 125 l.logger.Errorf(format, args...) 126 } 127 128 func (l *zapLogger) Panic(args ...interface{}) { 129 l.logger.Fatal(args...) 130 } 131 132 func (l *zapLogger) Panicf(format string, args ...interface{}) { 133 l.logger.Fatalf(format, args...) 134 } 135 136 func (l *zapLogger) Fatal(args ...interface{}) { 137 l.logger.Fatal(args...) 138 } 139 140 func (l *zapLogger) Fatalf(format string, args ...interface{}) { 141 l.logger.Fatalf(format, args...) 142 } 143 144 func (l *zapLogger) V(level logger.Level) logger.Logger { 145 146 if l.opts.Verbose < level { 147 return l.empty 148 } 149 150 return l 151 } 152 153 func (l *zapLogger) Inject(fn func(level logger.Level)) { 154 return 155 } 156 157 func (l *zapLogger) Fx() fxevent.Logger { 158 159 if l.opts.Verbose < 6 { 160 return l.empty.Fx() 161 } 162 163 return &fxevent.ZapLogger{ 164 Logger: l.logger.Desugar(), 165 } 166 } 167 168 func getZapLevel(level logger.Level) zapcore.Level { 169 switch level { 170 case logger.DebugLevel: 171 return zapcore.DebugLevel 172 case logger.InfoLevel: 173 return zapcore.InfoLevel 174 case logger.WarnLevel: 175 return zapcore.WarnLevel 176 case logger.ErrorLevel: 177 return zapcore.ErrorLevel 178 case logger.FatalLevel: 179 return zapcore.FatalLevel 180 case logger.PanicLevel: 181 return zapcore.PanicLevel 182 default: 183 return zapcore.InfoLevel 184 } 185 } 186 187 func (l *zapLogger) getFields(fields logger.Fields) []zapcore.Field { 188 return l.fieldsMerge(l.opts.Fields, fields) 189 } 190 191 func (l *zapLogger) fieldsMerge(parent, src map[string]interface{}) []zapcore.Field { 192 193 var ( 194 i = 0 195 dst = make([]zapcore.Field, len(parent)+len(src)) 196 ) 197 198 for k, v := range parent { 199 switch v := v.(type) { 200 case int: 201 dst[i] = zap.Int(k, v) 202 case float64: 203 dst[i] = zap.Float64(k, v) 204 case string: 205 dst[i] = zap.String(k, v) 206 default: 207 dst[i] = zap.String(k, fmt.Sprintf("%s", v)) 208 } 209 i++ 210 } 211 212 for k, v := range src { 213 switch v := v.(type) { 214 case int: 215 dst[i] = zap.Int(k, v) 216 case float64: 217 dst[i] = zap.Float64(k, v) 218 case string: 219 dst[i] = zap.String(k, v) 220 default: 221 dst[i] = zap.String(k, fmt.Sprintf("%s", v)) 222 } 223 i++ 224 } 225 return dst 226 }