github.com/516108736/tendermint@v0.36.0/cmd/tendermint/commands/debug/dump.go (about)

     1  package debug
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"time"
    10  
    11  	"github.com/spf13/cobra"
    12  	"github.com/spf13/viper"
    13  
    14  	cfg "github.com/tendermint/tendermint/config"
    15  	"github.com/tendermint/tendermint/libs/cli"
    16  	rpchttp "github.com/tendermint/tendermint/rpc/client/http"
    17  )
    18  
    19  var dumpCmd = &cobra.Command{
    20  	Use:   "dump [output-directory]",
    21  	Short: "Continuously poll a Tendermint process and dump debugging data into a single location",
    22  	Long: `Continuously poll a Tendermint process and dump debugging data into a single
    23  location at a specified frequency. At each frequency interval, an archived and compressed
    24  file will contain node debugging information including the goroutine and heap profiles
    25  if enabled.`,
    26  	Args: cobra.ExactArgs(1),
    27  	RunE: dumpCmdHandler,
    28  }
    29  
    30  func init() {
    31  	dumpCmd.Flags().UintVar(
    32  		&frequency,
    33  		flagFrequency,
    34  		30,
    35  		"the frequency (seconds) in which to poll, aggregate and dump Tendermint debug data",
    36  	)
    37  
    38  	dumpCmd.Flags().StringVar(
    39  		&profAddr,
    40  		flagProfAddr,
    41  		"",
    42  		"the profiling server address (<host>:<port>)",
    43  	)
    44  }
    45  
    46  func dumpCmdHandler(_ *cobra.Command, args []string) error {
    47  	outDir := args[0]
    48  	if outDir == "" {
    49  		return errors.New("invalid output directory")
    50  	}
    51  
    52  	if frequency == 0 {
    53  		return errors.New("frequency must be positive")
    54  	}
    55  
    56  	if _, err := os.Stat(outDir); os.IsNotExist(err) {
    57  		if err := os.Mkdir(outDir, os.ModePerm); err != nil {
    58  			return fmt.Errorf("failed to create output directory: %w", err)
    59  		}
    60  	}
    61  
    62  	rpc, err := rpchttp.New(nodeRPCAddr, "/websocket")
    63  	if err != nil {
    64  		return fmt.Errorf("failed to create new http client: %w", err)
    65  	}
    66  
    67  	home := viper.GetString(cli.HomeFlag)
    68  	conf := cfg.DefaultConfig()
    69  	conf = conf.SetRoot(home)
    70  	cfg.EnsureRoot(conf.RootDir)
    71  
    72  	dumpDebugData(outDir, conf, rpc)
    73  
    74  	ticker := time.NewTicker(time.Duration(frequency) * time.Second)
    75  	for range ticker.C {
    76  		dumpDebugData(outDir, conf, rpc)
    77  	}
    78  
    79  	return nil
    80  }
    81  
    82  func dumpDebugData(outDir string, conf *cfg.Config, rpc *rpchttp.HTTP) {
    83  	start := time.Now().UTC()
    84  
    85  	tmpDir, err := ioutil.TempDir(outDir, "tendermint_debug_tmp")
    86  	if err != nil {
    87  		logger.Error("failed to create temporary directory", "dir", tmpDir, "error", err)
    88  		return
    89  	}
    90  	defer os.RemoveAll(tmpDir)
    91  
    92  	logger.Info("getting node status...")
    93  	if err := dumpStatus(rpc, tmpDir, "status.json"); err != nil {
    94  		logger.Error("failed to dump node status", "error", err)
    95  		return
    96  	}
    97  
    98  	logger.Info("getting node network info...")
    99  	if err := dumpNetInfo(rpc, tmpDir, "net_info.json"); err != nil {
   100  		logger.Error("failed to dump node network info", "error", err)
   101  		return
   102  	}
   103  
   104  	logger.Info("getting node consensus state...")
   105  	if err := dumpConsensusState(rpc, tmpDir, "consensus_state.json"); err != nil {
   106  		logger.Error("failed to dump node consensus state", "error", err)
   107  		return
   108  	}
   109  
   110  	logger.Info("copying node WAL...")
   111  	if err := copyWAL(conf, tmpDir); err != nil {
   112  		logger.Error("failed to copy node WAL", "error", err)
   113  		return
   114  	}
   115  
   116  	if profAddr != "" {
   117  		logger.Info("getting node goroutine profile...")
   118  		if err := dumpProfile(tmpDir, profAddr, "goroutine", 2); err != nil {
   119  			logger.Error("failed to dump goroutine profile", "error", err)
   120  			return
   121  		}
   122  
   123  		logger.Info("getting node heap profile...")
   124  		if err := dumpProfile(tmpDir, profAddr, "heap", 2); err != nil {
   125  			logger.Error("failed to dump heap profile", "error", err)
   126  			return
   127  		}
   128  	}
   129  
   130  	outFile := filepath.Join(outDir, fmt.Sprintf("%s.zip", start.Format(time.RFC3339)))
   131  	if err := zipDir(tmpDir, outFile); err != nil {
   132  		logger.Error("failed to create and compress archive", "file", outFile, "error", err)
   133  	}
   134  }