github.com/jimmyx0x/go-ethereum@v1.10.28/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/ethereum/go-ethereum/internal/flags" 28 "github.com/ethereum/go-ethereum/log" 29 "github.com/ethereum/go-ethereum/metrics" 30 "github.com/ethereum/go-ethereum/metrics/exp" 31 "github.com/fjl/memsize/memsizeui" 32 "github.com/mattn/go-colorable" 33 "github.com/mattn/go-isatty" 34 "github.com/urfave/cli/v2" 35 ) 36 37 var Memsize memsizeui.Handler 38 39 var ( 40 verbosityFlag = &cli.IntFlag{ 41 Name: "verbosity", 42 Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail", 43 Value: 3, 44 Category: flags.LoggingCategory, 45 } 46 vmoduleFlag = &cli.StringFlag{ 47 Name: "vmodule", 48 Usage: "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=5,p2p=4)", 49 Value: "", 50 Category: flags.LoggingCategory, 51 } 52 logjsonFlag = &cli.BoolFlag{ 53 Name: "log.json", 54 Usage: "Format logs with JSON", 55 Category: flags.LoggingCategory, 56 } 57 logFileFlag = &cli.StringFlag{ 58 Name: "log.file", 59 Usage: "Write logs to a file", 60 Category: flags.LoggingCategory, 61 } 62 backtraceAtFlag = &cli.StringFlag{ 63 Name: "log.backtrace", 64 Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", 65 Value: "", 66 Category: flags.LoggingCategory, 67 } 68 debugFlag = &cli.BoolFlag{ 69 Name: "log.debug", 70 Usage: "Prepends log messages with call-site location (file and line number)", 71 Category: flags.LoggingCategory, 72 } 73 pprofFlag = &cli.BoolFlag{ 74 Name: "pprof", 75 Usage: "Enable the pprof HTTP server", 76 Category: flags.LoggingCategory, 77 } 78 pprofPortFlag = &cli.IntFlag{ 79 Name: "pprof.port", 80 Usage: "pprof HTTP server listening port", 81 Value: 6060, 82 Category: flags.LoggingCategory, 83 } 84 pprofAddrFlag = &cli.StringFlag{ 85 Name: "pprof.addr", 86 Usage: "pprof HTTP server listening interface", 87 Value: "127.0.0.1", 88 Category: flags.LoggingCategory, 89 } 90 memprofilerateFlag = &cli.IntFlag{ 91 Name: "pprof.memprofilerate", 92 Usage: "Turn on memory profiling with the given rate", 93 Value: runtime.MemProfileRate, 94 Category: flags.LoggingCategory, 95 } 96 blockprofilerateFlag = &cli.IntFlag{ 97 Name: "pprof.blockprofilerate", 98 Usage: "Turn on block profiling with the given rate", 99 Category: flags.LoggingCategory, 100 } 101 cpuprofileFlag = &cli.StringFlag{ 102 Name: "pprof.cpuprofile", 103 Usage: "Write CPU profile to the given file", 104 Category: flags.LoggingCategory, 105 } 106 traceFlag = &cli.StringFlag{ 107 Name: "trace", 108 Usage: "Write execution trace to the given file", 109 Category: flags.LoggingCategory, 110 } 111 ) 112 113 // Flags holds all command-line flags required for debugging. 114 var Flags = []cli.Flag{ 115 verbosityFlag, 116 vmoduleFlag, 117 logjsonFlag, 118 logFileFlag, 119 backtraceAtFlag, 120 debugFlag, 121 pprofFlag, 122 pprofAddrFlag, 123 pprofPortFlag, 124 memprofilerateFlag, 125 blockprofilerateFlag, 126 cpuprofileFlag, 127 traceFlag, 128 } 129 130 var ( 131 glogger *log.GlogHandler 132 logOutputStream log.Handler 133 ) 134 135 func init() { 136 glogger = log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) 137 glogger.Verbosity(log.LvlInfo) 138 log.Root().SetHandler(glogger) 139 } 140 141 // Setup initializes profiling and logging based on the CLI flags. 142 // It should be called as early as possible in the program. 143 func Setup(ctx *cli.Context) error { 144 logFile := ctx.String(logFileFlag.Name) 145 useColor := logFile == "" && os.Getenv("TERM") != "dumb" && (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) 146 147 var logfmt log.Format 148 if ctx.Bool(logjsonFlag.Name) { 149 logfmt = log.JSONFormat() 150 } else { 151 logfmt = log.TerminalFormat(useColor) 152 } 153 154 if logFile != "" { 155 var err error 156 logOutputStream, err = log.FileHandler(logFile, logfmt) 157 if err != nil { 158 return err 159 } 160 } else { 161 output := io.Writer(os.Stderr) 162 if useColor { 163 output = colorable.NewColorableStderr() 164 } 165 logOutputStream = log.StreamHandler(output, logfmt) 166 } 167 glogger.SetHandler(logOutputStream) 168 169 // logging 170 verbosity := ctx.Int(verbosityFlag.Name) 171 glogger.Verbosity(log.Lvl(verbosity)) 172 vmodule := ctx.String(vmoduleFlag.Name) 173 glogger.Vmodule(vmodule) 174 175 debug := ctx.Bool(debugFlag.Name) 176 if ctx.IsSet(debugFlag.Name) { 177 debug = ctx.Bool(debugFlag.Name) 178 } 179 log.PrintOrigins(debug) 180 181 backtrace := ctx.String(backtraceAtFlag.Name) 182 glogger.BacktraceAt(backtrace) 183 184 log.Root().SetHandler(glogger) 185 186 // profiling, tracing 187 runtime.MemProfileRate = memprofilerateFlag.Value 188 if ctx.IsSet(memprofilerateFlag.Name) { 189 runtime.MemProfileRate = ctx.Int(memprofilerateFlag.Name) 190 } 191 192 blockProfileRate := ctx.Int(blockprofilerateFlag.Name) 193 Handler.SetBlockProfileRate(blockProfileRate) 194 195 if traceFile := ctx.String(traceFlag.Name); traceFile != "" { 196 if err := Handler.StartGoTrace(traceFile); err != nil { 197 return err 198 } 199 } 200 201 if cpuFile := ctx.String(cpuprofileFlag.Name); cpuFile != "" { 202 if err := Handler.StartCPUProfile(cpuFile); err != nil { 203 return err 204 } 205 } 206 207 // pprof server 208 if ctx.Bool(pprofFlag.Name) { 209 listenHost := ctx.String(pprofAddrFlag.Name) 210 211 port := ctx.Int(pprofPortFlag.Name) 212 213 address := fmt.Sprintf("%s:%d", listenHost, port) 214 // This context value ("metrics.addr") represents the utils.MetricsHTTPFlag.Name. 215 // It cannot be imported because it will cause a cyclical dependency. 216 StartPProf(address, !ctx.IsSet("metrics.addr")) 217 } 218 return nil 219 } 220 221 func StartPProf(address string, withMetrics bool) { 222 // Hook go-metrics into expvar on any /debug/metrics request, load all vars 223 // from the registry into expvar, and execute regular expvar handler. 224 if withMetrics { 225 exp.Exp(metrics.DefaultRegistry) 226 } 227 http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize)) 228 log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) 229 go func() { 230 if err := http.ListenAndServe(address, nil); err != nil { 231 log.Error("Failure in running pprof server", "err", err) 232 } 233 }() 234 } 235 236 // Exit stops all running profiles, flushing their output to the 237 // respective file. 238 func Exit() { 239 Handler.StopCPUProfile() 240 Handler.StopGoTrace() 241 if closer, ok := logOutputStream.(io.Closer); ok { 242 closer.Close() 243 } 244 }