diff --git a/cmd/pd-server/main.go b/cmd/pd-server/main.go index 21e6d5ca0e0..ea5c26b00fe 100644 --- a/cmd/pd-server/main.go +++ b/cmd/pd-server/main.go @@ -24,10 +24,11 @@ import ( grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/pingcap/errors" "github.com/pingcap/log" + "github.com/spf13/cobra" "github.com/tikv/pd/pkg/autoscaling" - bs "github.com/tikv/pd/pkg/basicserver" "github.com/tikv/pd/pkg/dashboard" "github.com/tikv/pd/pkg/errs" + tso "github.com/tikv/pd/pkg/mcs/tso/server" "github.com/tikv/pd/pkg/swaggerserver" "github.com/tikv/pd/pkg/utils/logutil" "github.com/tikv/pd/pkg/utils/metricutil" @@ -41,43 +42,83 @@ import ( ) func main() { - ctx, cancel, svr := createServerWrapper(os.Args[1:]) - - sc := make(chan os.Signal, 1) - signal.Notify(sc, - syscall.SIGHUP, - syscall.SIGINT, - syscall.SIGTERM, - syscall.SIGQUIT) - - var sig os.Signal - go func() { - sig = <-sc - cancel() - }() + rootCmd := &cobra.Command{ + Use: "pd-server", + Short: "Placement Driver server", + Run: createServerWrapper, + } - if err := svr.Run(); err != nil { - log.Fatal("run server failed", errs.ZapError(err)) + rootCmd.Flags().BoolP("version", "V", false, "print version information and exit") + rootCmd.Flags().StringP("config", "", "", "config file") + rootCmd.Flags().BoolP("config-check", "", false, "check config file validity and exit") + rootCmd.Flags().StringP("name", "", "", "human-readable name for this pd member") + rootCmd.Flags().StringP("data-dir", "", "", "path to the data directory (default 'default.${name}')") + rootCmd.Flags().StringP("client-urls", "", "http://127.0.0.1:2379", "url for client traffic") + rootCmd.Flags().StringP("advertise-client-urls", "", "", "advertise url for client traffic (default '${client-urls}')") + rootCmd.Flags().StringP("peer-urls", "", "http://127.0.0.1:2379", "url for peer traffic") + rootCmd.Flags().StringP("advertise-peer-urls", "", "", "advertise url for peer traffic (default '${peer-urls}')") + rootCmd.Flags().StringP("initial-cluster", "", "", "initial cluster configuration for bootstrapping, e,g. pd=http://127.0.0.1:2380") + rootCmd.Flags().StringP("join", "", "", "join to an existing cluster (usage: cluster's '${advertise-client-urls}'") + rootCmd.Flags().StringP("metrics-addr", "", "", "prometheus pushgateway address, leaves it empty will disable prometheus push") + rootCmd.Flags().StringP("log-level", "L", "info", "log level: debug, info, warn, error, fatal (default 'info')") + rootCmd.Flags().StringP("log-file", "", "", "log file path") + rootCmd.Flags().StringP("cacert", "", "", "path of file that contains list of trusted TLS CAs") + rootCmd.Flags().StringP("cert", "", "", "path of file that contains X509 certificate in PEM format") + rootCmd.Flags().StringP("key", "", "", "path of file that contains X509 key in PEM format") + rootCmd.Flags().BoolP("force-new-cluster", "", false, "force to create a new one-member cluster") + rootCmd.AddCommand(NewServiceCommand()) + + rootCmd.SetOutput(os.Stdout) + if err := rootCmd.Execute(); err != nil { + rootCmd.Println(err) + os.Exit(1) } +} - <-ctx.Done() - log.Info("Got signal to exit", zap.String("signal", sig.String())) +// NewServiceCommand returns the service command. +func NewServiceCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "service ", + Short: "Run a service", + } + cmd.AddCommand(NewTSOServiceCommand()) + return cmd +} - svr.Close() - switch sig { - case syscall.SIGTERM: - exit(0) - default: - exit(1) +// NewTSOServiceCommand returns the unsafe remove failed stores command. +func NewTSOServiceCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "tso", + Short: "Run the tso service", + Run: tso.CreateServerWrapper, } + cmd.Flags().BoolP("version", "V", false, "print version information and exit") + cmd.Flags().StringP("config", "", "", "config file") + cmd.Flags().StringP("backend-endpoints", "", "http://127.0.0.1:2379", "url for etcd client") + cmd.Flags().StringP("listen-addr", "", "", "listen address for tso service") + cmd.Flags().StringP("cacert", "", "", "path of file that contains list of trusted TLS CAs") + cmd.Flags().StringP("cert", "", "", "path of file that contains X509 certificate in PEM format") + cmd.Flags().StringP("key", "", "", "path of file that contains X509 key in PEM format") + return cmd } -func createServerWrapper(args []string) (context.Context, context.CancelFunc, bs.Server) { +func createServerWrapper(cmd *cobra.Command, args []string) { schedulers.Register() cfg := config.NewConfig() - err := cfg.Parse(args) + flagSet := cmd.Flags() + flagSet.Parse(args) + err := cfg.Parse(flagSet) + if err != nil { + cmd.Println(err) + return + } - if cfg.Version { + printVersion, err := flagSet.GetBool("version") + if err != nil { + cmd.Println(err) + return + } + if printVersion { server.PrintPDInfo() exit(0) } @@ -92,15 +133,21 @@ func createServerWrapper(args []string) (context.Context, context.CancelFunc, bs log.Fatal("parse cmd flags error", errs.ZapError(err)) } - if cfg.ConfigCheck { + configCheck, err := flagSet.GetBool("config-check") + if err != nil { + cmd.Println(err) + return + } + + if configCheck { server.PrintConfigCheckMsg(cfg) exit(0) } // New zap logger - err = cfg.SetupLogger() + err = logutil.SetupLogger(cfg.Log, &cfg.Logger, &cfg.LogProps, cfg.Security.RedactInfoLog) if err == nil { - log.ReplaceGlobals(cfg.GetZapLogger(), cfg.GetZapLogProperties()) + log.ReplaceGlobals(cfg.Logger, cfg.LogProps) } else { log.Fatal("initialize logger error", errs.ZapError(err)) } @@ -132,7 +179,33 @@ func createServerWrapper(args []string) (context.Context, context.CancelFunc, bs log.Fatal("create server failed", errs.ZapError(err)) } - return ctx, cancel, svr + sc := make(chan os.Signal, 1) + signal.Notify(sc, + syscall.SIGHUP, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT) + + var sig os.Signal + go func() { + sig = <-sc + cancel() + }() + + if err := svr.Run(); err != nil { + log.Fatal("run server failed", errs.ZapError(err)) + } + + <-ctx.Done() + log.Info("Got signal to exit", zap.String("signal", sig.String())) + + svr.Close() + switch sig { + case syscall.SIGTERM: + exit(0) + default: + exit(1) + } } func exit(code int) { diff --git a/pkg/mcs/tso/server/server.go b/pkg/mcs/tso/server/server.go index 4d336a4ef5b..29a7642591b 100644 --- a/pkg/mcs/tso/server/server.go +++ b/pkg/mcs/tso/server/server.go @@ -19,16 +19,19 @@ import ( "flag" "net/http" "os" + "os/signal" + "syscall" grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/pingcap/errors" "github.com/pingcap/log" - bs "github.com/tikv/pd/pkg/basicserver" + "github.com/spf13/cobra" "github.com/tikv/pd/pkg/errs" "github.com/tikv/pd/pkg/tso" "github.com/tikv/pd/pkg/utils/logutil" "github.com/tikv/pd/pkg/utils/metricutil" "go.etcd.io/etcd/clientv3" + "go.uber.org/zap" ) // Server is the TSO server, and it implements bs.Server. @@ -69,12 +72,24 @@ func (s *Server) GetHTTPClient() *http.Client { } // CreateServerWrapper encapsulates the configuration/log/metrics initialization and create the server -func CreateServerWrapper(args []string) (context.Context, context.CancelFunc, bs.Server) { +func CreateServerWrapper(cmd *cobra.Command, args []string) { + cmd.Flags().Parse(args) cfg := tso.NewConfig() - err := cfg.Parse(os.Args[1:]) + flagSet := cmd.Flags() + err := cfg.Parse(flagSet) + if err != nil { + cmd.Println(err) + return + } - if cfg.Version { - printVersionInfo() + printVersion, err := flagSet.GetBool("version") + if err != nil { + cmd.Println(err) + return + } + if printVersion { + // TODO: support printing TSO server info + // server.PrintTSOInfo() exit(0) } @@ -88,12 +103,18 @@ func CreateServerWrapper(args []string) (context.Context, context.CancelFunc, bs log.Fatal("parse cmd flags error", errs.ZapError(err)) } - if cfg.ConfigCheck { - printConfigCheckMsg(cfg) - exit(0) + // New zap logger + err = logutil.SetupLogger(cfg.Log, &cfg.Logger, &cfg.LogProps, cfg.Security.RedactInfoLog) + if err == nil { + log.ReplaceGlobals(cfg.Logger, cfg.LogProps) + } else { + log.Fatal("initialize logger error", errs.ZapError(err)) } + // Flushing any buffered log entries + defer log.Sync() - // TODO: Initialize logger + // TODO: support printing TSO server info + // LogTSOInfo() // TODO: Make it configurable if it has big impact on performance. grpcprometheus.EnableHandlingTimeHistogram() @@ -101,16 +122,36 @@ func CreateServerWrapper(args []string) (context.Context, context.CancelFunc, bs metricutil.Push(&cfg.Metric) // TODO: Create the server + ctx, cancel := context.WithCancel(context.Background()) + svr := &Server{} + + sc := make(chan os.Signal, 1) + signal.Notify(sc, + syscall.SIGHUP, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT) + + var sig os.Signal + go func() { + sig = <-sc + cancel() + }() + + if err := svr.Run(); err != nil { + log.Fatal("run server failed", errs.ZapError(err)) + } - return nil, nil, nil -} - -// TODO: implement it -func printVersionInfo() { -} + <-ctx.Done() + log.Info("Got signal to exit", zap.String("signal", sig.String())) -// TODO: implement it -func printConfigCheckMsg(cfg *tso.Config) { + svr.Close() + switch sig { + case syscall.SIGTERM: + exit(0) + default: + exit(1) + } } func exit(code int) { diff --git a/pkg/tso/config.go b/pkg/tso/config.go index baf1fdc0062..9c20abbf307 100644 --- a/pkg/tso/config.go +++ b/pkg/tso/config.go @@ -15,12 +15,17 @@ package tso import ( - "flag" "time" + "github.com/BurntSushi/toml" "github.com/pingcap/errors" + "github.com/pingcap/log" + "github.com/spf13/pflag" + "github.com/tikv/pd/pkg/encryption" + "github.com/tikv/pd/pkg/utils/grpcutil" "github.com/tikv/pd/pkg/utils/metricutil" "github.com/tikv/pd/pkg/utils/typeutil" + "go.uber.org/zap" ) const ( @@ -30,12 +35,8 @@ const ( // Config is the configuration for the TSO. type Config struct { - flagSet *flag.FlagSet - - Version bool `json:"-"` - - ConfigCheck bool `json:"-"` - configFile string + BackendEndpoints string `toml:"backend-endpoints" json:"backend-endpoints"` + ListenAddr string `toml:"listen-addr" json:"listen-addr"` // EnableLocalTSO is used to enable the Local TSO Allocator feature, // which allows the PD server to generate Local TSO for certain DC-level transactions. @@ -57,28 +58,61 @@ type Config struct { MaxResetTSGap typeutil.Duration `toml:"max-gap-reset-ts" json:"max-gap-reset-ts"` Metric metricutil.MetricConfig `toml:"metric" json:"metric"` + + // Log related config. + Log log.Config `toml:"log" json:"log"` + + Logger *zap.Logger + LogProps *log.ZapProperties + + Security SecurityConfig `toml:"security" json:"security"` } // NewConfig creates a new config. func NewConfig() *Config { - cfg := &Config{} - cfg.flagSet = flag.NewFlagSet("pd", flag.ContinueOnError) - fs := cfg.flagSet - - fs.StringVar(&cfg.configFile, "config", "", "config file") - - return cfg + return &Config{} } // Parse parses flag definitions from the argument list. -func (c *Config) Parse(arguments []string) error { - // Parse first to get config file. - err := c.flagSet.Parse(arguments) - if err != nil { - return errors.WithStack(err) +func (c *Config) Parse(flagSet *pflag.FlagSet) error { + // Load config file if specified. + if configFile, _ := flagSet.GetString("config"); configFile != "" { + _, err := c.configFromFile(configFile) + if err != nil { + return err + } } - // TODO: Implement the main function body + // ignore the error check here + adjustCommandlineString(flagSet, &c.Log.Level, "log-level") + adjustCommandlineString(flagSet, &c.Log.File.Filename, "log-file") + adjustCommandlineString(flagSet, &c.Metric.PushAddress, "metrics-addr") + adjustCommandlineString(flagSet, &c.Security.CAPath, "cacert") + adjustCommandlineString(flagSet, &c.Security.CertPath, "cert") + adjustCommandlineString(flagSet, &c.Security.KeyPath, "key") + adjustCommandlineString(flagSet, &c.BackendEndpoints, "backend-endpoints") + adjustCommandlineString(flagSet, &c.ListenAddr, "listen-addr") + // TODO: Implement the main function body return nil } + +// configFromFile loads config from file. +func (c *Config) configFromFile(path string) (*toml.MetaData, error) { + meta, err := toml.DecodeFile(path, c) + return &meta, errors.WithStack(err) +} + +// SecurityConfig indicates the security configuration for pd server +type SecurityConfig struct { + grpcutil.TLSConfig + // RedactInfoLog indicates that whether enabling redact log + RedactInfoLog bool `toml:"redact-info-log" json:"redact-info-log"` + Encryption encryption.Config `toml:"encryption" json:"encryption"` +} + +func adjustCommandlineString(flagSet *pflag.FlagSet, v *string, name string) { + if value, _ := flagSet.GetString(name); value != "" { + *v = value + } +} diff --git a/pkg/utils/logutil/log.go b/pkg/utils/logutil/log.go index d98b9bc2e6c..a46f47da891 100644 --- a/pkg/utils/logutil/log.go +++ b/pkg/utils/logutil/log.go @@ -20,6 +20,7 @@ import ( "sync/atomic" "github.com/pingcap/log" + "github.com/tikv/pd/pkg/errs" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -65,6 +66,20 @@ func StringToZapLogLevel(level string) zapcore.Level { return zapcore.InfoLevel } +// SetupLogger setup the logger. +func SetupLogger(logConfig log.Config, logger **zap.Logger, logProps **log.ZapProperties, enabled ...bool) error { + lg, p, err := log.InitLogger(&logConfig, zap.AddStacktrace(zapcore.FatalLevel)) + if err != nil { + return errs.ErrInitLogger.Wrap(err).FastGenWithCause() + } + *logger = lg + *logProps = p + if len(enabled) > 0 { + SetRedactLog(enabled[0]) + } + return nil +} + // LogPanic logs the panic reason and stack, then exit the process. // Commonly used with a `defer`. func LogPanic() { diff --git a/server/api/server_test.go b/server/api/server_test.go index 437f8c4888f..ed045e7de5e 100644 --- a/server/api/server_test.go +++ b/server/api/server_test.go @@ -28,6 +28,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/tikv/pd/pkg/utils/apiutil" "github.com/tikv/pd/pkg/utils/assertutil" + "github.com/tikv/pd/pkg/utils/logutil" "github.com/tikv/pd/pkg/utils/testutil" "github.com/tikv/pd/server" "github.com/tikv/pd/server/config" @@ -84,10 +85,10 @@ func mustNewCluster(re *require.Assertions, num int, opts ...func(cfg *config.Co ch := make(chan *server.Server, num) for _, cfg := range cfgs { go func(cfg *config.Config) { - err := cfg.SetupLogger() + err := logutil.SetupLogger(cfg.Log, &cfg.Logger, &cfg.LogProps, cfg.Security.RedactInfoLog) re.NoError(err) zapLogOnce.Do(func() { - log.ReplaceGlobals(cfg.GetZapLogger(), cfg.GetZapLogProperties()) + log.ReplaceGlobals(cfg.Logger, cfg.LogProps) }) for _, opt := range opts { opt(cfg) diff --git a/server/config/config.go b/server/config/config.go index d5f39170932..ae1e27bfd22 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -17,7 +17,6 @@ package config import ( "crypto/tls" "encoding/json" - "flag" "fmt" "math" "net/url" @@ -27,12 +26,12 @@ import ( "time" "github.com/docker/go-units" + "github.com/spf13/pflag" "github.com/tikv/pd/pkg/core/storelimit" "github.com/tikv/pd/pkg/encryption" "github.com/tikv/pd/pkg/errs" "github.com/tikv/pd/pkg/utils/configutil" "github.com/tikv/pd/pkg/utils/grpcutil" - "github.com/tikv/pd/pkg/utils/logutil" "github.com/tikv/pd/pkg/utils/metricutil" "github.com/tikv/pd/pkg/utils/syncutil" "github.com/tikv/pd/pkg/utils/typeutil" @@ -46,18 +45,11 @@ import ( "go.etcd.io/etcd/embed" "go.etcd.io/etcd/pkg/transport" "go.uber.org/zap" - "go.uber.org/zap/zapcore" ) // Config is the pd server configuration. // NOTE: This type is exported by HTTP API. Please pay more attention when modifying it. type Config struct { - flagSet *flag.FlagSet - - Version bool `json:"-"` - - ConfigCheck bool `json:"-"` - ClientUrls string `toml:"client-urls" json:"client-urls"` PeerUrls string `toml:"peer-urls" json:"peer-urls"` AdvertiseClientUrls string `toml:"advertise-client-urls" json:"advertise-client-urls"` @@ -150,8 +142,6 @@ type Config struct { LabelProperty LabelPropertyConfig `toml:"label-property" json:"label-property"` - configFile string - // For all warnings during parsing. WarningMsgs []string @@ -160,8 +150,8 @@ type Config struct { HeartbeatStreamBindInterval typeutil.Duration LeaderPriorityCheckInterval typeutil.Duration - logger *zap.Logger - logProps *log.ZapProperties + Logger *zap.Logger `json:"-"` + LogProps *log.ZapProperties `json:"-"` Dashboard DashboardConfig `toml:"dashboard" json:"dashboard"` @@ -172,36 +162,7 @@ type Config struct { // NewConfig creates a new config. func NewConfig() *Config { - cfg := &Config{} - cfg.flagSet = flag.NewFlagSet("pd", flag.ContinueOnError) - fs := cfg.flagSet - - fs.BoolVar(&cfg.Version, "V", false, "print version information and exit") - fs.BoolVar(&cfg.Version, "version", false, "print version information and exit") - fs.StringVar(&cfg.configFile, "config", "", "config file") - fs.BoolVar(&cfg.ConfigCheck, "config-check", false, "check config file validity and exit") - - fs.StringVar(&cfg.Name, "name", "", "human-readable name for this pd member") - - fs.StringVar(&cfg.DataDir, "data-dir", "", "path to the data directory (default 'default.${name}')") - fs.StringVar(&cfg.ClientUrls, "client-urls", defaultClientUrls, "url for client traffic") - fs.StringVar(&cfg.AdvertiseClientUrls, "advertise-client-urls", "", "advertise url for client traffic (default '${client-urls}')") - fs.StringVar(&cfg.PeerUrls, "peer-urls", defaultPeerUrls, "url for peer traffic") - fs.StringVar(&cfg.AdvertisePeerUrls, "advertise-peer-urls", "", "advertise url for peer traffic (default '${peer-urls}')") - fs.StringVar(&cfg.InitialCluster, "initial-cluster", "", "initial cluster configuration for bootstrapping, e,g. pd=http://127.0.0.1:2380") - fs.StringVar(&cfg.Join, "join", "", "join to an existing cluster (usage: cluster's '${advertise-client-urls}'") - - fs.StringVar(&cfg.Metric.PushAddress, "metrics-addr", "", "prometheus pushgateway address, leaves it empty will disable prometheus push") - - fs.StringVar(&cfg.Log.Level, "L", "info", "log level: debug, info, warn, error, fatal (default 'info')") - fs.StringVar(&cfg.Log.File.Filename, "log-file", "", "log file path") - - fs.StringVar(&cfg.Security.CAPath, "cacert", "", "path of file that contains list of trusted TLS CAs") - fs.StringVar(&cfg.Security.CertPath, "cert", "", "path of file that contains X509 certificate in PEM format") - fs.StringVar(&cfg.Security.KeyPath, "key", "", "path of file that contains X509 key in PEM format") - fs.BoolVar(&cfg.ForceNewCluster, "force-new-cluster", false, "force to create a new one-member cluster") - - return cfg + return &Config{} } const ( @@ -391,54 +352,66 @@ func adjustPath(p *string) { } // Parse parses flag definitions from the argument list. -func (c *Config) Parse(arguments []string) error { - // Parse first to get config file. - err := c.flagSet.Parse(arguments) - if err != nil { - return errors.WithStack(err) - } - +func (c *Config) Parse(flagSet *pflag.FlagSet) error { // Load config file if specified. var meta *toml.MetaData - if c.configFile != "" { - meta, err = c.configFromFile(c.configFile) + if configFile, _ := flagSet.GetString("config"); configFile != "" { + meta, err := c.configFromFile(configFile) if err != nil { return err } // Backward compatibility for toml config if c.LogFileDeprecated != "" { - msg := fmt.Sprintf("log-file in %s is deprecated, use [log.file] instead", c.configFile) + msg := fmt.Sprintf("log-file in %s is deprecated, use [log.file] instead", configFile) c.WarningMsgs = append(c.WarningMsgs, msg) if c.Log.File.Filename == "" { c.Log.File.Filename = c.LogFileDeprecated } } if c.LogLevelDeprecated != "" { - msg := fmt.Sprintf("log-level in %s is deprecated, use [log] instead", c.configFile) + msg := fmt.Sprintf("log-level in %s is deprecated, use [log] instead", configFile) c.WarningMsgs = append(c.WarningMsgs, msg) if c.Log.Level == "" { c.Log.Level = c.LogLevelDeprecated } } if meta.IsDefined("schedule", "disable-raft-learner") { - msg := fmt.Sprintf("disable-raft-learner in %s is deprecated", c.configFile) + msg := fmt.Sprintf("disable-raft-learner in %s is deprecated", configFile) c.WarningMsgs = append(c.WarningMsgs, msg) } } - // Parse again to replace with command line options. - err = c.flagSet.Parse(arguments) - if err != nil { - return errors.WithStack(err) - } + // ignore the error check here + adjustCommandlineString(flagSet, &c.Log.Level, "log-level") + adjustCommandlineString(flagSet, &c.Log.File.Filename, "log-file") + adjustCommandlineString(flagSet, &c.Name, "name") + adjustCommandlineString(flagSet, &c.DataDir, "data-dir") + adjustCommandlineString(flagSet, &c.ClientUrls, "client-urls") + adjustCommandlineString(flagSet, &c.AdvertiseClientUrls, "advertise-client-urls") + adjustCommandlineString(flagSet, &c.PeerUrls, "peer-urls") + adjustCommandlineString(flagSet, &c.AdvertisePeerUrls, "advertise-peer-urls") + adjustCommandlineString(flagSet, &c.InitialCluster, "initial-cluster") + adjustCommandlineString(flagSet, &c.Join, "join") + adjustCommandlineString(flagSet, &c.Metric.PushAddress, "metrics-addr") + adjustCommandlineString(flagSet, &c.Security.CAPath, "cacert") + adjustCommandlineString(flagSet, &c.Security.CertPath, "cert") + adjustCommandlineString(flagSet, &c.Security.KeyPath, "key") + adjustCommandlineBool(flagSet, &c.ForceNewCluster, "force-new-cluster") + + return c.Adjust(meta, false) +} - if len(c.flagSet.Args()) != 0 { - return errors.Errorf("'%s' is an invalid flag", c.flagSet.Arg(0)) +func adjustCommandlineString(flagSet *pflag.FlagSet, v *string, name string) { + if value, _ := flagSet.GetString(name); value != "" { + *v = value } +} - err = c.Adjust(meta, false) - return err +func adjustCommandlineBool(flagSet *pflag.FlagSet, v *bool, name string) { + if value, _ := flagSet.GetBool(name); value { + *v = value + } } // Validate is used to validate if some configurations are right. @@ -1301,33 +1274,6 @@ func (c LabelPropertyConfig) Clone() LabelPropertyConfig { return m } -// SetupLogger setup the logger. -func (c *Config) SetupLogger() error { - lg, p, err := log.InitLogger(&c.Log, zap.AddStacktrace(zapcore.FatalLevel)) - if err != nil { - return errs.ErrInitLogger.Wrap(err).FastGenWithCause() - } - c.logger = lg - c.logProps = p - logutil.SetRedactLog(c.Security.RedactInfoLog) - return nil -} - -// GetZapLogger gets the created zap logger. -func (c *Config) GetZapLogger() *zap.Logger { - return c.logger -} - -// GetZapLogProperties gets properties of the zap logger. -func (c *Config) GetZapLogProperties() *log.ZapProperties { - return c.logProps -} - -// GetConfigFile gets the config file. -func (c *Config) GetConfigFile() string { - return c.configFile -} - // IsLocalTSOEnabled returns if the local TSO is enabled. func (c *Config) IsLocalTSOEnabled() bool { return c.EnableLocalTSO @@ -1382,7 +1328,7 @@ func (c *Config) GenEmbedEtcdConfig() (*embed.Config, error) { cfg.PeerTLSInfo.KeyFile = c.Security.KeyPath cfg.PeerTLSInfo.AllowedCN = allowedCN cfg.ForceNewCluster = c.ForceNewCluster - cfg.ZapLoggerBuilder = embed.NewZapCoreLoggerBuilder(c.logger, c.logger.Core(), c.logProps.Syncer) + cfg.ZapLoggerBuilder = embed.NewZapCoreLoggerBuilder(c.Logger, c.Logger.Core(), c.LogProps.Syncer) cfg.EnableGRPCGateway = c.EnableGRPCGateway cfg.EnableV2 = true cfg.Logger = "zap" diff --git a/server/config/config_test.go b/server/config/config_test.go index a767b71a443..ee6c9e22287 100644 --- a/server/config/config_test.go +++ b/server/config/config_test.go @@ -24,6 +24,7 @@ import ( "time" "github.com/BurntSushi/toml" + "github.com/spf13/pflag" "github.com/stretchr/testify/require" "github.com/tikv/pd/pkg/storage" "github.com/tikv/pd/pkg/utils/configutil" @@ -177,7 +178,13 @@ max-merge-region-size = 0 enable-one-way-merge = true leader-schedule-limit = 0 ` + + flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) + flagSet.StringP("log-level", "L", "info", "log level: debug, info, warn, error, fatal (default 'info')") + flagSet.Parse(nil) cfg := NewConfig() + err := cfg.Parse(flagSet) + re.NoError(err) meta, err := toml.Decode(cfgData, &cfg) re.NoError(err) err = cfg.Adjust(&meta, false) diff --git a/server/server.go b/server/server.go index 91e3e19ffda..3830fd574af 100644 --- a/server/server.go +++ b/server/server.go @@ -248,8 +248,8 @@ func CreateServer(ctx context.Context, cfg *config.Config, legacyServiceBuilders } s.etcdCfg = etcdCfg - s.lg = cfg.GetZapLogger() - s.logProps = cfg.GetZapLogProperties() + s.lg = cfg.Logger + s.logProps = cfg.LogProps return s, nil } diff --git a/server/testutil.go b/server/testutil.go index 3820962ece3..05d68dce8e6 100644 --- a/server/testutil.go +++ b/server/testutil.go @@ -27,6 +27,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tikv/pd/pkg/utils/apiutil" "github.com/tikv/pd/pkg/utils/assertutil" + "github.com/tikv/pd/pkg/utils/logutil" "github.com/tikv/pd/pkg/utils/tempurl" "github.com/tikv/pd/pkg/utils/testutil" "github.com/tikv/pd/pkg/utils/typeutil" @@ -86,10 +87,10 @@ func NewTestSingleConfig(c *assertutil.Checker) *config.Config { cfg.TickInterval = typeutil.NewDuration(100 * time.Millisecond) cfg.ElectionInterval = typeutil.NewDuration(3 * time.Second) cfg.LeaderPriorityCheckInterval = typeutil.NewDuration(100 * time.Millisecond) - err := cfg.SetupLogger() + err := logutil.SetupLogger(cfg.Log, &cfg.Logger, &cfg.LogProps, cfg.Security.RedactInfoLog) c.AssertNil(err) zapLogOnce.Do(func() { - log.ReplaceGlobals(cfg.GetZapLogger(), cfg.GetZapLogProperties()) + log.ReplaceGlobals(cfg.Logger, cfg.LogProps) }) c.AssertNil(cfg.Adjust(nil, false)) diff --git a/tests/cluster.go b/tests/cluster.go index e9fa55bcc24..ba1d619070e 100644 --- a/tests/cluster.go +++ b/tests/cluster.go @@ -34,6 +34,7 @@ import ( "github.com/tikv/pd/pkg/id" "github.com/tikv/pd/pkg/swaggerserver" "github.com/tikv/pd/pkg/tso" + "github.com/tikv/pd/pkg/utils/logutil" "github.com/tikv/pd/pkg/utils/testutil" "github.com/tikv/pd/server" "github.com/tikv/pd/server/api" @@ -73,12 +74,12 @@ var zapLogOnce sync.Once // NewTestServer creates a new TestServer. func NewTestServer(ctx context.Context, cfg *config.Config) (*TestServer, error) { - err := cfg.SetupLogger() + err := logutil.SetupLogger(cfg.Log, &cfg.Logger, &cfg.LogProps, cfg.Security.RedactInfoLog) if err != nil { return nil, err } zapLogOnce.Do(func() { - log.ReplaceGlobals(cfg.GetZapLogger(), cfg.GetZapLogProperties()) + log.ReplaceGlobals(cfg.Logger, cfg.LogProps) }) err = join.PrepareJoinCluster(cfg) if err != nil { diff --git a/tests/config.go b/tests/config.go index 0c23d198184..4f653a3dc3c 100644 --- a/tests/config.go +++ b/tests/config.go @@ -19,6 +19,7 @@ import ( "os" "strings" + "github.com/spf13/pflag" "github.com/tikv/pd/pkg/utils/tempurl" "github.com/tikv/pd/server/config" ) @@ -61,8 +62,31 @@ func (c *serverConfig) Generate(opts ...ConfigOption) (*config.Config, error) { arguments = append(arguments, "--initial-cluster="+c.ClusterConfig.GetServerAddrs()) } + flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) + flagSet.BoolP("version", "V", false, "print version information and exit") + flagSet.StringP("config", "", "", "config file") + flagSet.BoolP("config-check", "", false, "check config file validity and exit") + flagSet.StringP("name", "", "", "human-readable name for this pd member") + flagSet.StringP("data-dir", "", "", "path to the data directory (default 'default.${name}')") + flagSet.StringP("client-urls", "", "http://127.0.0.1:2379", "url for client traffic") + flagSet.StringP("advertise-client-urls", "", "", "advertise url for client traffic (default '${client-urls}')") + flagSet.StringP("peer-urls", "", "http://127.0.0.1:2379", "url for peer traffic") + flagSet.StringP("advertise-peer-urls", "", "", "advertise url for peer traffic (default '${peer-urls}')") + flagSet.StringP("initial-cluster", "", "", "initial cluster configuration for bootstrapping, e,g. pd=http://127.0.0.1:2380") + flagSet.StringP("join", "", "", "join to an existing cluster (usage: cluster's '${advertise-client-urls}'") + flagSet.StringP("metrics-addr", "", "", "prometheus pushgateway address, leaves it empty will disable prometheus push") + flagSet.StringP("log-level", "L", "info", "log level: debug, info, warn, error, fatal (default 'info')") + flagSet.StringP("log-file", "", "", "log file path") + flagSet.StringP("cacert", "", "", "path of file that contains list of trusted TLS CAs") + flagSet.StringP("cert", "", "", "path of file that contains X509 certificate in PEM format") + flagSet.StringP("key", "", "", "path of file that contains X509 key in PEM format") + flagSet.BoolP("force-new-cluster", "", false, "force to create a new one-member cluster") + err := flagSet.Parse(arguments) + if err != nil { + return nil, err + } cfg := config.NewConfig() - err := cfg.Parse(arguments) + err = cfg.Parse(flagSet) if err != nil { return nil, err } diff --git a/tools/pd-heartbeat-bench/config/config.go b/tools/pd-heartbeat-bench/config/config.go index 5d59bb52974..d85e68bfb60 100644 --- a/tools/pd-heartbeat-bench/config/config.go +++ b/tools/pd-heartbeat-bench/config/config.go @@ -6,7 +6,6 @@ import ( "github.com/pingcap/log" flag "github.com/spf13/pflag" "go.uber.org/zap" - "go.uber.org/zap/zapcore" ) const ( @@ -32,8 +31,8 @@ type Config struct { StatusAddr string Log log.Config `toml:"log" json:"log"` - logger *zap.Logger - logProps *log.ZapProperties + Logger *zap.Logger + LogProps *log.ZapProperties StoreCount int `toml:"store-count" json:"store-count"` RegionCount int `toml:"region-count" json:"region-count"` @@ -138,27 +137,6 @@ func (c *Config) configFromFile(path string) (*toml.MetaData, error) { return &meta, err } -// SetupLogger setup the logger. -func (c *Config) SetupLogger() error { - lg, p, err := log.InitLogger(&c.Log, zap.AddStacktrace(zapcore.FatalLevel)) - if err != nil { - return err - } - c.logger = lg - c.logProps = p - return nil -} - -// GetZapLogger gets the created zap logger. -func (c *Config) GetZapLogger() *zap.Logger { - return c.logger -} - -// GetZapLogProperties gets properties of the zap logger. -func (c *Config) GetZapLogProperties() *log.ZapProperties { - return c.logProps -} - func adjustFloat64(v *float64, defValue float64) { if *v == 0 { *v = defValue diff --git a/tools/pd-heartbeat-bench/main.go b/tools/pd-heartbeat-bench/main.go index 15d955c57ef..cec110cb635 100644 --- a/tools/pd-heartbeat-bench/main.go +++ b/tools/pd-heartbeat-bench/main.go @@ -408,9 +408,9 @@ func main() { } // New zap logger - err = cfg.SetupLogger() + err = logutil.SetupLogger(cfg.Log, &cfg.Logger, &cfg.LogProps) if err == nil { - log.ReplaceGlobals(cfg.GetZapLogger(), cfg.GetZapLogProperties()) + log.ReplaceGlobals(cfg.Logger, cfg.LogProps) } else { log.Fatal("initialize logger error", zap.Error(err)) } diff --git a/tools/pd-simulator/main.go b/tools/pd-simulator/main.go index c37f4502b99..8e646998714 100644 --- a/tools/pd-simulator/main.go +++ b/tools/pd-simulator/main.go @@ -28,6 +28,7 @@ import ( "github.com/pingcap/log" "github.com/prometheus/client_golang/prometheus/promhttp" flag "github.com/spf13/pflag" + "github.com/tikv/pd/pkg/utils/logutil" "github.com/tikv/pd/server" "github.com/tikv/pd/server/api" "github.com/tikv/pd/server/config" @@ -132,18 +133,13 @@ func runHTTPServer() { // NewSingleServer creates a pd server for simulator. func NewSingleServer(ctx context.Context, simConfig *simulator.SimConfig) (*server.Server, server.CleanupFunc) { - err := simConfig.ServerConfig.SetupLogger() + err := logutil.SetupLogger(simConfig.ServerConfig.Log, &simConfig.ServerConfig.Logger, &simConfig.ServerConfig.LogProps) if err == nil { - log.ReplaceGlobals(simConfig.ServerConfig.GetZapLogger(), simConfig.ServerConfig.GetZapLogProperties()) + log.ReplaceGlobals(simConfig.ServerConfig.Logger, simConfig.ServerConfig.LogProps) } else { log.Fatal("setup logger error", zap.Error(err)) } - simConfig.ServerConfig.SetupLogger() - if err != nil { - log.Fatal("initialize logger error", zap.Error(err)) - } - s, err := server.CreateServer(ctx, simConfig.ServerConfig, api.NewHandler) if err != nil { panic("create server failed")