github.com/m3db/m3@v1.5.0/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 zc := zap.Config{ 57 Level: zap.NewAtomicLevelAt(zap.InfoLevel), 58 Development: false, 59 DisableCaller: true, 60 DisableStacktrace: true, 61 Sampling: &zap.SamplingConfig{ 62 Initial: 100, 63 Thereafter: 100, 64 }, 65 Encoding: "json", 66 EncoderConfig: cfg.newEncoderConfig(), 67 OutputPaths: []string{"stdout"}, 68 ErrorOutputPaths: []string{"stdout"}, 69 InitialFields: cfg.Fields, 70 } 71 72 if cfg.File != "" { 73 zc.OutputPaths = append(zc.OutputPaths, cfg.File) 74 zc.ErrorOutputPaths = append(zc.ErrorOutputPaths, cfg.File) 75 } 76 77 if len(cfg.Level) != 0 { 78 var parsedLevel zap.AtomicLevel 79 if err := parsedLevel.UnmarshalText([]byte(cfg.Level)); err != nil { 80 return nil, fmt.Errorf("unable to parse log level %s: %v", cfg.Level, err) 81 } 82 zc.Level = parsedLevel 83 } 84 85 return zc.Build() 86 } 87 88 func (cfg Configuration) newEncoderConfig() zapcore.EncoderConfig { 89 ec := zap.NewProductionEncoderConfig() 90 91 if cfg.EncoderConfig.MessageKey != "" { 92 ec.MessageKey = cfg.EncoderConfig.MessageKey 93 } 94 95 if cfg.EncoderConfig.LevelKey != "" { 96 ec.LevelKey = cfg.EncoderConfig.LevelKey 97 } 98 99 if cfg.EncoderConfig.TimeKey != "" { 100 ec.TimeKey = cfg.EncoderConfig.TimeKey 101 } 102 103 if cfg.EncoderConfig.NameKey != "" { 104 ec.NameKey = cfg.EncoderConfig.NameKey 105 } 106 107 if cfg.EncoderConfig.CallerKey != "" { 108 ec.CallerKey = cfg.EncoderConfig.CallerKey 109 } 110 111 if cfg.EncoderConfig.FunctionKey != "" { 112 ec.FunctionKey = cfg.EncoderConfig.FunctionKey 113 } 114 115 if cfg.EncoderConfig.StacktraceKey != "" { 116 ec.StacktraceKey = cfg.EncoderConfig.StacktraceKey 117 } 118 119 if cfg.EncoderConfig.LineEnding != "" { 120 ec.LineEnding = cfg.EncoderConfig.LineEnding 121 } 122 123 if cfg.EncoderConfig.EncodeLevel != "" { 124 var levelEncoder zapcore.LevelEncoder 125 _ = levelEncoder.UnmarshalText([]byte(cfg.EncoderConfig.EncodeLevel)) 126 ec.EncodeLevel = levelEncoder 127 } 128 129 if cfg.EncoderConfig.EncodeTime != "" { 130 var timeEncoder zapcore.TimeEncoder 131 _ = timeEncoder.UnmarshalText([]byte(cfg.EncoderConfig.EncodeTime)) 132 ec.EncodeTime = timeEncoder 133 } 134 135 if cfg.EncoderConfig.EncodeDuration != "" { 136 var durationEncoder zapcore.DurationEncoder 137 _ = durationEncoder.UnmarshalText([]byte(cfg.EncoderConfig.EncodeDuration)) 138 ec.EncodeDuration = durationEncoder 139 } 140 141 if cfg.EncoderConfig.EncodeCaller != "" { 142 var callerEncoder zapcore.CallerEncoder 143 _ = callerEncoder.UnmarshalText([]byte(cfg.EncoderConfig.EncodeCaller)) 144 ec.EncodeCaller = callerEncoder 145 } 146 147 if cfg.EncoderConfig.EncodeName != "" { 148 var nameEncoder zapcore.NameEncoder 149 _ = nameEncoder.UnmarshalText([]byte(cfg.EncoderConfig.EncodeName)) 150 ec.EncodeName = nameEncoder 151 } 152 153 return ec 154 }