diff --git a/embed/config.go b/embed/config.go index 2106db1e8ae..d223b6696e2 100644 --- a/embed/config.go +++ b/embed/config.go @@ -15,11 +15,13 @@ package embed import ( + "crypto/tls" "fmt" "io/ioutil" "net" "net/http" "net/url" + "os" "path/filepath" "strings" "time" @@ -31,8 +33,10 @@ import ( "github.com/coreos/etcd/pkg/transport" "github.com/coreos/etcd/pkg/types" + "github.com/coreos/pkg/capnslog" "github.com/ghodss/yaml" "google.golang.org/grpc" + "google.golang.org/grpc/grpclog" ) const ( @@ -136,6 +140,7 @@ type Config struct { Debug bool `json:"debug"` LogPkgLevels string `json:"log-package-levels"` + LogOutput string `json:"log-output"` EnablePprof bool `json:"enable-pprof"` Metrics string `json:"metrics"` ListenMetricsUrls []url.URL @@ -228,6 +233,45 @@ func NewConfig() *Config { return cfg } +// SetupLogging initializes etcd logging. +// Must be called after flag parsing. +func (cfg *Config) SetupLogging() { + cfg.ClientTLSInfo.HandshakeFailure = func(conn *tls.Conn, err error) { + plog.Infof("rejected connection from %q (%v)", conn.RemoteAddr().String(), err) + } + cfg.PeerTLSInfo.HandshakeFailure = cfg.ClientTLSInfo.HandshakeFailure + + capnslog.SetGlobalLogLevel(capnslog.INFO) + if cfg.Debug { + capnslog.SetGlobalLogLevel(capnslog.DEBUG) + grpc.EnableTracing = true + } else { + grpclog.SetLoggerV2(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, ioutil.Discard)) + } + if cfg.LogPkgLevels != "" { + repoLog := capnslog.MustRepoLogger("github.com/coreos/etcd") + settings, err := repoLog.ParseLogLevelConfig(cfg.LogPkgLevels) + if err != nil { + plog.Warningf("couldn't parse log level string: %s, continuing with default levels", err.Error()) + return + } + repoLog.SetLogLevel(settings) + } + + // capnslog initially SetFormatter(NewDefaultFormatter(os.Stderr)) + // where NewDefaultFormatter returns NewJournaldFormatter when syscall.Getppid() == 1 + // specify 'stdout' or 'stderr' to skip journald logging even when running under systemd + switch cfg.LogOutput { + case "stdout": + capnslog.SetFormatter(capnslog.NewPrettyFormatter(os.Stdout, cfg.Debug)) + case "stderr": + capnslog.SetFormatter(capnslog.NewPrettyFormatter(os.Stderr, cfg.Debug)) + case "default": + default: + plog.Panicf(`unknown log-output %q (only supports "default", "stdout", "stderr")`, cfg.LogOutput) + } +} + func ConfigFromFile(path string) (*Config, error) { cfg := &configYAML{Config: *NewConfig()} if err := cfg.configFromFile(path); err != nil { diff --git a/etcd.conf.yml.sample b/etcd.conf.yml.sample index 7759e5432b6..0178ed691b1 100644 --- a/etcd.conf.yml.sample +++ b/etcd.conf.yml.sample @@ -137,5 +137,8 @@ debug: false # Specify a particular log level for each etcd package (eg: 'etcdmain=CRITICAL,etcdserver=DEBUG'. log-package-levels: +# Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd. +log-output: default + # Force to create a new one member cluster. force-new-cluster: false diff --git a/etcdmain/config.go b/etcdmain/config.go index 17461dacf8f..a186a35103b 100644 --- a/etcdmain/config.go +++ b/etcdmain/config.go @@ -29,6 +29,7 @@ import ( "github.com/coreos/etcd/pkg/flags" "github.com/coreos/etcd/pkg/types" "github.com/coreos/etcd/version" + "github.com/ghodss/yaml" ) @@ -80,7 +81,6 @@ type config struct { configFile string printVersion bool ignored []string - logOutput string } // configFlags has the set of flags used for command line parsing a Config @@ -192,7 +192,7 @@ func newConfig() *config { // logging fs.BoolVar(&cfg.Debug, "debug", false, "Enable debug-level logging for etcd.") fs.StringVar(&cfg.LogPkgLevels, "log-package-levels", "", "Specify a particular log level for each etcd package (eg: 'etcdmain=CRITICAL,etcdserver=DEBUG').") - fs.StringVar(&cfg.logOutput, "log-output", "default", "Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd.") + fs.StringVar(&cfg.LogOutput, "log-output", "default", "Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd.") // unsafe fs.BoolVar(&cfg.ForceNewCluster, "force-new-cluster", false, "Force to create a new one member cluster.") diff --git a/etcdmain/etcd.go b/etcdmain/etcd.go index faff8378efc..47a8e563b8c 100644 --- a/etcdmain/etcd.go +++ b/etcdmain/etcd.go @@ -15,7 +15,6 @@ package etcdmain import ( - "crypto/tls" "encoding/json" "fmt" "io/ioutil" @@ -39,6 +38,7 @@ import ( "github.com/coreos/etcd/pkg/types" "github.com/coreos/etcd/proxy/httpproxy" "github.com/coreos/etcd/version" + "github.com/coreos/pkg/capnslog" "github.com/grpc-ecosystem/go-grpc-prometheus" "google.golang.org/grpc" @@ -69,7 +69,7 @@ func startEtcdOrProxyV2() { } os.Exit(1) } - setupLogging(cfg) + cfg.Config.SetupLogging() var stopped <-chan struct{} var errc <-chan error @@ -387,41 +387,6 @@ func identifyDataDirOrDie(dir string) dirType { return dirEmpty } -func setupLogging(cfg *config) { - cfg.ClientTLSInfo.HandshakeFailure = func(conn *tls.Conn, err error) { - plog.Infof("rejected connection from %q (%v)", conn.RemoteAddr().String(), err) - } - cfg.PeerTLSInfo.HandshakeFailure = cfg.ClientTLSInfo.HandshakeFailure - - capnslog.SetGlobalLogLevel(capnslog.INFO) - if cfg.Debug { - capnslog.SetGlobalLogLevel(capnslog.DEBUG) - grpc.EnableTracing = true - } - if cfg.LogPkgLevels != "" { - repoLog := capnslog.MustRepoLogger("github.com/coreos/etcd") - settings, err := repoLog.ParseLogLevelConfig(cfg.LogPkgLevels) - if err != nil { - plog.Warningf("couldn't parse log level string: %s, continuing with default levels", err.Error()) - return - } - repoLog.SetLogLevel(settings) - } - - // capnslog initially SetFormatter(NewDefaultFormatter(os.Stderr)) - // where NewDefaultFormatter returns NewJournaldFormatter when syscall.Getppid() == 1 - // specify 'stdout' or 'stderr' to skip journald logging even when running under systemd - switch cfg.logOutput { - case "stdout": - capnslog.SetFormatter(capnslog.NewPrettyFormatter(os.Stdout, cfg.Debug)) - case "stderr": - capnslog.SetFormatter(capnslog.NewPrettyFormatter(os.Stderr, cfg.Debug)) - case "default": - default: - plog.Panicf(`unknown log-output %q (only supports "default", "stdout", "stderr")`, cfg.logOutput) - } -} - func checkSupportArch() { // TODO qualify arm64 if runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64le" {