github.com/ethxdao/go-ethereum@v0.0.0-20221218102228-5ae34a9cc189/internal/debug/flags.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package debug 18 19 import ( 20 "fmt" 21 "io" 22 "net/http" 23 _ "net/http/pprof" // nolint: gosec 24 "os" 25 "runtime" 26 27 "github.com/ethxdao/go-ethereum/internal/flags" 28 "github.com/ethxdao/go-ethereum/log" 29 "github.com/ethxdao/go-ethereum/metrics" 30 "github.com/ethxdao/go-ethereum/metrics/exp" 31 "github.com/fjl/memsize/memsizeui" 32 "github.com/mattn/go-colorable" 33 "github.com/mattn/go-isatty" 34 ) 35 36 var Memsize memsizeui.Handler 37 38 var ( 39 verbosityFlag = &cli.IntFlag{ 40 Name: "verbosity", 41 Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail", 42 Value: 3, 43 Category: flags.LoggingCategory, 44 } 45 vmoduleFlag = &cli.StringFlag{ 46 Name: "vmodule", 47 Usage: "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=5,p2p=4)", 48 Value: "", 49 Category: flags.LoggingCategory, 50 } 51 logjsonFlag = &cli.BoolFlag{ 52 Name: "log.json", 53 Usage: "Format logs with JSON", 54 Category: flags.LoggingCategory, 55 } 56 backtraceAtFlag = &cli.StringFlag{ 57 Name: "log.backtrace", 58 Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", 59 Value: "", 60 Category: flags.LoggingCategory, 61 } 62 debugFlag = &cli.BoolFlag{ 63 Name: "log.debug", 64 Usage: "Prepends log messages with call-site location (file and line number)", 65 Category: flags.LoggingCategory, 66 } 67 pprofFlag = &cli.BoolFlag{ 68 Name: "pprof", 69 Usage: "Enable the pprof HTTP server", 70 Category: flags.LoggingCategory, 71 } 72 pprofPortFlag = &cli.IntFlag{ 73 Name: "pprof.port", 74 Usage: "pprof HTTP server listening port", 75 Value: 6060, 76 Category: flags.LoggingCategory, 77 } 78 pprofAddrFlag = &cli.StringFlag{ 79 Name: "pprof.addr", 80 Usage: "pprof HTTP server listening interface", 81 Value: "127.0.0.1", 82 Category: flags.LoggingCategory, 83 } 84 memprofilerateFlag = &cli.IntFlag{ 85 Name: "pprof.memprofilerate", 86 Usage: "Turn on memory profiling with the given rate", 87 Value: runtime.MemProfileRate, 88 Category: flags.LoggingCategory, 89 } 90 blockprofilerateFlag = &cli.IntFlag{ 91 Name: "pprof.blockprofilerate", 92 Usage: "Turn on block profiling with the given rate", 93 Category: flags.LoggingCategory, 94 } 95 cpuprofileFlag = &cli.StringFlag{ 96 Name: "pprof.cpuprofile", 97 Usage: "Write CPU profile to the given file", 98 Category: flags.LoggingCategory, 99 } 100 traceFlag = &cli.StringFlag{ 101 Name: "trace", 102 Usage: "Write execution trace to the given file", 103 Category: flags.LoggingCategory, 104 } 105 ) 106 107 // Flags holds all command-line flags required for debugging. 108 var Flags = []cli.Flag{ 109 verbosityFlag, 110 vmoduleFlag, 111 logjsonFlag, 112 backtraceAtFlag, 113 debugFlag, 114 pprofFlag, 115 pprofAddrFlag, 116 pprofPortFlag, 117 memprofilerateFlag, 118 blockprofilerateFlag, 119 cpuprofileFlag, 120 traceFlag, 121 } 122 123 var glogger *log.GlogHandler 124 125 func init() { 126 glogger = log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) 127 glogger.Verbosity(log.LvlInfo) 128 log.Root().SetHandler(glogger) 129 } 130 131 // Setup initializes profiling and logging based on the CLI flags. 132 // It should be called as early as possible in the program. 133 func Setup(ctx *cli.Context) error { 134 var ostream log.Handler 135 output := io.Writer(os.Stderr) 136 if ctx.Bool(logjsonFlag.Name) { 137 ostream = log.StreamHandler(output, log.JSONFormat()) 138 } else { 139 usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" 140 if usecolor { 141 output = colorable.NewColorableStderr() 142 } 143 ostream = log.StreamHandler(output, log.TerminalFormat(usecolor)) 144 } 145 glogger.SetHandler(ostream) 146 147 // logging 148 verbosity := ctx.Int(verbosityFlag.Name) 149 glogger.Verbosity(log.Lvl(verbosity)) 150 vmodule := ctx.String(vmoduleFlag.Name) 151 glogger.Vmodule(vmodule) 152 153 debug := ctx.Bool(debugFlag.Name) 154 if ctx.IsSet(debugFlag.Name) { 155 debug = ctx.Bool(debugFlag.Name) 156 } 157 log.PrintOrigins(debug) 158 159 backtrace := ctx.String(backtraceAtFlag.Name) 160 glogger.BacktraceAt(backtrace) 161 162 log.Root().SetHandler(glogger) 163 164 // profiling, tracing 165 runtime.MemProfileRate = memprofilerateFlag.Value 166 if ctx.IsSet(memprofilerateFlag.Name) { 167 runtime.MemProfileRate = ctx.Int(memprofilerateFlag.Name) 168 } 169 170 blockProfileRate := ctx.Int(blockprofilerateFlag.Name) 171 Handler.SetBlockProfileRate(blockProfileRate) 172 173 if traceFile := ctx.String(traceFlag.Name); traceFile != "" { 174 if err := Handler.StartGoTrace(traceFile); err != nil { 175 return err 176 } 177 } 178 179 if cpuFile := ctx.String(cpuprofileFlag.Name); cpuFile != "" { 180 if err := Handler.StartCPUProfile(cpuFile); err != nil { 181 return err 182 } 183 } 184 185 // pprof server 186 if ctx.Bool(pprofFlag.Name) { 187 listenHost := ctx.String(pprofAddrFlag.Name) 188 189 port := ctx.Int(pprofPortFlag.Name) 190 191 address := fmt.Sprintf("%s:%d", listenHost, port) 192 // This context value ("metrics.addr") represents the utils.MetricsHTTPFlag.Name. 193 // It cannot be imported because it will cause a cyclical dependency. 194 StartPProf(address, !ctx.IsSet("metrics.addr")) 195 } 196 return nil 197 } 198 199 func StartPProf(address string, withMetrics bool) { 200 // Hook go-metrics into expvar on any /debug/metrics request, load all vars 201 // from the registry into expvar, and execute regular expvar handler. 202 if withMetrics { 203 exp.Exp(metrics.DefaultRegistry) 204 } 205 http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize)) 206 log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) 207 go func() { 208 if err := http.ListenAndServe(address, nil); err != nil { 209 log.Error("Failure in running pprof server", "err", err) 210 } 211 }() 212 } 213 214 // Exit stops all running profiles, flushing their output to the 215 // respective file. 216 func Exit() { 217 Handler.StopCPUProfile() 218 Handler.StopGoTrace() 219 }