mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-12-29 16:30:19 +00:00
222 lines
6.5 KiB
Go
222 lines
6.5 KiB
Go
|
package flume
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"go.uber.org/zap/zapcore"
|
||
|
"os"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// DefaultConfigEnvVars is a list of the environment variables
|
||
|
// that ConfigFromEnv will search by default.
|
||
|
var DefaultConfigEnvVars = []string{"FLUME"}
|
||
|
|
||
|
// ConfigFromEnv configures flume from environment variables.
|
||
|
// It should be called from main():
|
||
|
//
|
||
|
// func main() {
|
||
|
// flume.ConfigFromEnv()
|
||
|
// ...
|
||
|
// }
|
||
|
//
|
||
|
// It searches envvars for the first environment
|
||
|
// variable that is set, and attempts to parse the value.
|
||
|
//
|
||
|
// If no environment variable is set, it silently does nothing.
|
||
|
//
|
||
|
// If an environment variable with a value is found, but parsing
|
||
|
// fails, an error is printed to stdout, and the error is returned.
|
||
|
//
|
||
|
// If envvars is empty, it defaults to DefaultConfigEnvVars.
|
||
|
//
|
||
|
func ConfigFromEnv(envvars ...string) error {
|
||
|
if len(envvars) == 0 {
|
||
|
envvars = DefaultConfigEnvVars
|
||
|
}
|
||
|
|
||
|
var configString string
|
||
|
|
||
|
for _, v := range envvars {
|
||
|
configString = os.Getenv(v)
|
||
|
if configString != "" {
|
||
|
err := ConfigString(configString)
|
||
|
if err != nil {
|
||
|
fmt.Println("error parsing log config from env var " + v + ": " + err.Error())
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Config offers a declarative way to configure a Factory.
|
||
|
//
|
||
|
// The same things can be done by calling Factory methods, but
|
||
|
// Configs can be unmarshaled from JSON, making it a convenient
|
||
|
// way to configure most logging options from env vars or files, i.e.:
|
||
|
//
|
||
|
// err := flume.ConfigString(os.Getenv("flume"))
|
||
|
//
|
||
|
// Configs can be created and applied programmatically:
|
||
|
//
|
||
|
// err := flume.Configure(flume.Config{})
|
||
|
//
|
||
|
// Defaults are appropriate for a JSON encoded production logger:
|
||
|
//
|
||
|
// - LTSV encoder
|
||
|
// - full timestamps
|
||
|
// - default log level set to INFO
|
||
|
// - call sites are not logged
|
||
|
//
|
||
|
// An alternate set of defaults, more appropriate for development environments,
|
||
|
// can be configured with `Config{Development:true}`:
|
||
|
//
|
||
|
// err := flume.Configure(flume.Config{Development:true})
|
||
|
//
|
||
|
// - colorized terminal encoder
|
||
|
// - short timestamps
|
||
|
// - call sites are logged
|
||
|
//
|
||
|
// err := flume.Configure(flume.Config{Development:true})
|
||
|
//
|
||
|
// Any of the other configuration options can be specified to override
|
||
|
// the defaults.
|
||
|
//
|
||
|
// Note: If configuring the EncoderConfig setting, if any of the *Key properties
|
||
|
// are omitted, that entire field will be omitted.
|
||
|
type Config struct {
|
||
|
// DefaultLevel is the default log level for all loggers not
|
||
|
// otherwise configured by Levels. Defaults to Info.
|
||
|
DefaultLevel Level `json:"level" yaml:"level"`
|
||
|
// Levels configures log levels for particular named loggers. See
|
||
|
// LevelsString for format.
|
||
|
Levels string `json:"levels" yaml:"levels"`
|
||
|
// AddCaller annotates logs with the calling function's file
|
||
|
// name and line number. Defaults to true when the Development
|
||
|
// flag is set, false otherwise.
|
||
|
AddCaller *bool `json:"addCaller" yaml:"addCaller"`
|
||
|
// Encoding sets the logger's encoding. Valid values are "json",
|
||
|
// "console", "ltsv", "term", and "term-color".
|
||
|
// Defaults to "term-color" if development is true, else
|
||
|
// "ltsv"
|
||
|
Encoding string `json:"encoding" yaml:"encoding"`
|
||
|
// Development toggles the defaults used for the other
|
||
|
// settings. Defaults to false.
|
||
|
Development bool `json:"development" yaml:"development"`
|
||
|
// EncoderConfig sets options for the chosen encoder. See
|
||
|
// EncoderConfig for details. Defaults to NewEncoderConfig() if
|
||
|
// Development is false, otherwise defaults to NewDevelopmentEncoderConfig().
|
||
|
EncoderConfig *EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
|
||
|
}
|
||
|
|
||
|
// SetAddCaller sets the Config's AddCaller flag.
|
||
|
func (c *Config) SetAddCaller(b bool) {
|
||
|
c.AddCaller = &b
|
||
|
}
|
||
|
|
||
|
// UnsetAddCaller unsets the Config's AddCaller flag (reverting to defaults).
|
||
|
func (c *Config) UnsetAddCaller() {
|
||
|
c.AddCaller = nil
|
||
|
}
|
||
|
|
||
|
// EncoderConfig captures the options for encoders.
|
||
|
// Type alias to avoid exporting zap.
|
||
|
type EncoderConfig zapcore.EncoderConfig
|
||
|
|
||
|
type privEncCfg struct {
|
||
|
EncodeLevel string `json:"levelEncoder" yaml:"levelEncoder"`
|
||
|
EncodeTime string `json:"timeEncoder" yaml:"timeEncoder"`
|
||
|
}
|
||
|
|
||
|
// UnmarshalJSON implements json.Marshaler
|
||
|
func (enc *EncoderConfig) UnmarshalJSON(b []byte) error {
|
||
|
var zapCfg zapcore.EncoderConfig
|
||
|
err := json.Unmarshal(b, &zapCfg)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
var pc privEncCfg
|
||
|
err = json.Unmarshal(b, &pc)
|
||
|
if err == nil {
|
||
|
switch pc.EncodeLevel {
|
||
|
case "", "abbr":
|
||
|
zapCfg.EncodeLevel = AbbrLevelEncoder
|
||
|
}
|
||
|
switch pc.EncodeTime {
|
||
|
case "":
|
||
|
zapCfg.EncodeTime = zapcore.ISO8601TimeEncoder
|
||
|
case "justtime":
|
||
|
zapCfg.EncodeTime = JustTimeEncoder
|
||
|
}
|
||
|
}
|
||
|
*enc = EncoderConfig(zapCfg)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// NewEncoderConfig returns an EncoderConfig with default settings.
|
||
|
func NewEncoderConfig() *EncoderConfig {
|
||
|
return &EncoderConfig{
|
||
|
MessageKey: "msg",
|
||
|
TimeKey: "time",
|
||
|
LevelKey: "level",
|
||
|
NameKey: "name",
|
||
|
CallerKey: "caller",
|
||
|
StacktraceKey: "stacktrace",
|
||
|
EncodeTime: zapcore.ISO8601TimeEncoder,
|
||
|
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||
|
EncodeLevel: AbbrLevelEncoder,
|
||
|
EncodeCaller: zapcore.ShortCallerEncoder,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NewDevelopmentEncoderConfig returns an EncoderConfig which is intended
|
||
|
// for local development.
|
||
|
func NewDevelopmentEncoderConfig() *EncoderConfig {
|
||
|
cfg := NewEncoderConfig()
|
||
|
cfg.EncodeTime = JustTimeEncoder
|
||
|
cfg.EncodeDuration = zapcore.StringDurationEncoder
|
||
|
return cfg
|
||
|
}
|
||
|
|
||
|
// JustTimeEncoder is a timestamp encoder function which encodes time
|
||
|
// as a simple time of day, without a date. Intended for development and testing.
|
||
|
// Not good in a production system, where you probably need to know the date.
|
||
|
//
|
||
|
// encConfig := flume.EncoderConfig{}
|
||
|
// encConfig.EncodeTime = flume.JustTimeEncoder
|
||
|
//
|
||
|
func JustTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
|
||
|
enc.AppendString(t.Format("15:04:05.000"))
|
||
|
}
|
||
|
|
||
|
// AbbrLevelEncoder encodes logging levels to the strings in the log entries.
|
||
|
// Encodes levels as 3-char abbreviations in upper case.
|
||
|
//
|
||
|
// encConfig := flume.EncoderConfig{}
|
||
|
// encConfig.EncodeTime = flume.AbbrLevelEncoder
|
||
|
//
|
||
|
func AbbrLevelEncoder(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
|
||
|
switch l {
|
||
|
case zapcore.DebugLevel:
|
||
|
enc.AppendString("DBG")
|
||
|
case zapcore.InfoLevel:
|
||
|
enc.AppendString("INF")
|
||
|
case zapcore.WarnLevel:
|
||
|
enc.AppendString("WRN")
|
||
|
case zapcore.ErrorLevel:
|
||
|
enc.AppendString("ERR")
|
||
|
case zapcore.PanicLevel, zapcore.FatalLevel, zapcore.DPanicLevel:
|
||
|
enc.AppendString("FTL")
|
||
|
default:
|
||
|
s := l.String()
|
||
|
if len(s) > 3 {
|
||
|
s = s[:3]
|
||
|
}
|
||
|
enc.AppendString(strings.ToUpper(s))
|
||
|
|
||
|
}
|
||
|
}
|