github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/cmd/br/cmd.go (about)

     1  // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0.
     2  
     3  package main
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"sync"
    11  	"sync/atomic"
    12  	"time"
    13  
    14  	"github.com/pingcap/errors"
    15  	"github.com/pingcap/log"
    16  	tidbutils "github.com/pingcap/tidb-tools/pkg/utils"
    17  	"github.com/pingcap/tidb/util/logutil"
    18  	"github.com/spf13/cobra"
    19  
    20  	"github.com/pingcap/br/pkg/gluetidb"
    21  	"github.com/pingcap/br/pkg/redact"
    22  	"github.com/pingcap/br/pkg/summary"
    23  	"github.com/pingcap/br/pkg/task"
    24  	"github.com/pingcap/br/pkg/utils"
    25  	"github.com/pingcap/br/pkg/version/build"
    26  )
    27  
    28  var (
    29  	initOnce        = sync.Once{}
    30  	defaultContext  context.Context
    31  	hasLogFile      uint64
    32  	tidbGlue        = gluetidb.New()
    33  	envLogToTermKey = "BR_LOG_TO_TERM"
    34  
    35  	filterOutSysAndMemTables = []string{
    36  		"*.*",
    37  		fmt.Sprintf("!%s.*", utils.TemporaryDBName("*")),
    38  		"!mysql.*",
    39  		"!sys.*",
    40  		"!INFORMATION_SCHEMA.*",
    41  		"!PERFORMANCE_SCHEMA.*",
    42  		"!METRICS_SCHEMA.*",
    43  		"!INSPECTION_SCHEMA.*",
    44  	}
    45  	acceptAllTables = []string{
    46  		"*.*",
    47  	}
    48  )
    49  
    50  const (
    51  	// FlagLogLevel is the name of log-level flag.
    52  	FlagLogLevel = "log-level"
    53  	// FlagLogFile is the name of log-file flag.
    54  	FlagLogFile = "log-file"
    55  	// FlagLogFormat is the name of log-format flag.
    56  	FlagLogFormat = "log-format"
    57  	// FlagStatusAddr is the name of status-addr flag.
    58  	FlagStatusAddr = "status-addr"
    59  	// FlagSlowLogFile is the name of slow-log-file flag.
    60  	FlagSlowLogFile = "slow-log-file"
    61  	// FlagRedactLog is whether to redact sensitive information in log, already deprecated by FlagRedactInfoLog
    62  	FlagRedactLog = "redact-log"
    63  	// FlagRedactInfoLog is whether to redact sensitive information in log.
    64  	FlagRedactInfoLog = "redact-info-log"
    65  
    66  	flagVersion      = "version"
    67  	flagVersionShort = "V"
    68  )
    69  
    70  func timestampLogFileName() string {
    71  	return filepath.Join(os.TempDir(), time.Now().Format("br.log.2006-01-02T15.04.05Z0700"))
    72  }
    73  
    74  // AddFlags adds flags to the given cmd.
    75  func AddFlags(cmd *cobra.Command) {
    76  	cmd.Version = build.Info()
    77  	cmd.Flags().BoolP(flagVersion, flagVersionShort, false, "Display version information about BR")
    78  	cmd.SetVersionTemplate("{{printf \"%s\" .Version}}\n")
    79  
    80  	cmd.PersistentFlags().StringP(FlagLogLevel, "L", "info",
    81  		"Set the log level")
    82  	cmd.PersistentFlags().String(FlagLogFile, timestampLogFileName(),
    83  		"Set the log file path. If not set, logs will output to temp file")
    84  	cmd.PersistentFlags().String(FlagLogFormat, "text",
    85  		"Set the log format")
    86  	cmd.PersistentFlags().Bool(FlagRedactLog, false,
    87  		"Set whether to redact sensitive info in log, already deprecated by --redact-info-log")
    88  	cmd.PersistentFlags().Bool(FlagRedactInfoLog, false,
    89  		"Set whether to redact sensitive info in log")
    90  	cmd.PersistentFlags().String(FlagStatusAddr, "",
    91  		"Set the HTTP listening address for the status report service. Set to empty string to disable")
    92  	task.DefineCommonFlags(cmd.PersistentFlags())
    93  
    94  	cmd.PersistentFlags().StringP(FlagSlowLogFile, "", "",
    95  		"Set the slow log file path. If not set, discard slow logs")
    96  	_ = cmd.PersistentFlags().MarkHidden(FlagSlowLogFile)
    97  	_ = cmd.PersistentFlags().MarkHidden(FlagRedactLog)
    98  }
    99  
   100  // Init initializes BR cli.
   101  func Init(cmd *cobra.Command) (err error) {
   102  	initOnce.Do(func() {
   103  		slowLogFilename, e := cmd.Flags().GetString(FlagSlowLogFile)
   104  		if e != nil {
   105  			err = e
   106  			return
   107  		}
   108  		tidbLogCfg := logutil.LogConfig{}
   109  		if len(slowLogFilename) != 0 {
   110  			tidbLogCfg.SlowQueryFile = slowLogFilename
   111  			// Just for special grpc log file,
   112  			// otherwise the info will be print in stdout...
   113  			tidbLogCfg.File.Filename = timestampLogFileName()
   114  		} else {
   115  			// Disable annoying TiDB Log.
   116  			// TODO: some error logs outputs randomly, we need to fix them in TiDB.
   117  			tidbLogCfg.Level = "fatal"
   118  		}
   119  		e = logutil.InitLogger(&tidbLogCfg)
   120  		if e != nil {
   121  			err = e
   122  			return
   123  		}
   124  		// Initialize the logger.
   125  		conf := new(log.Config)
   126  		conf.Level, err = cmd.Flags().GetString(FlagLogLevel)
   127  		if err != nil {
   128  			return
   129  		}
   130  		conf.File.Filename, err = cmd.Flags().GetString(FlagLogFile)
   131  		if err != nil {
   132  			return
   133  		}
   134  		conf.Format, err = cmd.Flags().GetString(FlagLogFormat)
   135  		if err != nil {
   136  			return
   137  		}
   138  		_, outputLogToTerm := os.LookupEnv(envLogToTermKey)
   139  		if outputLogToTerm {
   140  			// Log to term if env `BR_LOG_TO_TERM` is set.
   141  			conf.File.Filename = ""
   142  		}
   143  		if len(conf.File.Filename) != 0 {
   144  			atomic.StoreUint64(&hasLogFile, 1)
   145  			summary.InitCollector(true)
   146  			// cmd.PrintErr prints to stderr, but PrintErrf prints to stdout.
   147  			cmd.PrintErr(fmt.Sprintf("Detail BR log in %s \n", conf.File.Filename))
   148  		}
   149  		lg, p, e := log.InitLogger(conf)
   150  		if e != nil {
   151  			err = e
   152  			return
   153  		}
   154  		log.ReplaceGlobals(lg, p)
   155  
   156  		redactLog, e := cmd.Flags().GetBool(FlagRedactLog)
   157  		if e != nil {
   158  			err = e
   159  			return
   160  		}
   161  		redactInfoLog, e := cmd.Flags().GetBool(FlagRedactInfoLog)
   162  		if e != nil {
   163  			err = e
   164  			return
   165  		}
   166  		redact.InitRedact(redactLog || redactInfoLog)
   167  		err = startPProf(cmd)
   168  	})
   169  	return errors.Trace(err)
   170  }
   171  
   172  func startPProf(cmd *cobra.Command) error {
   173  	// Initialize the pprof server.
   174  	statusAddr, err := cmd.Flags().GetString(FlagStatusAddr)
   175  	if err != nil {
   176  		return errors.Trace(err)
   177  	}
   178  	ca, cert, key, err := task.ParseTLSTripleFromFlags(cmd.Flags())
   179  	if err != nil {
   180  		return errors.Trace(err)
   181  	}
   182  	// Host isn't used here.
   183  	tls, err := tidbutils.NewTLS(ca, cert, key, "localhost", nil)
   184  	if err != nil {
   185  		return errors.Trace(err)
   186  	}
   187  
   188  	if statusAddr != "" {
   189  		return utils.StartPProfListener(statusAddr, tls)
   190  	}
   191  	utils.StartDynamicPProfListener(tls)
   192  	return nil
   193  }
   194  
   195  // HasLogFile returns whether we set a log file.
   196  func HasLogFile() bool {
   197  	return atomic.LoadUint64(&hasLogFile) != uint64(0)
   198  }
   199  
   200  // SetDefaultContext sets the default context for command line usage.
   201  func SetDefaultContext(ctx context.Context) {
   202  	defaultContext = ctx
   203  }
   204  
   205  // GetDefaultContext returns the default context for command line usage.
   206  func GetDefaultContext() context.Context {
   207  	return defaultContext
   208  }