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