Skip to content

Commit dcd0db3

Browse files
authored
Add a debug command (#58)
* Add a debug command * Exclude certain files by default in the debug output * Show port configs * Show RPC server status
1 parent 9f703c4 commit dcd0db3

File tree

4 files changed

+302
-33
lines changed

4 files changed

+302
-33
lines changed

cmd/debug/debug.go

+209
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
package debug
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
"path/filepath"
8+
"regexp"
9+
"sort"
10+
"strings"
11+
"text/tabwriter"
12+
13+
"github.com/chia-network/go-chia-libs/pkg/config"
14+
"github.com/chia-network/go-chia-libs/pkg/rpc"
15+
"github.com/chia-network/go-modules/pkg/slogs"
16+
"github.com/spf13/cobra"
17+
"github.com/spf13/viper"
18+
19+
"github.com/chia-network/chia-tools/cmd"
20+
"github.com/chia-network/chia-tools/cmd/network"
21+
)
22+
23+
// Define a fixed column width for size
24+
const sizeColumnWidth = 14
25+
26+
// FileInfo stores file path and size
27+
type FileInfo struct {
28+
Size int64
29+
Path string
30+
}
31+
32+
// Exclusions - List of patterns to exclude in the default mode
33+
var exclusions = []string{
34+
`\.DS_Store$`,
35+
`data_layer/db/server_files_location.*/.*delta.*`, // Don't show delta files by default
36+
`wallet/db/temp.*`,
37+
`run/.*`,
38+
}
39+
40+
// debugCmd represents the config command
41+
var debugCmd = &cobra.Command{
42+
Use: "debug",
43+
Short: "Outputs debugging information about Chia",
44+
Run: func(cmd *cobra.Command, args []string) {
45+
fmt.Println("# Version Information")
46+
fmt.Println(strings.Repeat("-", 60)) // Separator
47+
ShowVersionInfo()
48+
49+
fmt.Println("\n# Network Information")
50+
fmt.Println(strings.Repeat("-", 60)) // Separator
51+
network.ShowNetworkInfo()
52+
53+
fmt.Println("\n# Port Information")
54+
fmt.Println(strings.Repeat("-", 60)) // Separator
55+
debugPorts()
56+
57+
fmt.Println("\n# RPC Server Status")
58+
fmt.Println(strings.Repeat("-", 60)) // Separator
59+
debugRPC()
60+
61+
fmt.Println("\n# File Sizes")
62+
debugFileSizes()
63+
},
64+
}
65+
66+
func debugRPC() {
67+
slogs.Logr.Debug("initializing websocket client")
68+
websocketClient, err := rpc.NewClient(rpc.ConnectionModeWebsocket, rpc.WithAutoConfig(), rpc.WithSyncWebsocket())
69+
if err != nil {
70+
slogs.Logr.Fatal("error initializing websocket RPC client", "error", err)
71+
}
72+
slogs.Logr.Debug("initializing http client")
73+
rpcClient, err := rpc.NewClient(rpc.ConnectionModeHTTP, rpc.WithAutoConfig(), rpc.WithSyncWebsocket())
74+
if err != nil {
75+
slogs.Logr.Fatal("error initializing websocket RPC client", "error", err)
76+
}
77+
78+
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
79+
runningHelper(w, websocketClient.DaemonService, "Daemon")
80+
runningHelper(w, rpcClient.FullNodeService, "Full Node")
81+
runningHelper(w, rpcClient.WalletService, "Wallet")
82+
runningHelper(w, rpcClient.FarmerService, "Farmer")
83+
runningHelper(w, rpcClient.HarvesterService, "Harvester")
84+
runningHelper(w, rpcClient.CrawlerService, "Crawler")
85+
runningHelper(w, rpcClient.DataLayerService, "Data Layer")
86+
runningHelper(w, rpcClient.TimelordService, "Timelord")
87+
_ = w.Flush()
88+
}
89+
90+
func runningHelper(w io.Writer, service hasVersionInfo, label string) {
91+
running := "Running"
92+
_, _, err := service.GetVersion(&rpc.GetVersionOptions{})
93+
if err != nil {
94+
slogs.Logr.Debug("error getting RPC Status from daemon", "error", err)
95+
running = "Not Running"
96+
}
97+
_, _ = fmt.Fprintln(w, label, "\t", running)
98+
}
99+
100+
func debugPorts() {
101+
cfg, err := config.GetChiaConfig()
102+
if err != nil {
103+
fmt.Println("Could not load config")
104+
return
105+
}
106+
107+
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
108+
_, _ = fmt.Fprintln(w, "Full Node Port\t", cfg.FullNode.Port)
109+
_, _ = fmt.Fprintln(w, "Full Node RPC\t", cfg.FullNode.RPCPort)
110+
_, _ = fmt.Fprintln(w, "Wallet RPC\t", cfg.Wallet.RPCPort)
111+
_, _ = fmt.Fprintln(w, "Farmer Port\t", cfg.Farmer.Port)
112+
_, _ = fmt.Fprintln(w, "Farmer RPC\t", cfg.Farmer.RPCPort)
113+
_, _ = fmt.Fprintln(w, "Harvester RPC\t", cfg.Harvester.RPCPort)
114+
_, _ = fmt.Fprintln(w, "Crawler RPC\t", cfg.Seeder.CrawlerConfig.RPCPort)
115+
_, _ = fmt.Fprintln(w, "Seeder Port\t", cfg.Seeder.Port)
116+
_, _ = fmt.Fprintln(w, "Data Layer Host Port\t", cfg.DataLayer.HostPort)
117+
_, _ = fmt.Fprintln(w, "Data Layer RPC\t", cfg.DataLayer.RPCPort)
118+
_, _ = fmt.Fprintln(w, "Timelord RPC\t", cfg.Timelord.RPCPort)
119+
_ = w.Flush()
120+
}
121+
122+
// debugFileSizes retrieves the Chia root path and prints sorted file paths with sizes
123+
func debugFileSizes() {
124+
chiaroot, err := config.GetChiaRootPath()
125+
if err != nil {
126+
fmt.Printf("Could not determine CHIA_ROOT: %s\n", err.Error())
127+
return
128+
}
129+
130+
fmt.Println("Scanning:", chiaroot)
131+
fmt.Printf("%-*s %s\n", sizeColumnWidth, "Size", "File") // Header
132+
fmt.Println(strings.Repeat("-", 60)) // Separator
133+
134+
// Collect files and sort them by size
135+
files := collectFiles(chiaroot)
136+
if viper.GetBool("debug-sort") {
137+
sort.Slice(files, func(i, j int) bool {
138+
return files[i].Size > files[j].Size // Sort descending
139+
})
140+
}
141+
142+
// Print sorted files
143+
for _, file := range files {
144+
fmt.Printf("%-*s %s\n", sizeColumnWidth, humanReadableSize(file.Size), file.Path)
145+
}
146+
}
147+
148+
// collectFiles recursively collects file paths and sizes
149+
func collectFiles(root string) []FileInfo {
150+
var files []FileInfo
151+
err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
152+
if err != nil {
153+
return nil
154+
}
155+
if !d.IsDir() {
156+
info, err := os.Stat(path)
157+
if err == nil {
158+
relPath, _ := filepath.Rel(root, path)
159+
160+
// Apply exclusions
161+
if !viper.GetBool("debug-all-files") && isExcluded(relPath) {
162+
return nil // Skip this file
163+
}
164+
165+
files = append(files, FileInfo{Size: info.Size(), Path: relPath})
166+
}
167+
}
168+
return nil
169+
})
170+
if err != nil {
171+
slogs.Logr.Fatal("error scanning chia root")
172+
}
173+
return files
174+
}
175+
176+
// isExcluded checks if a file path matches any exclusion pattern
177+
func isExcluded(path string) bool {
178+
for _, pattern := range exclusions {
179+
match, _ := regexp.MatchString(pattern, path)
180+
if match {
181+
return true
182+
}
183+
}
184+
return false
185+
}
186+
187+
// humanReadableSize converts bytes into a human-friendly format (KB, MB, GB, etc.)
188+
func humanReadableSize(bytes int64) string {
189+
const unit = 1024
190+
if bytes < unit {
191+
return fmt.Sprintf("%d B", bytes)
192+
}
193+
div, exp := int64(unit), 0
194+
for n := bytes / unit; n >= unit; n /= unit {
195+
div *= unit
196+
exp++
197+
}
198+
return fmt.Sprintf("%.2f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
199+
}
200+
201+
func init() {
202+
debugCmd.PersistentFlags().Bool("sort", false, "Sort the files largest first")
203+
debugCmd.PersistentFlags().Bool("all-files", false, "Show all files. By default, some typically small files are excluded from the output")
204+
205+
cobra.CheckErr(viper.BindPFlag("debug-sort", debugCmd.PersistentFlags().Lookup("sort")))
206+
cobra.CheckErr(viper.BindPFlag("debug-all-files", debugCmd.PersistentFlags().Lookup("all-files")))
207+
208+
cmd.RootCmd.AddCommand(debugCmd)
209+
}

cmd/debug/version.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package debug
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"net/http"
7+
"os"
8+
"text/tabwriter"
9+
10+
"github.com/chia-network/go-chia-libs/pkg/rpc"
11+
"github.com/chia-network/go-modules/pkg/slogs"
12+
)
13+
14+
// ShowVersionInfo outputs the running version for all services
15+
func ShowVersionInfo() {
16+
slogs.Logr.Debug("initializing websocket client")
17+
websocketClient, err := rpc.NewClient(rpc.ConnectionModeWebsocket, rpc.WithAutoConfig(), rpc.WithSyncWebsocket())
18+
if err != nil {
19+
slogs.Logr.Fatal("error initializing websocket RPC client", "error", err)
20+
}
21+
slogs.Logr.Debug("initializing http client")
22+
rpcClient, err := rpc.NewClient(rpc.ConnectionModeHTTP, rpc.WithAutoConfig(), rpc.WithSyncWebsocket())
23+
if err != nil {
24+
slogs.Logr.Fatal("error initializing websocket RPC client", "error", err)
25+
}
26+
27+
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
28+
versionHelper(w, websocketClient.DaemonService, "Daemon")
29+
versionHelper(w, rpcClient.FullNodeService, "Full Node")
30+
versionHelper(w, rpcClient.WalletService, "Wallet")
31+
versionHelper(w, rpcClient.FarmerService, "Farmer")
32+
versionHelper(w, rpcClient.HarvesterService, "Harvester")
33+
versionHelper(w, rpcClient.CrawlerService, "Crawler")
34+
versionHelper(w, rpcClient.DataLayerService, "Data Layer")
35+
versionHelper(w, rpcClient.TimelordService, "Timelord")
36+
_ = w.Flush()
37+
}
38+
39+
type hasVersionInfo interface {
40+
GetVersion(opts *rpc.GetVersionOptions) (*rpc.GetVersionResponse, *http.Response, error)
41+
}
42+
43+
func versionHelper(w io.Writer, service hasVersionInfo, label string) {
44+
version, _, err := service.GetVersion(&rpc.GetVersionOptions{})
45+
if err != nil {
46+
slogs.Logr.Debug("error getting network info from daemon", "error", err)
47+
version = &rpc.GetVersionResponse{Version: "Not Running"}
48+
}
49+
if version == nil {
50+
slogs.Logr.Debug("no network info found", "service", label)
51+
version = &rpc.GetVersionResponse{Version: "Not Running"}
52+
}
53+
_, _ = fmt.Fprintln(w, label, "\t", version.Version)
54+
}

