github.com/DxChainNetwork/dxc@v0.8.1-0.20220824085222-1162e304b6e7/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" 24 "os" 25 "runtime" 26 27 "github.com/DxChainNetwork/dxc/log" 28 "github.com/DxChainNetwork/dxc/metrics" 29 "github.com/DxChainNetwork/dxc/metrics/exp" 30 "github.com/fjl/memsize/memsizeui" 31 "github.com/mattn/go-colorable" 32 "github.com/mattn/go-isatty" 33 "gopkg.in/urfave/cli.v1" 34 ) 35 36 var Memsize memsizeui.Handler 37 var ID string 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 } 45 logPathFlag = cli.StringFlag{ 46 Name: "logpath", 47 Usage: "File path for log files", 48 Value: "", 49 } 50 51 metricLogFlag = cli.BoolFlag{ 52 Name: "metriclog", 53 Usage: "Write metric info to log files", 54 } 55 56 vmoduleFlag = cli.StringFlag{ 57 Name: "vmodule", 58 Usage: "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=5,p2p=4)", 59 Value: "", 60 } 61 logjsonFlag = cli.BoolFlag{ 62 Name: "log.json", 63 Usage: "Format logs with JSON", 64 } 65 backtraceAtFlag = cli.StringFlag{ 66 Name: "log.backtrace", 67 Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", 68 Value: "", 69 } 70 debugFlag = cli.BoolFlag{ 71 Name: "log.debug", 72 Usage: "Prepends log messages with call-site location (file and line number)", 73 } 74 pprofFlag = cli.BoolFlag{ 75 Name: "pprof", 76 Usage: "Enable the pprof HTTP server", 77 } 78 pprofPortFlag = cli.IntFlag{ 79 Name: "pprof.port", 80 Usage: "pprof HTTP server listening port", 81 Value: 6060, 82 } 83 pprofAddrFlag = cli.StringFlag{ 84 Name: "pprof.addr", 85 Usage: "pprof HTTP server listening interface", 86 Value: "127.0.0.1", 87 } 88 memprofilerateFlag = cli.IntFlag{ 89 Name: "pprof.memprofilerate", 90 Usage: "Turn on memory profiling with the given rate", 91 Value: runtime.MemProfileRate, 92 } 93 blockprofilerateFlag = cli.IntFlag{ 94 Name: "pprof.blockprofilerate", 95 Usage: "Turn on block profiling with the given rate", 96 } 97 cpuprofileFlag = cli.StringFlag{ 98 Name: "pprof.cpuprofile", 99 Usage: "Write CPU profile to the given file", 100 } 101 traceFlag = cli.StringFlag{ 102 Name: "trace", 103 Usage: "Write execution trace to the given file", 104 } 105 // (Deprecated April 2020) 106 legacyPprofPortFlag = cli.IntFlag{ 107 Name: "pprofport", 108 Usage: "pprof HTTP server listening port (deprecated, use --pprof.port)", 109 Value: 6060, 110 } 111 legacyPprofAddrFlag = cli.StringFlag{ 112 Name: "pprofaddr", 113 Usage: "pprof HTTP server listening interface (deprecated, use --pprof.addr)", 114 Value: "127.0.0.1", 115 } 116 legacyMemprofilerateFlag = cli.IntFlag{ 117 Name: "memprofilerate", 118 Usage: "Turn on memory profiling with the given rate (deprecated, use --pprof.memprofilerate)", 119 Value: runtime.MemProfileRate, 120 } 121 legacyBlockprofilerateFlag = cli.IntFlag{ 122 Name: "blockprofilerate", 123 Usage: "Turn on block profiling with the given rate (deprecated, use --pprof.blockprofilerate)", 124 } 125 legacyCpuprofileFlag = cli.StringFlag{ 126 Name: "cpuprofile", 127 Usage: "Write CPU profile to the given file (deprecated, use --pprof.cpuprofile)", 128 } 129 legacyBacktraceAtFlag = cli.StringFlag{ 130 Name: "backtrace", 131 Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\") (deprecated, use --log.backtrace)", 132 Value: "", 133 } 134 legacyDebugFlag = cli.BoolFlag{ 135 Name: "debug", 136 Usage: "Prepends log messages with call-site location (file and line number) (deprecated, use --log.debug)", 137 } 138 ) 139 140 // Flags holds all command-line flags required for debugging. 141 var Flags = []cli.Flag{ 142 verbosityFlag, 143 logPathFlag, 144 vmoduleFlag, 145 logjsonFlag, 146 metricLogFlag, 147 backtraceAtFlag, 148 debugFlag, 149 pprofFlag, 150 pprofAddrFlag, 151 pprofPortFlag, 152 memprofilerateFlag, 153 blockprofilerateFlag, 154 cpuprofileFlag, 155 traceFlag, 156 } 157 158 // This is the list of deprecated debugging flags. 159 var DeprecatedFlags = []cli.Flag{ 160 legacyPprofPortFlag, 161 legacyPprofAddrFlag, 162 legacyMemprofilerateFlag, 163 legacyBlockprofilerateFlag, 164 legacyCpuprofileFlag, 165 legacyBacktraceAtFlag, 166 legacyDebugFlag, 167 } 168 169 var glogger *log.GlogHandler 170 171 const ( 172 metricLogFile = "metric.log" 173 metricKey = "metric" 174 ) 175 176 func init() { 177 glogger = log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) 178 glogger.Verbosity(log.LvlInfo) 179 log.Root().SetHandler(glogger) 180 } 181 182 func setupLogHandler(ctx *cli.Context) (handler log.Handler) { 183 defer func() { 184 if !ctx.GlobalBool(metricLogFlag.Name) { 185 inner := handler 186 handler = log.FuncHandler(func(r *log.Record) error { 187 if r.Msg == metricKey { 188 return nil 189 } 190 191 return inner.Log(r) 192 }) 193 } 194 }() 195 196 var format log.Format 197 output := io.Writer(os.Stderr) 198 if ctx.GlobalBool(logjsonFlag.Name) { 199 format = log.JSONFormat() 200 } else { 201 usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" 202 if usecolor { 203 output = colorable.NewColorableStderr() 204 } 205 format = log.TerminalFormat(usecolor) 206 } 207 208 if ctx.GlobalString(logPathFlag.Name) == "" { 209 handler = log.StreamHandler(output, format) 210 return 211 } 212 213 rConfig := log.NewRotateConfig() 214 rConfig.LogDir = ctx.GlobalString(logPathFlag.Name) 215 handler1 := log.NewFileRotateHandler(rConfig, format) 216 if !ctx.GlobalBool(metricLogFlag.Name) { 217 handler = handler1 218 return 219 } 220 221 mConfig := log.NewRotateConfig() 222 mConfig.LogDir = ctx.GlobalString(logPathFlag.Name) 223 mConfig.Filename = metricLogFile 224 handler2 := log.NewFileRotateHandler(mConfig, log.JSONFormat()) 225 226 handler = log.FuncHandler(func(r *log.Record) error { 227 if r.Msg == metricKey { 228 r.Ctx = append(r.Ctx, "id", ID) 229 return handler2.Log(r) 230 } else { 231 return handler1.Log(r) 232 } 233 }) 234 235 return 236 } 237 238 // Setup initializes profiling and logging based on the CLI flags. 239 // It should be called as early as possible in the program. 240 func Setup(ctx *cli.Context) error { 241 handler := setupLogHandler(ctx) 242 glogger.SetHandler(handler) 243 244 // logging 245 verbosity := ctx.GlobalInt(verbosityFlag.Name) 246 glogger.Verbosity(log.Lvl(verbosity)) 247 vmodule := ctx.GlobalString(vmoduleFlag.Name) 248 glogger.Vmodule(vmodule) 249 250 backtrace := ctx.GlobalString(backtraceAtFlag.Name) 251 if b := ctx.GlobalString(legacyBacktraceAtFlag.Name); b != "" { 252 backtrace = b 253 log.Warn("The flag --backtrace is deprecated and will be removed in the future, please use --log.backtrace") 254 } 255 if b := ctx.GlobalString(backtraceAtFlag.Name); b != "" { 256 backtrace = b 257 } 258 glogger.BacktraceAt(backtrace) 259 260 log.Root().SetHandler(glogger) 261 262 // profiling, tracing 263 runtime.MemProfileRate = memprofilerateFlag.Value 264 if ctx.GlobalIsSet(legacyMemprofilerateFlag.Name) { 265 runtime.MemProfileRate = ctx.GlobalInt(legacyMemprofilerateFlag.Name) 266 log.Warn("The flag --memprofilerate is deprecated and will be removed in the future, please use --pprof.memprofilerate") 267 } 268 if ctx.GlobalIsSet(memprofilerateFlag.Name) { 269 runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name) 270 } 271 272 blockProfileRate := blockprofilerateFlag.Value 273 if ctx.GlobalIsSet(legacyBlockprofilerateFlag.Name) { 274 blockProfileRate = ctx.GlobalInt(legacyBlockprofilerateFlag.Name) 275 log.Warn("The flag --blockprofilerate is deprecated and will be removed in the future, please use --pprof.blockprofilerate") 276 } 277 if ctx.GlobalIsSet(blockprofilerateFlag.Name) { 278 blockProfileRate = ctx.GlobalInt(blockprofilerateFlag.Name) 279 } 280 Handler.SetBlockProfileRate(blockProfileRate) 281 282 if traceFile := ctx.GlobalString(traceFlag.Name); traceFile != "" { 283 if err := Handler.StartGoTrace(traceFile); err != nil { 284 return err 285 } 286 } 287 288 if cpuFile := ctx.GlobalString(cpuprofileFlag.Name); cpuFile != "" { 289 if err := Handler.StartCPUProfile(cpuFile); err != nil { 290 return err 291 } 292 } 293 294 // pprof server 295 if ctx.GlobalBool(pprofFlag.Name) { 296 listenHost := ctx.GlobalString(pprofAddrFlag.Name) 297 298 port := ctx.GlobalInt(pprofPortFlag.Name) 299 300 address := fmt.Sprintf("%s:%d", listenHost, port) 301 // This context value ("metrics.addr") represents the utils.MetricsHTTPFlag.Name. 302 // It cannot be imported because it will cause a cyclical dependency. 303 StartPProf(address, !ctx.GlobalIsSet("metrics.addr")) 304 } 305 return nil 306 } 307 308 func StartPProf(address string, withMetrics bool) { 309 // Hook go-metrics into expvar on any /debug/metrics request, load all vars 310 // from the registry into expvar, and execute regular expvar handler. 311 if withMetrics { 312 exp.Exp(metrics.DefaultRegistry) 313 } 314 http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize)) 315 log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) 316 go func() { 317 if err := http.ListenAndServe(address, nil); err != nil { 318 log.Error("Failure in running pprof server", "err", err) 319 } 320 }() 321 } 322 323 // Exit stops all running profiles, flushing their output to the 324 // respective file. 325 func Exit() { 326 Handler.StopCPUProfile() 327 Handler.StopGoTrace() 328 }