github.com/jayanthvn/pure-gobpf@v0.0.0-20230623131354-8d1d959d9e0b/pkg/logger/logger.go (about) 1 // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 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 package logger 16 17 import ( 18 "os" 19 "runtime" 20 "strings" 21 22 "go.uber.org/zap" 23 "go.uber.org/zap/zapcore" 24 "gopkg.in/natefinch/lumberjack.v2" 25 ) 26 27 const ( 28 defaultLogFilePath = "/var/log/aws-routed-eni/ebpf-sdk.log" 29 defaultLogLevel = "Debug" 30 envLogLevel = "AWS_EBPF_SDK_LOGLEVEL" 31 envLogFilePath = "AWS_EBPF_SDK_LOG_FILE" 32 ) 33 34 // Log is global variable so that log functions can be directly accessed 35 var log Logger 36 37 // Fields Type to pass when we want to call WithFields for structured logging 38 type Fields map[string]interface{} 39 40 // Logger is our contract for the logger 41 type Logger interface { 42 Debugf(format string, args ...interface{}) 43 44 Debug(format string) 45 46 Infof(format string, args ...interface{}) 47 48 Info(format string) 49 50 Warnf(format string, args ...interface{}) 51 52 Warn(format string) 53 54 Errorf(format string, args ...interface{}) 55 56 Error(format string) 57 58 Fatalf(format string, args ...interface{}) 59 60 Panicf(format string, args ...interface{}) 61 62 WithFields(keyValues Fields) Logger 63 } 64 65 // Configuration stores the config for the logger 66 type Configuration struct { 67 LogLevel string 68 LogLocation string 69 } 70 71 // LoadLogConfig returns the log configuration 72 func LoadLogConfig() *Configuration { 73 return &Configuration{ 74 LogLevel: GetLogLevel(), 75 LogLocation: GetLogLocation(), 76 } 77 } 78 79 // GetLogLocation returns the log file path 80 func GetLogLocation() string { 81 logFilePath := os.Getenv(envLogFilePath) 82 if logFilePath == "" { 83 logFilePath = defaultLogFilePath 84 } 85 return logFilePath 86 } 87 88 // GetLogLevel returns the log level 89 func GetLogLevel() string { 90 logLevel := os.Getenv(envLogLevel) 91 switch logLevel { 92 case "": 93 logLevel = defaultLogLevel 94 return logLevel 95 default: 96 return logLevel 97 } 98 } 99 100 type structuredLogger struct { 101 zapLogger *zap.SugaredLogger 102 } 103 104 // getZapLevel converts log level string to zapcore.Level 105 func getZapLevel(inputLogLevel string) zapcore.Level { 106 lvl := strings.ToLower(inputLogLevel) 107 108 switch lvl { 109 case "debug": 110 return zapcore.DebugLevel 111 case "info": 112 return zapcore.InfoLevel 113 case "warn": 114 return zapcore.WarnLevel 115 case "error": 116 return zapcore.ErrorLevel 117 case "fatal": 118 return zapcore.FatalLevel 119 default: 120 return zapcore.DebugLevel 121 } 122 } 123 124 func (logf *structuredLogger) Debugf(format string, args ...interface{}) { 125 logf.zapLogger.Debugf(format, args...) 126 } 127 128 func (logf *structuredLogger) Debug(format string) { 129 logf.zapLogger.Desugar().Debug(format) 130 } 131 132 func (logf *structuredLogger) Infof(format string, args ...interface{}) { 133 logf.zapLogger.Infof(format, args...) 134 } 135 136 func (logf *structuredLogger) Info(format string) { 137 logf.zapLogger.Desugar().Info(format) 138 } 139 140 func (logf *structuredLogger) Warnf(format string, args ...interface{}) { 141 logf.zapLogger.Warnf(format, args...) 142 } 143 144 func (logf *structuredLogger) Warn(format string) { 145 logf.zapLogger.Desugar().Warn(format) 146 } 147 148 func (logf *structuredLogger) Error(format string) { 149 logf.zapLogger.Desugar().Error(format) 150 } 151 152 func (logf *structuredLogger) Errorf(format string, args ...interface{}) { 153 logf.zapLogger.Errorf(format, args...) 154 } 155 156 func (logf *structuredLogger) Fatalf(format string, args ...interface{}) { 157 logf.zapLogger.Fatalf(format, args...) 158 } 159 160 func (logf *structuredLogger) Panicf(format string, args ...interface{}) { 161 logf.zapLogger.Fatalf(format, args...) 162 } 163 164 func (logf *structuredLogger) WithFields(fields Fields) Logger { 165 var f = make([]interface{}, 0) 166 for k, v := range fields { 167 f = append(f, k) 168 f = append(f, v) 169 } 170 newLogger := logf.zapLogger.With(f...) 171 return &structuredLogger{newLogger} 172 } 173 174 func getEncoder() zapcore.Encoder { 175 encoderConfig := zap.NewProductionEncoderConfig() 176 encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder 177 return zapcore.NewJSONEncoder(encoderConfig) 178 } 179 180 func (logConfig *Configuration) newZapLogger() *structuredLogger { 181 var cores []zapcore.Core 182 183 logLevel := getZapLevel(logConfig.LogLevel) 184 185 writer := getSDKLogFilePath(logConfig.LogLocation) 186 187 cores = append(cores, zapcore.NewCore(getEncoder(), writer, logLevel)) 188 189 combinedCore := zapcore.NewTee(cores...) 190 191 logger := zap.New(combinedCore, 192 zap.AddCaller(), 193 zap.AddCallerSkip(2), 194 ) 195 defer logger.Sync() 196 sugar := logger.Sugar() 197 198 return &structuredLogger{ 199 zapLogger: sugar, 200 } 201 } 202 203 // getSDKLogFilePath returns the writer 204 func getSDKLogFilePath(logFilePath string) zapcore.WriteSyncer { 205 var writer zapcore.WriteSyncer 206 207 if logFilePath == "" { 208 writer = zapcore.Lock(os.Stderr) 209 } else if strings.ToLower(logFilePath) != "stdout" { 210 writer = getLogWriter(logFilePath) 211 } else { 212 writer = zapcore.Lock(os.Stdout) 213 } 214 215 return writer 216 } 217 218 // getLogWriter is for lumberjack 219 func getLogWriter(logFilePath string) zapcore.WriteSyncer { 220 lumberJackLogger := &lumberjack.Logger{ 221 Filename: logFilePath, 222 MaxSize: 100, 223 MaxBackups: 5, 224 MaxAge: 30, 225 Compress: true, 226 } 227 return zapcore.AddSync(lumberJackLogger) 228 } 229 230 // DefaultLogger creates and returns a new default logger. 231 func DefaultLogger() Logger { 232 productionConfig := zap.NewProductionConfig() 233 productionConfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder 234 productionConfig.EncoderConfig.EncodeCaller = func(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) { 235 _, caller.File, caller.Line, _ = runtime.Caller(8) 236 enc.AppendString(caller.FullPath()) 237 } 238 logger, _ := productionConfig.Build() 239 defer logger.Sync() 240 sugar := logger.Sugar() 241 return &structuredLogger{ 242 zapLogger: sugar, 243 } 244 } 245 246 // Get returns an default instance of the zap logger 247 func Get() Logger { 248 if log == nil { 249 logConfig := LoadLogConfig() 250 log = New(logConfig) 251 log.Info("Initialized new logger as an existing instance was not found") 252 } 253 return log 254 } 255 256 // New logger initializes logger 257 func New(inputLogConfig *Configuration) Logger { 258 log = inputLogConfig.newZapLogger() 259 log.Info("Constructed new logger instance") 260 return log 261 }