Merge pull request #10947 from gyuho/log-level

*: make log level configurable
This commit is contained in:
Gyuho Lee 2019-07-29 16:06:51 -07:00 committed by GitHub
commit 6e766ac5fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 172 additions and 45 deletions

View File

@ -342,7 +342,8 @@ The security flags help to [build a secure etcd cluster][security].
### --logger
**Available from v3.4**
**Available from v3.4.**
**WARNING: `--logger=capnslog` to be deprecated in v3.5.**
+ Specify 'zap' for structured logging or 'capnslog'.
+ default: capnslog
@ -354,12 +355,27 @@ The security flags help to [build a secure etcd cluster][security].
+ env variable: ETCD_LOG_OUTPUTS
+ 'default' use 'stderr' config for v3.4 during zap logger migraion
### --log-level
**Available from v3.4.**
+ Configures log level. Only supports debug, info, warn, error, panic, or fatal.
+ default: info
+ env variable: ETCD_LOG_LEVEL
+ 'default' use 'info'.
### --debug
**WARNING: to be deprecated in v3.5.**
+ Drop the default log level to DEBUG for all subpackages.
+ default: false (INFO for all packages)
+ env variable: ETCD_DEBUG
### --log-package-levels
**WARNING: to be deprecated in v3.5.**
+ Set individual etcd subpackages to specific log levels. An example being `etcdserver=WARNING,security=DEBUG`
+ default: "" (INFO for all packages)
+ env variable: ETCD_LOG_PACKAGE_LEVELS

View File

