github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/log/config.go (about) 1 // Copyright (c) 2021 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package log 22 23 import ( 24 "fmt" 25 26 "go.uber.org/zap" 27 "go.uber.org/zap/zapcore" 28 ) 29 30 // Configuration defines configuration for logging. 31 type Configuration struct { 32 File string `json:"file" yaml:"file"` 33 Level string `json:"level" yaml:"level"` 34 Fields map[string]interface{} `json:"fields" yaml:"fields"` 35 EncoderConfig encoderConfig `json:"encoderConfig,omitempty" yaml:"encoderConfig,omitempty"` 36 } 37 38 type encoderConfig struct { 39 MessageKey string `json:"messageKey" yaml:"messageKey"` 40 LevelKey string `json:"levelKey" yaml:"levelKey"` 41 TimeKey string `json:"timeKey" yaml:"timeKey"` 42 NameKey string `json:"nameKey" yaml:"nameKey"` 43 CallerKey string `json:"callerKey" yaml:"callerKey"` 44 FunctionKey string `json:"functionKey" yaml:"functionKey"` 45 StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"` 46 LineEnding string `json:"lineEnding" yaml:"lineEnding"` 47 EncodeLevel string `json:"levelEncoder" yaml:"levelEncoder"` 48 EncodeTime string `json:"timeEncoder" yaml:"timeEncoder"` 49 EncodeDuration string `json:"durationEncoder" yaml:"durationEncoder"` 50 EncodeCaller string `json:"callerEncoder" yaml:"callerEncoder"` 51 EncodeName string `json:"nameEncoder" yaml:"nameEncoder,omitempty"` 52 } 53 54 // BuildLogger builds a new Logger based on the configuration. 55 func (cfg Configuration) BuildLogger() (*zap.Logger, error) { 56 logger, _, err := cfg.BuildLoggerAndReturnConfig() 57 return logger, err 58 } 59 60 // BuildLoggerAndReturnConfig builds a new Logger based on the configuration and returns a zap.Config object. 61 func (cfg Configuration) BuildLoggerAndReturnConfig() (*zap.Logger, *zap.Config, error) { 62 zc := zap.Config{ 63 Level: zap.NewAtomicLevelAt(zap.InfoLevel), 64 Development: false, 65 DisableCaller: true, 66 DisableStacktrace: true, 67 Sampling: &zap.SamplingConfig{ 68 Initial: 100, 69 Thereafter: 100, 70 }, 71 Encoding: "json", 72 EncoderConfig: cfg.newEncoderConfig(), 73 OutputPaths: []string{"stdout"}, 74 ErrorOutputPaths: []string{"stdout"}, 75 InitialFields: cfg.Fields, 76 } 77 78 if cfg.File != "" { 79 zc.OutputPaths = append(zc.OutputPaths, cfg.File) 80 zc.ErrorOutputPaths = append(zc.ErrorOutputPaths, cfg.File) 81 } 82 83 if len(cfg.Level) != 0 { 84 var parsedLevel zap.AtomicLevel 85 if err := parsedLevel.UnmarshalText([]byte(cfg.Level)); err != nil { 86 return nil, nil, fmt.Errorf("unable to parse log level %s: %w", cfg.Level, err) 87 } 88 zc.Level = parsedLevel 89 } 90 logger, err := zc.Build() 91 return logger, &zc, err 92 } 93 94 func (cfg Configuration) newEncoderConfig() zapcore.EncoderConfig { 95 ec := zap.NewProductionEncoderConfig() 96 97 if cfg.EncoderConfig.MessageKey != "" { 98 ec.MessageKey = cfg.EncoderConfig.MessageKey 99 } 100 101 if cfg.EncoderConfig.LevelKey != "" { 102 ec.LevelKey = cfg.EncoderConfig.LevelKey 103 } 104 105 if cfg.EncoderConfig.TimeKey != "" { 106 ec.TimeKey = cfg.EncoderConfig.TimeKey 107 } 108 109 if cfg.EncoderConfig.NameKey != "" { 110 ec.NameKey = cfg.EncoderConfig.NameKey 111 } 112 113 if cfg.EncoderConfig.CallerKey != "" { 114 ec.CallerKey = cfg.EncoderConfig.CallerKey 115 } 116 117 if cfg.EncoderConfig.FunctionKey != "" { 118 ec.FunctionKey = cfg.EncoderConfig.FunctionKey 119 } 120 121 if cfg.EncoderConfig.StacktraceKey != "" { 122 ec.StacktraceKey = cfg.EncoderConfig.StacktraceKey 123 } 124 125 if cfg.EncoderConfig.LineEnding != "" { 126 ec.LineEnding = cfg.EncoderConfig.LineEnding 127 } 128 129 if cfg.EncoderConfig.EncodeLevel != "" { 130 var levelEncoder zapcore.LevelEncoder 131 _ = levelEncoder.UnmarshalText([]byte(cfg.EncoderConfig.EncodeLevel)) 132 ec.EncodeLevel = levelEncoder 133 } 134 135 if cfg.EncoderConfig.EncodeTime != "" { 136 var timeEncoder zapcore.TimeEncoder 137 _ = timeEncoder.UnmarshalText([]byte(cfg.EncoderConfig.EncodeTime)) 138 ec.EncodeTime = timeEncoder 139 } 140 141 if cfg.EncoderConfig.EncodeDuration != "" { 142 var durationEncoder zapcore.DurationEncoder 143 _ = durationEncoder.UnmarshalText([]byte(cfg.EncoderConfig.EncodeDuration)) 144 ec.EncodeDuration = durationEncoder 145 } 146 147 if cfg.EncoderConfig.EncodeCaller != "" { 148 var callerEncoder zapcore.CallerEncoder 149 _ = callerEncoder.UnmarshalText([]byte(cfg.EncoderConfig.EncodeCaller)) 150 ec.EncodeCaller = callerEncoder 151 } 152 153 if cfg.EncoderConfig.EncodeName != "" { 154 var nameEncoder zapcore.NameEncoder 155 _ = nameEncoder.UnmarshalText([]byte(cfg.EncoderConfig.EncodeName)) 156 ec.EncodeName = nameEncoder 157 } 158 159 return ec 160 }