github.com/lirm/aeron-go@v0.0.0-20230415210743-920325491dc4/aeron/logging/logging.go (about) 1 // Copyright (C) 2021 Talos, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Provides a transition layer from "github.com/op/go-logging" to 16 // "go.uber.org/zap" to simply resolve some reentrancy issues in go-logging. 17 // 18 // This provides a largely api compatible layer so we can quickly 19 // drop in a replacement. 20 package logging 21 22 import ( 23 "sync" 24 25 "go.uber.org/zap" 26 "go.uber.org/zap/zapcore" 27 ) 28 29 // Zaplogger is a container to wrap zap logging with the parts of the go-logging API we use 30 type ZapLogger struct { 31 name string 32 sugar *zap.SugaredLogger 33 logger *zap.Logger 34 config zap.Config 35 } 36 37 // Mapping of go-logging to zap log levels. It's imperfect but good enough 38 const ( 39 DEBUG = zapcore.DebugLevel 40 INFO = zapcore.InfoLevel 41 WARNING = zapcore.WarnLevel 42 NOTICE = zapcore.InfoLevel // Map to info 43 ERROR = zapcore.ErrorLevel 44 CRITICAL = zapcore.DPanicLevel 45 ) 46 47 // The go-logging package creates named loggers and allows them to be 48 // accessed by name This is used in aeron to allow parent code to set 49 // the logging level of library components so we need to provide a 50 // mechanism for that 51 var namedLoggers sync.Map // [string]*ZapLogger 52 53 // MustGetLogger returns a new logger or panic()s 54 func MustGetLogger(name string) *ZapLogger { 55 z := new(ZapLogger) 56 z.name = name 57 58 z.config = aeronLoggingConfig() 59 logger, err := z.config.Build() 60 if err != nil { 61 panic("Failed to make logger") 62 } 63 z.logger = logger.Named(name).WithOptions(zap.AddCallerSkip(1)) 64 z.sugar = z.logger.Sugar() 65 66 // Keep a reference 67 namedLoggers.Store(name, z) 68 69 return z 70 } 71 72 // newAeronEncoderConfig returns a default opinionated EncoderConfig for aeron 73 func newAeronEncoderConfig() zapcore.EncoderConfig { 74 return zapcore.EncoderConfig{ 75 TimeKey: "ts", 76 LevelKey: "level", 77 NameKey: "logger", 78 CallerKey: "caller", 79 FunctionKey: zapcore.OmitKey, 80 MessageKey: "msg", 81 StacktraceKey: "stacktrace", 82 LineEnding: zapcore.DefaultLineEnding, 83 EncodeLevel: zapcore.LowercaseLevelEncoder, 84 EncodeTime: zapcore.ISO8601TimeEncoder, 85 EncodeDuration: zapcore.SecondsDurationEncoder, 86 EncodeCaller: zapcore.ShortCallerEncoder, 87 } 88 } 89 90 // Default config 91 func aeronLoggingConfig() zap.Config { 92 return zap.Config{ 93 Level: zap.NewAtomicLevelAt(zap.InfoLevel), 94 Development: false, 95 Sampling: &zap.SamplingConfig{ 96 Initial: 100, 97 Thereafter: 100, 98 }, 99 Encoding: "console", 100 EncoderConfig: newAeronEncoderConfig(), 101 OutputPaths: []string{"stderr"}, 102 ErrorOutputPaths: []string{"stderr"}, 103 } 104 } 105 106 // SetConfigAndRebuild so you can replace the default config 107 func (z *ZapLogger) SetConfigAndRebuild(c zap.Config) error { 108 z.config = c 109 logger, err := z.config.Build() 110 if err != nil { 111 return err 112 } 113 114 z.logger = logger.Named(z.name) 115 z.sugar = z.logger.Sugar() 116 return nil 117 } 118 119 // SetLevel on a named logger 120 func SetLevel(l zapcore.Level, name string) { 121 z, ok := namedLoggers.Load(name) 122 if ok { 123 zlogger := z.(*ZapLogger) 124 zlogger.SetLevel(l) 125 } 126 } 127 128 // GetLevel on a named logger 129 func GetLevel(name string) zapcore.Level { 130 z, ok := namedLoggers.Load(name) 131 if ok { 132 zlogger := z.(*ZapLogger) 133 return zlogger.GetLevel() 134 } 135 136 // Bogus return but that's the API we are emulating and shouldn't happen 137 return zapcore.InfoLevel 138 } 139 140 // Sugar returns the internal Sugared logger 141 func (z *ZapLogger) Sugar() *zap.SugaredLogger { 142 return z.sugar 143 } 144 145 // SetSugar sets our internal Sugared logger 146 func (z *ZapLogger) SetSugar(s *zap.SugaredLogger) { 147 z.sugar = s 148 } 149 150 // Logger returns the internal zap logger 151 func (z *ZapLogger) Logger() *zap.Logger { 152 return z.logger 153 } 154 155 // SetLogger sets the internal zap logger 156 func (z *ZapLogger) SetLogger(l *zap.Logger) { 157 z.logger = l 158 } 159 160 // SetLevel sets the log level at which we will log 161 func (z *ZapLogger) SetLevel(l zapcore.Level) { 162 z.config.Level.SetLevel(l) 163 } 164 165 // GetLevel returns the log level at which we will log 166 func (z *ZapLogger) GetLevel() zapcore.Level { 167 return z.config.Level.Level() 168 } 169 170 // IsEnabledFor returns true if logging is enabled for the specified level 171 func (z *ZapLogger) IsEnabledFor(level zapcore.Level) bool { 172 return level >= z.GetLevel() 173 } 174 175 // Fatalf logs a formatted string at log level Fatal and will then always exit() 176 func (z *ZapLogger) Fatalf(template string, args ...interface{}) { 177 z.sugar.Fatalf(template, args...) 178 } 179 180 // Errorf logs a formatted string at log level Error 181 func (z *ZapLogger) Errorf(template string, args ...interface{}) { 182 z.sugar.Errorf(template, args...) 183 } 184 185 // Warningf logs a formatted string at log level Warning 186 func (z *ZapLogger) Warningf(template string, args ...interface{}) { 187 z.sugar.Warnf(template, args...) 188 } 189 190 // Infof logs a formatted string at log level Info 191 func (z *ZapLogger) Infof(template string, args ...interface{}) { 192 z.sugar.Infof(template, args...) 193 } 194 195 // Noticef logs a formatted string at log level *Info* 196 func (z *ZapLogger) Noticef(template string, args ...interface{}) { 197 z.sugar.Infof(template, args...) 198 } 199 200 // Debugf logs a formatted string at log level Debug 201 func (z *ZapLogger) Debugf(template string, args ...interface{}) { 202 z.sugar.Debugf(template, args...) 203 } 204 205 // Fatal logs it's arguments at log level Fatal 206 func (z *ZapLogger) Fatal(args ...interface{}) { 207 z.sugar.Fatal(args...) 208 } 209 210 // Error logs it's arguments at log level Error 211 func (z *ZapLogger) Error(args ...interface{}) { 212 z.sugar.Error(args...) 213 } 214 215 // Warning logs it's arguments at log level Warning 216 func (z *ZapLogger) Warning(args ...interface{}) { 217 z.sugar.Warn(args...) 218 } 219 220 // Info logs it's arguments at log level Info 221 func (z *ZapLogger) Info(args ...interface{}) { 222 z.sugar.Info(args...) 223 } 224 225 // Notice logs it's arguments at log level *Info* 226 func (z *ZapLogger) Notice(args ...interface{}) { 227 z.sugar.Info(args...) 228 } 229 230 // Debug logs it's arguments at log level Debug 231 func (z *ZapLogger) Debug(args ...interface{}) { 232 z.sugar.Debug(args...) 233 }