@ -30,6 +30,7 @@ import (
"go.etcd.io/etcd/etcdserver"
"go.etcd.io/etcd/etcdserver/api/v3compactor"
"go.etcd.io/etcd/pkg/flags"
"go.etcd.io/etcd/pkg/logutil"
"go.etcd.io/etcd/pkg/netutil"
"go.etcd.io/etcd/pkg/srv"
"go.etcd.io/etcd/pkg/tlsutil"
@ -291,11 +292,8 @@ type Config struct {
// Logger is logger options: "zap", "capnslog".
// WARN: "capnslog" is being deprecated in v3.5.
Logger string `json:"logger"`
// DeprecatedLogOutput is to be deprecated in v3.5.
// Just here for safe migration in v3.4.
DeprecatedLogOutput []string `json:"log-output"`
// LogLevel configures log level. Only supports debug, info, warn, error, panic, or fatal. Default 'info'.
LogLevel string `json:"log-level"`
// LogOutputs is either:
// - "default" as os.Stderr,
// - "stderr" as os.Stderr,
@ -304,11 +302,8 @@ type Config struct {
// It can be multiple when "Logger" is zap.
LogOutputs []string `json:"log-outputs"`
// Debug is true, to enable debug level logging.
Debug bool `json:"debug"`
// ZapLoggerBuilder is used to build the zap logger.
ZapLoggerBuilder func(*Config) error
// zapLoggerBuilder is used to build the zap logger.
zapLoggerBuilder func(*Config) error
// logger logs server-side operations. The default is nil,
// and "setupLogging" must be called before starting server.
@ -329,6 +324,12 @@ type Config struct {
// TO BE DEPRECATED
// DeprecatedLogOutput is to be deprecated in v3.5.
// Just here for safe migration in v3.4.
DeprecatedLogOutput []string `json:"log-output"`
// Debug is true, to enable debug level logging.
// WARNING: to be deprecated in 3.5. Use "--log-level=debug" instead.
Debug bool `json:"debug"`
// LogPkgLevels is being deprecated in v3.5.
// Only valid if "logger" option is "capnslog".
// WARN: DO NOT USE THIS!
@ -415,6 +416,7 @@ func NewConfig() *Config {
DeprecatedLogOutput: []string{DefaultLogOutput},
LogOutputs: []string{DefaultLogOutput},
Debug: false,
LogLevel: logutil.DefaultLogLevel,
LogPkgLevels: "",
}
cfg.InitialCluster = cfg.InitialClusterFromName(cfg.Name)

View File

@ -69,11 +69,25 @@ func (cfg *Config) setupLogging() error {
return fmt.Errorf("'--log-output=%q' and '--log-outputs=%q' are incompatible; only set --log-outputs", cfg.DeprecatedLogOutput, cfg.LogOutputs)
}
if !reflect.DeepEqual(cfg.DeprecatedLogOutput, []string{DefaultLogOutput}) {
fmt.Fprintf(os.Stderr, "Deprecated '--log-output' flag is set to %q\n", cfg.DeprecatedLogOutput)
fmt.Fprintf(os.Stderr, "[WARNING] Deprecated '--log-output' flag is set to %q\n", cfg.DeprecatedLogOutput)
fmt.Fprintln(os.Stderr, "Please use '--log-outputs' flag")
}
}
// TODO: remove after deprecating log related flags in v3.5
if cfg.Debug {
fmt.Fprintf(os.Stderr, "[WARNING] Deprecated '--debug' flag is set to %v (use '--log-level=debug' instead\n", cfg.Debug)
}
if cfg.Debug && cfg.LogLevel != "debug" {
fmt.Fprintf(os.Stderr, "[WARNING] Deprecated '--debug' flag is set to %v with inconsistent '--log-level=%s' flag\n", cfg.Debug, cfg.LogLevel)
}
if cfg.Logger == "capnslog" {
fmt.Fprintf(os.Stderr, "[WARNING] Deprecated '--logger=%s' flag is set; use '--logger=zap' flag instead\n", cfg.Logger)
}
if cfg.LogPkgLevels != "" {
fmt.Fprintf(os.Stderr, "[WARNING] Deprecated '--log-package-levels=%s' flag is set; use '--logger=zap' flag instead\n", cfg.LogPkgLevels)
}
switch cfg.Logger {
case "capnslog": // TODO: deprecate this in v3.5
cfg.ClientTLSInfo.HandshakeFailure = logTLSHandshakeFailure
@ -85,7 +99,7 @@ func (cfg *Config) setupLogging() error {
// enable info, warning, error
grpclog.SetLoggerV2(grpclog.NewLoggerV2(os.Stderr, os.Stderr, os.Stderr))
} else {
capnslog.SetGlobalLogLevel(capnslog.INFO)
capnslog.SetGlobalLogLevel(logutil.ConvertToCapnslogLogLevel(cfg.LogLevel))
// only discard info
grpclog.SetLoggerV2(grpclog.NewLoggerV2(ioutil.Discard, os.Stderr, os.Stderr))
}
@ -157,13 +171,15 @@ func (cfg *Config) setupLogging() error {
if !isJournal {
copied := logutil.AddOutputPaths(logutil.DefaultZapLoggerConfig, outputPaths, errOutputPaths)
if cfg.Debug {
copied.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
copied.Level = zap.NewAtomicLevelAt(logutil.ConvertToZapLevel(cfg.LogLevel))
if cfg.Debug || cfg.LogLevel == "debug" {
// enable tracing even when "--debug --log-level info"
// in order to keep backward compatibility with <= v3.3
// TODO: remove "Debug" check in v3.5
grpc.EnableTracing = true
}
if cfg.ZapLoggerBuilder == nil {
cfg.ZapLoggerBuilder = func(c *Config) error {
if cfg.zapLoggerBuilder == nil {
cfg.zapLoggerBuilder = func(c *Config) error {
var err error
c.logger, err = copied.Build()
if err != nil {
@ -201,9 +217,11 @@ func (cfg *Config) setupLogging() error {
return lerr
}
lvl := zap.NewAtomicLevelAt(zap.InfoLevel)
if cfg.Debug {
lvl = zap.NewAtomicLevelAt(zap.DebugLevel)
lvl := zap.NewAtomicLevelAt(logutil.ConvertToZapLevel(cfg.LogLevel))
if cfg.Debug || cfg.LogLevel == "debug" {
// enable tracing even when "--debug --log-level info"
// in order to keep backward compatibility with <= v3.3
// TODO: remove "Debug" check in v3.5
grpc.EnableTracing = true
}
@ -214,8 +232,8 @@ func (cfg *Config) setupLogging() error {
syncer,
lvl,
)
if cfg.ZapLoggerBuilder == nil {
cfg.ZapLoggerBuilder = func(c *Config) error {
if cfg.zapLoggerBuilder == nil {
cfg.zapLoggerBuilder = func(c *Config) error {
c.logger = zap.New(cr, zap.AddCaller(), zap.ErrorOutput(syncer))
c.loggerMu.Lock()
defer c.loggerMu.Unlock()
@ -231,7 +249,7 @@ func (cfg *Config) setupLogging() error {
}
}
err := cfg.ZapLoggerBuilder(cfg)
err := cfg.zapLoggerBuilder(cfg)
if err != nil {
return err
}

View File

@ -28,6 +28,7 @@ import (
"go.etcd.io/etcd/embed"
"go.etcd.io/etcd/pkg/flags"
"go.etcd.io/etcd/pkg/logutil"
"go.etcd.io/etcd/pkg/types"
"go.etcd.io/etcd/version"
@ -221,11 +222,12 @@ func newConfig() *config {
fs.Var(flags.NewUniqueStringsValue("*"), "host-whitelist", "Comma-separated acceptable hostnames from HTTP client requests, if server is not secure (empty means allow all).")
// logging
fs.StringVar(&cfg.ec.Logger, "logger", "capnslog", "Specify 'zap' for structured logging or 'capnslog'.")
fs.Var(flags.NewUniqueStringsValue(embed.DefaultLogOutput), "log-output", "DEPRECATED: use '--log-outputs'.")
fs.StringVar(&cfg.ec.Logger, "logger", "capnslog", "Specify 'zap' for structured logging or 'capnslog'. WARN: 'capnslog' is being deprecated in v3.5.")
fs.Var(flags.NewUniqueStringsValue(embed.DefaultLogOutput), "log-output", "[TO BE DEPRECATED IN v3.5] use '--log-outputs'.")
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.BoolVar(&cfg.ec.Debug, "debug", false, "Enable debug-level logging for etcd.")
fs.StringVar(&cfg.ec.LogPkgLevels, "log-package-levels", "", "(To be deprecated) Specify a particular log level for each etcd package (eg: 'etcdmain=CRITICAL,etcdserver=DEBUG').")
fs.BoolVar(&cfg.ec.Debug, "debug", false, "[TO BE DEPRECATED IN v3.5] Enable debug-level logging for etcd. Use '--log-level=debug' instead.")
fs.StringVar(&cfg.ec.LogLevel, "log-level", logutil.DefaultLogLevel, "Configures log level. Only supports debug, info, warn, error, panic, or fatal. Default 'info'.")
fs.StringVar(&cfg.ec.LogPkgLevels, "log-package-levels", "", "[TO BE DEPRECATED IN v3.5] Specify a particular log level for each etcd package (eg: 'etcdmain=CRITICAL,etcdserver=DEBUG').")
// version
fs.BoolVar(&cfg.printVersion, "version", false, "Print the version and exit.")

View File

@ -173,15 +173,11 @@ Profiling and Monitoring:
Logging:
--logger 'capnslog'
Specify 'zap' for structured logging or 'capnslog'.
Specify 'zap' for structured logging or 'capnslog'. [WARN] 'capnslog' will be deprecated in v3.5.
--log-outputs 'default'
Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd, or list of comma separated output targets.
--debug 'false'
Enable debug-level logging for etcd.
Logging (to be deprecated in v3.5):
--log-package-levels ''
Specify a particular log level for each etcd package (eg: 'etcdmain=CRITICAL,etcdserver=DEBUG').
--log-level 'info'
Configures log level. Only supports debug, info, warn, error, panic, or fatal.
v2 Proxy (to be deprecated in v4):
--proxy 'off'
@ -214,5 +210,12 @@ Unsafe feature:
Force to create a new one-member cluster.
CAUTIOUS with unsafe flag! It may break the guarantees given by the consensus protocol!
TO BE DEPRECATED:
--debug 'false'
Enable debug-level logging for etcd. [WARN] Will be deprecated in v3.5. Use '--log-level=debug' instead.
--log-package-levels ''
Specify a particular log level for each etcd package (eg: 'etcdmain=CRITICAL,etcdserver=DEBUG').
`
)

View File

@ -58,13 +58,6 @@ var (
)
func init() {
lcfg := logutil.DefaultZapLoggerConfig
lg, err := logutil.NewRaftLogger(&lcfg)
if err != nil {
log.Fatalf("cannot create raft logger %v", err)
}
raft.SetLogger(lg)
expvar.Publish("raft.status", expvar.Func(func() interface{} {
raftStatusMu.Lock()
defer raftStatusMu.Unlock()
@ -124,6 +117,18 @@ type raftNodeConfig struct {
}
func newRaftNode(cfg raftNodeConfig) *raftNode {
var lg raft.Logger
if cfg.lg != nil {
lg = logutil.NewRaftLoggerZap(cfg.lg)
} else {
lcfg := logutil.DefaultZapLoggerConfig
var err error
lg, err = logutil.NewRaftLogger(&lcfg)
if err != nil {
log.Fatalf("cannot create raft logger %v", err)
}
}
raft.SetLogger(lg)
r := &raftNode{
lg: cfg.lg,
tickMu: new(sync.Mutex),

70
pkg/logutil/log_level.go Normal file
View File

@ -0,0 +1,70 @@
// Copyright 2019 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package logutil
import (
"fmt"
"github.com/coreos/pkg/capnslog"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var DefaultLogLevel = "info"
// ConvertToZapLevel converts log level string to zapcore.Level.
func ConvertToZapLevel(lvl string) zapcore.Level {
switch lvl {
case "debug":
return zap.DebugLevel
case "info":
return zap.InfoLevel
case "warn":
return zap.WarnLevel
case "error":
return zap.ErrorLevel
case "dpanic":
return zap.DPanicLevel
case "panic":
return zap.PanicLevel
case "fatal":
return zap.FatalLevel
default:
panic(fmt.Sprintf("unknown level %q", lvl))
}
}
// ConvertToCapnslogLogLevel convert log level string to capnslog.LogLevel.
// TODO: deprecate this in 3.5
func ConvertToCapnslogLogLevel(lvl string) capnslog.LogLevel {
switch lvl {
case "debug":
return capnslog.DEBUG
case "info":
return capnslog.INFO
case "warn":
return capnslog.WARNING
case "error":
return capnslog.ERROR
case "dpanic":
return capnslog.CRITICAL
case "panic":
return capnslog.CRITICAL
case "fatal":
return capnslog.CRITICAL
default:
panic(fmt.Sprintf("unknown level %q", lvl))
}
}

View File

@ -23,7 +23,7 @@ import (
// DefaultZapLoggerConfig defines default zap logger configuration.
var DefaultZapLoggerConfig = zap.Config{
Level: zap.NewAtomicLevelAt(zap.InfoLevel),
Level: zap.NewAtomicLevelAt(ConvertToZapLevel(DefaultLogLevel)),
Development: false,
Sampling: &zap.SamplingConfig{

View File

@ -23,7 +23,7 @@ import (
"go.uber.org/zap/zapcore"
)
// NewRaftLogger converts "*zap.Logger" to "raft.Logger".
// NewRaftLogger builds "raft.Logger" from "*zap.Config".
func NewRaftLogger(lcfg *zap.Config) (raft.Logger, error) {
if lcfg == nil {
return nil, errors.New("nil zap.Config")
@ -35,6 +35,11 @@ func NewRaftLogger(lcfg *zap.Config) (raft.Logger, error) {
return &zapRaftLogger{lg: lg, sugar: lg.Sugar()}, nil
}
// NewRaftLoggerZap converts "*zap.Logger" to "raft.Logger".
func NewRaftLoggerZap(lg *zap.Logger) raft.Logger {
return &zapRaftLogger{lg: lg, sugar: lg.Sugar()}
}
// NewRaftLoggerFromZapCore creates "raft.Logger" from "zap.Core"
// and "zapcore.WriteSyncer".
func NewRaftLoggerFromZapCore(cr zapcore.Core, syncer zapcore.WriteSyncer) raft.Logger {

View File

@ -19,6 +19,7 @@ import (
"io/ioutil"
"log"
"os"
"sync"
)
type Logger interface {
@ -41,11 +42,16 @@ type Logger interface {
Panicf(format string, v ...interface{})
}
func SetLogger(l Logger) { raftLogger = l }
func SetLogger(l Logger) {
raftLoggerMu.Lock()
raftLogger = l
raftLoggerMu.Unlock()
}
var (
defaultLogger = &DefaultLogger{Logger: log.New(os.Stderr, "raft", log.LstdFlags)}
discardLogger = &DefaultLogger{Logger: log.New(ioutil.Discard, "", 0)}
raftLoggerMu sync.Mutex
raftLogger = Logger(defaultLogger)
)