cmd/network/show.go

+38-33
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,49 @@ var showCmd = &cobra.Command{
1818
Use: "show",
1919
Short: "Show information about the currently selected/running network",
2020
Run: func(cmd *cobra.Command, args []string) {
21-
chiaRoot, err := config.GetChiaRootPath()
22-
if err != nil {
23-
slogs.Logr.Fatal("error determining chia root", "error", err)
24-
}
25-
slogs.Logr.Debug("Chia root discovered", "CHIA_ROOT", chiaRoot)
21+
ShowNetworkInfo()
22+
},
23+
}
24+
25+
// ShowNetworkInfo outputs network information from the configuration and any running services
26+
func ShowNetworkInfo() {
27+
chiaRoot, err := config.GetChiaRootPath()
28+
if err != nil {
29+
slogs.Logr.Fatal("error determining chia root", "error", err)
30+
}
31+
slogs.Logr.Debug("Chia root discovered", "CHIA_ROOT", chiaRoot)
2632

27-
cfg, err := config.GetChiaConfig()
28-
if err != nil {
29-
slogs.Logr.Fatal("error loading config", "error", err)
30-
}
31-
slogs.Logr.Debug("Successfully loaded config")
33+
cfg, err := config.GetChiaConfig()
34+
if err != nil {
35+
slogs.Logr.Fatal("error loading config", "error", err)
36+
}
37+
slogs.Logr.Debug("Successfully loaded config")
3238

33-
configNetwork := *cfg.SelectedNetwork
39+
configNetwork := *cfg.SelectedNetwork
3440

35-
slogs.Logr.Debug("initializing websocket client")
36-
websocketClient, err := rpc.NewClient(rpc.ConnectionModeWebsocket, rpc.WithAutoConfig(), rpc.WithSyncWebsocket())
37-
if err != nil {
38-
slogs.Logr.Fatal("error initializing websocket RPC client", "error", err)
39-
}
40-
slogs.Logr.Debug("initializing http client")
41-
rpcClient, err := rpc.NewClient(rpc.ConnectionModeHTTP, rpc.WithAutoConfig(), rpc.WithSyncWebsocket())
42-
if err != nil {
43-
slogs.Logr.Fatal("error initializing websocket RPC client", "error", err)
44-
}
41+
slogs.Logr.Debug("initializing websocket client")
42+
websocketClient, err := rpc.NewClient(rpc.ConnectionModeWebsocket, rpc.WithAutoConfig(), rpc.WithSyncWebsocket())
43+
if err != nil {
44+
slogs.Logr.Fatal("error initializing websocket RPC client", "error", err)
45+
}
46+
slogs.Logr.Debug("initializing http client")
47+
rpcClient, err := rpc.NewClient(rpc.ConnectionModeHTTP, rpc.WithAutoConfig(), rpc.WithSyncWebsocket())
48+
if err != nil {
49+
slogs.Logr.Fatal("error initializing websocket RPC client", "error", err)
50+
}
4551

46-
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
47-
_, _ = fmt.Fprintln(w, "Config\t", configNetwork)
52+
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
53+
_, _ = fmt.Fprintln(w, "Config\t", configNetwork)
4854

49-
networkHelper(w, websocketClient.DaemonService, "Daemon")
50-
networkHelper(w, rpcClient.FullNodeService, "Full Node")
51-
networkHelper(w, rpcClient.WalletService, "Wallet")
52-
networkHelper(w, rpcClient.FarmerService, "Farmer")
53-
networkHelper(w, rpcClient.HarvesterService, "Harvester")
54-
networkHelper(w, rpcClient.CrawlerService, "Crawler")
55-
networkHelper(w, rpcClient.DataLayerService, "Data Layer")
56-
networkHelper(w, rpcClient.TimelordService, "Timelord")
57-
_ = w.Flush()
58-
},
55+
networkHelper(w, websocketClient.DaemonService, "Daemon")
56+
networkHelper(w, rpcClient.FullNodeService, "Full Node")
57+
networkHelper(w, rpcClient.WalletService, "Wallet")
58+
networkHelper(w, rpcClient.FarmerService, "Farmer")
59+
networkHelper(w, rpcClient.HarvesterService, "Harvester")
60+
networkHelper(w, rpcClient.CrawlerService, "Crawler")
61+
networkHelper(w, rpcClient.DataLayerService, "Data Layer")
62+
networkHelper(w, rpcClient.TimelordService, "Timelord")
63+
_ = w.Flush()
5964
}
6065

6166
type hasNetworkName interface {

main.go

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
_ "github.com/chia-network/chia-tools/cmd/certs"
66
_ "github.com/chia-network/chia-tools/cmd/config"
77
_ "github.com/chia-network/chia-tools/cmd/datalayer"
8+
_ "github.com/chia-network/chia-tools/cmd/debug"
89
_ "github.com/chia-network/chia-tools/cmd/network"
910
_ "github.com/chia-network/chia-tools/cmd/testnet"
1011
)

0 commit comments

Comments
 (0)