Skip to content

Commit

Permalink
etcd: Support configuring zap console log format with --log-format flag
Browse files Browse the repository at this point in the history
Console format is much easier to read during development when compared
to json.
  • Loading branch information
serathius committed May 14, 2021
1 parent 7ba53c7 commit 4938859
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 1 deletion.
8 changes: 8 additions & 0 deletions server/embed/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,8 @@ type Config struct {
// Logger is logger options: currently only supports "zap".
// "capnslog" is removed in v3.5.
Logger string `json:"logger"`
// LogFormat configures format of logs. Only supports json, console. Default 'json'.
LogFormat string `json:"log-format"`
// LogLevel configures log level. Only supports debug, info, warn, error, panic, or fatal. Default 'info'.
LogLevel string `json:"log-level"`
// LogOutputs is either:
Expand Down Expand Up @@ -485,6 +487,7 @@ func NewConfig() *Config {
loggerMu: new(sync.RWMutex),
logger: nil,
Logger: "zap",
LogFormat: "json",
LogOutputs: []string{DefaultLogOutput},
LogLevel: logutil.DefaultLogLevel,
EnableLogRotation: false,
Expand Down Expand Up @@ -619,6 +622,11 @@ func updateCipherSuites(tls *transport.TLSInfo, ss []string) error {

// Validate ensures that '*embed.Config' fields are properly configured.
func (cfg *Config) Validate() error {
switch cfg.LogFormat {
case "json", "console":
default:
return fmt.Errorf("--log-format=%s is not supported", cfg.LogFormat)
}
if err := cfg.setupLogging(); err != nil {
return err
}
Expand Down
5 changes: 4 additions & 1 deletion server/embed/config_logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func (cfg *Config) setupLogging() error {

if !isJournal {
copied := logutil.DefaultZapLoggerConfig
copied.OutputPaths = outputPaths
copied.Encoding = cfg.LogFormat
copied.ErrorOutputPaths = errOutputPaths
copied = logutil.MergeOutputPaths(copied)
copied.Level = zap.NewAtomicLevelAt(logutil.ConvertToZapLevel(cfg.LogLevel))
Expand All @@ -125,6 +125,9 @@ func (cfg *Config) setupLogging() error {
}
}
}
if cfg.LogFormat != logutil.DefaultLogLevel {
return fmt.Errorf("--log-format=%q with systemd/journal is not supported", cfg.LogFormat)
}

// use stderr as fallback
syncer, lerr := getJournalWriteSyncer()
Expand Down
45 changes: 45 additions & 0 deletions server/embed/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,3 +364,48 @@ func TestLogRotation(t *testing.T) {
})
}
}

func TestLogFormat(t *testing.T) {
tests := []struct {
name string
LogFormat string
wantErr bool
wantErrMsg error
}{
{
name: "default",
},
{
name: "json",
LogFormat: "json",
},
{
name: "console",
LogFormat: "console",
},
{
name: "unsupported",
LogFormat: "xml",
wantErr: true,
wantErrMsg: errors.New("--log-format=xml is not supported"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg := NewConfig()
if tt.LogFormat != "" {
cfg.LogFormat = tt.LogFormat
}
err := cfg.Validate()
if err != nil && !tt.wantErr {
t.Errorf("test %q, unexpected error %v", tt.name, err)
}
if err != nil && tt.wantErr && tt.wantErrMsg.Error() != err.Error() {
t.Errorf("test %q, expected error: %+v, got: %+v", tt.name, tt.wantErrMsg, err)
}
if err == nil && tt.wantErr {
t.Errorf("test %q, expected error, got nil", tt.name)
}
})
}
}
1 change: 1 addition & 0 deletions server/etcdmain/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ func newConfig() *config {

// logging
fs.StringVar(&cfg.ec.Logger, "logger", "zap", "Currently only supports 'zap' for structured logging.")
fs.StringVar(&cfg.ec.LogFormat, "log-format", "json", "Configures format of logs. Only supports json, console. Default 'json'.")
fs.Var(flags.NewUniqueStringsValue(embed.DefaultLogOutput), "log-outputs", "Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd, or list of comma separated output targets.")
fs.StringVar(&cfg.ec.LogLevel, "log-level", logutil.DefaultLogLevel, "Configures log level. Only supports debug, info, warn, error, panic, or fatal. Default 'info'.")
fs.BoolVar(&cfg.ec.EnableLogRotation, "enable-log-rotation", false, "Enable log rotation of a single log-outputs file target.")
Expand Down
2 changes: 2 additions & 0 deletions server/etcdmain/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ Profiling and Monitoring:
Logging:
--logger 'zap'
Currently only supports 'zap' for structured logging.
--log-format 'json'
LogFormat configures format of logs. Only supports json, console.
--log-outputs 'default'
Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd, or list of comma separated output targets.
--log-level 'info'
Expand Down
2 changes: 2 additions & 0 deletions tests/integration/embed/embed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func TestEmbedEtcd(t *testing.T) {
for i := range tests {
tests[i].cfg = *embed.NewConfig()
tests[i].cfg.Logger = "zap"
tests[i].cfg.LogFormat = "json"
tests[i].cfg.LogOutputs = []string{"/dev/null"}
}

Expand Down Expand Up @@ -199,6 +200,7 @@ func newEmbedURLs(secure bool, n int) (urls []url.URL) {

func setupEmbedCfg(cfg *embed.Config, curls []url.URL, purls []url.URL) {
cfg.Logger = "zap"
cfg.LogFormat = "json"
cfg.LogOutputs = []string{"/dev/null"}

cfg.ClusterState = "new"
Expand Down
1 change: 1 addition & 0 deletions tools/etcd-dump-metrics/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func newEmbedURLs(n int) (urls []url.URL) {

func setupEmbedCfg(cfg *embed.Config, curls, purls, ics []url.URL) {
cfg.Logger = "zap"
cfg.LogFormat = "json"
cfg.LogOutputs = []string{"/dev/null"}
// []string{"stderr"} to enable server logging

Expand Down

0 comments on commit 4938859

Please sign in to comment.