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