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  }