github.com/aswedchain/aswed@v1.0.1/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/aswedchain/aswed/log" 28 "github.com/aswedchain/aswed/metrics" 29 "github.com/aswedchain/aswed/metrics/exp" 30 "github.com/fjl/memsize/memsizeui" 31 colorable "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 backtraceAtFlag = cli.StringFlag{ 62 Name: "backtrace", 63 Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", 64 Value: "", 65 } 66 debugFlag = cli.BoolFlag{ 67 Name: "debug", 68 Usage: "Prepends log messages with call-site location (file and line number)", 69 } 70 pprofFlag = cli.BoolFlag{ 71 Name: "pprof", 72 Usage: "Enable the pprof HTTP server", 73 } 74 pprofPortFlag = cli.IntFlag{ 75 Name: "pprof.port", 76 Usage: "pprof HTTP server listening port", 77 Value: 6060, 78 } 79 pprofAddrFlag = cli.StringFlag{ 80 Name: "pprof.addr", 81 Usage: "pprof HTTP server listening interface", 82 Value: "127.0.0.1", 83 } 84 memprofilerateFlag = cli.IntFlag{ 85 Name: "pprof.memprofilerate", 86 Usage: "Turn on memory profiling with the given rate", 87 Value: runtime.MemProfileRate, 88 } 89 blockprofilerateFlag = cli.IntFlag{ 90 Name: "pprof.blockprofilerate", 91 Usage: "Turn on block profiling with the given rate", 92 } 93 cpuprofileFlag = cli.StringFlag{ 94 Name: "pprof.cpuprofile", 95 Usage: "Write CPU profile to the given file", 96 } 97 traceFlag = cli.StringFlag{ 98 Name: "trace", 99 Usage: "Write execution trace to the given file", 100 } 101 // (Deprecated April 2020) 102 legacyPprofPortFlag = cli.IntFlag{ 103 Name: "pprofport", 104 Usage: "pprof HTTP server listening port (deprecated, use --pprof.port)", 105 Value: 6060, 106 } 107 legacyPprofAddrFlag = cli.StringFlag{ 108 Name: "pprofaddr", 109 Usage: "pprof HTTP server listening interface (deprecated, use --pprof.addr)", 110 Value: "127.0.0.1", 111 } 112 legacyMemprofilerateFlag = cli.IntFlag{ 113 Name: "memprofilerate", 114 Usage: "Turn on memory profiling with the given rate (deprecated, use --pprof.memprofilerate)", 115 Value: runtime.MemProfileRate, 116 } 117 legacyBlockprofilerateFlag = cli.IntFlag{ 118 Name: "blockprofilerate", 119 Usage: "Turn on block profiling with the given rate (deprecated, use --pprof.blockprofilerate)", 120 } 121 legacyCpuprofileFlag = cli.StringFlag{ 122 Name: "cpuprofile", 123 Usage: "Write CPU profile to the given file (deprecated, use --pprof.cpuprofile)", 124 } 125 ) 126 127 // Flags holds all command-line flags required for debugging. 128 var Flags = []cli.Flag{ 129 verbosityFlag, logPathFlag, metricLogFlag, vmoduleFlag, backtraceAtFlag, debugFlag, 130 pprofFlag, pprofAddrFlag, pprofPortFlag, memprofilerateFlag, 131 blockprofilerateFlag, cpuprofileFlag, traceFlag, 132 } 133 134 var DeprecatedFlags = []cli.Flag{ 135 legacyPprofPortFlag, legacyPprofAddrFlag, legacyMemprofilerateFlag, 136 legacyBlockprofilerateFlag, legacyCpuprofileFlag, 137 } 138 139 var ( 140 glogger *log.GlogHandler 141 ) 142 143 const ( 144 metricLogFile = "metric.log" 145 metricKey = "metric" 146 ) 147 148 func setupLogHandler(ctx *cli.Context) (handler log.Handler) { 149 usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" 150 151 if ctx.GlobalString(logPathFlag.Name) == "" { 152 output := io.Writer(os.Stderr) 153 if usecolor { 154 output = colorable.NewColorableStderr() 155 } 156 handler = log.StreamHandler(output, log.TerminalFormat(usecolor)) 157 return 158 } 159 160 rConfig := log.NewRotateConfig() 161 rConfig.LogDir = ctx.GlobalString(logPathFlag.Name) 162 handler1 := log.NewFileRotateHandler(rConfig, log.TerminalFormat(usecolor)) 163 if !ctx.GlobalBool(metricLogFlag.Name) { 164 handler = handler1 165 return 166 } 167 168 mConfig := log.NewRotateConfig() 169 mConfig.LogDir = ctx.GlobalString(logPathFlag.Name) 170 mConfig.Filename = metricLogFile 171 handler2 := log.NewFileRotateHandler(mConfig, log.JSONFormat()) 172 173 handler = log.FuncHandler(func(r *log.Record) error { 174 if r.Msg == metricKey { 175 r.Ctx = append(r.Ctx, "id", ID) 176 return handler2.Log(r) 177 } else { 178 return handler1.Log(r) 179 } 180 }) 181 182 return 183 } 184 185 // Setup initializes profiling and logging based on the CLI flags. 186 // It should be called as early as possible in the program. 187 func Setup(ctx *cli.Context) error { 188 // logging 189 handler := setupLogHandler(ctx) 190 glogger = log.NewGlogHandler(handler) 191 192 log.PrintOrigins(ctx.GlobalBool(debugFlag.Name)) 193 glogger.Verbosity(log.Lvl(ctx.GlobalInt(verbosityFlag.Name))) 194 glogger.Vmodule(ctx.GlobalString(vmoduleFlag.Name)) 195 glogger.BacktraceAt(ctx.GlobalString(backtraceAtFlag.Name)) 196 log.Root().SetHandler(glogger) 197 198 // profiling, tracing 199 if ctx.GlobalIsSet(legacyMemprofilerateFlag.Name) { 200 runtime.MemProfileRate = ctx.GlobalInt(legacyMemprofilerateFlag.Name) 201 log.Warn("The flag --memprofilerate is deprecated and will be removed in the future, please use --pprof.memprofilerate") 202 } 203 runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name) 204 205 if ctx.GlobalIsSet(legacyBlockprofilerateFlag.Name) { 206 Handler.SetBlockProfileRate(ctx.GlobalInt(legacyBlockprofilerateFlag.Name)) 207 log.Warn("The flag --blockprofilerate is deprecated and will be removed in the future, please use --pprof.blockprofilerate") 208 } 209 Handler.SetBlockProfileRate(ctx.GlobalInt(blockprofilerateFlag.Name)) 210 211 if traceFile := ctx.GlobalString(traceFlag.Name); traceFile != "" { 212 if err := Handler.StartGoTrace(traceFile); err != nil { 213 return err 214 } 215 } 216 217 if cpuFile := ctx.GlobalString(cpuprofileFlag.Name); cpuFile != "" { 218 if err := Handler.StartCPUProfile(cpuFile); err != nil { 219 return err 220 } 221 } 222 if cpuFile := ctx.GlobalString(legacyCpuprofileFlag.Name); cpuFile != "" { 223 log.Warn("The flag --cpuprofile is deprecated and will be removed in the future, please use --pprof.cpuprofile") 224 if err := Handler.StartCPUProfile(cpuFile); err != nil { 225 return err 226 } 227 } 228 229 // pprof server 230 if ctx.GlobalBool(pprofFlag.Name) { 231 listenHost := ctx.GlobalString(pprofAddrFlag.Name) 232 if ctx.GlobalIsSet(legacyPprofAddrFlag.Name) && !ctx.GlobalIsSet(pprofAddrFlag.Name) { 233 listenHost = ctx.GlobalString(legacyPprofAddrFlag.Name) 234 log.Warn("The flag --pprofaddr is deprecated and will be removed in the future, please use --pprof.addr") 235 } 236 237 port := ctx.GlobalInt(pprofPortFlag.Name) 238 if ctx.GlobalIsSet(legacyPprofPortFlag.Name) && !ctx.GlobalIsSet(pprofPortFlag.Name) { 239 port = ctx.GlobalInt(legacyPprofPortFlag.Name) 240 log.Warn("The flag --pprofport is deprecated and will be removed in the future, please use --pprof.port") 241 } 242 243 address := fmt.Sprintf("%s:%d", listenHost, port) 244 // This context value ("metrics.addr") represents the utils.MetricsHTTPFlag.Name. 245 // It cannot be imported because it will cause a cyclical dependency. 246 StartPProf(address, !ctx.GlobalIsSet("metrics.addr")) 247 } 248 return nil 249 } 250 251 func StartPProf(address string, withMetrics bool) { 252 // Hook go-metrics into expvar on any /debug/metrics request, load all vars 253 // from the registry into expvar, and execute regular expvar handler. 254 if withMetrics { 255 exp.Exp(metrics.DefaultRegistry) 256 } 257 http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize)) 258 log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) 259 go func() { 260 if err := http.ListenAndServe(address, nil); err != nil { 261 log.Error("Failure in running pprof server", "err", err) 262 } 263 }() 264 } 265 266 // Exit stops all running profiles, flushing their output to the 267 // respective file. 268 func Exit() { 269 Handler.StopCPUProfile() 270 Handler.StopGoTrace() 271 }