github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/internal/debug/flags.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package debug 19 20 import ( 21 "fmt" 22 "io" 23 "net/http" 24 _ "net/http/pprof" 25 "os" 26 "runtime" 27 28 "github.com/AigarNetwork/aigar/log" 29 "github.com/AigarNetwork/aigar/metrics" 30 "github.com/AigarNetwork/aigar/metrics/exp" 31 "github.com/fjl/memsize/memsizeui" 32 colorable "github.com/mattn/go-colorable" 33 "github.com/mattn/go-isatty" 34 "gopkg.in/urfave/cli.v1" 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 } 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 } 50 backtraceAtFlag = cli.StringFlag{ 51 Name: "backtrace", 52 Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", 53 Value: "", 54 } 55 debugFlag = cli.BoolFlag{ 56 Name: "debug", 57 Usage: "Prepends log messages with call-site location (file and line number)", 58 } 59 pprofFlag = cli.BoolFlag{ 60 Name: "pprof", 61 Usage: "Enable the pprof HTTP server", 62 } 63 pprofPortFlag = cli.IntFlag{ 64 Name: "pprofport", 65 Usage: "pprof HTTP server listening port", 66 Value: 6060, 67 } 68 pprofAddrFlag = cli.StringFlag{ 69 Name: "pprofaddr", 70 Usage: "pprof HTTP server listening interface", 71 Value: "127.0.0.1", 72 } 73 memprofilerateFlag = cli.IntFlag{ 74 Name: "memprofilerate", 75 Usage: "Turn on memory profiling with the given rate", 76 Value: runtime.MemProfileRate, 77 } 78 blockprofilerateFlag = cli.IntFlag{ 79 Name: "blockprofilerate", 80 Usage: "Turn on block profiling with the given rate", 81 } 82 cpuprofileFlag = cli.StringFlag{ 83 Name: "cpuprofile", 84 Usage: "Write CPU profile to the given file", 85 } 86 traceFlag = cli.StringFlag{ 87 Name: "trace", 88 Usage: "Write execution trace to the given file", 89 } 90 ) 91 92 // Flags holds all command-line flags required for debugging. 93 var Flags = []cli.Flag{ 94 verbosityFlag, vmoduleFlag, backtraceAtFlag, debugFlag, 95 pprofFlag, pprofAddrFlag, pprofPortFlag, 96 memprofilerateFlag, blockprofilerateFlag, cpuprofileFlag, traceFlag, 97 } 98 99 var ( 100 ostream log.Handler 101 glogger *log.GlogHandler 102 ) 103 104 func init() { 105 usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" 106 output := io.Writer(os.Stderr) 107 if usecolor { 108 output = colorable.NewColorableStderr() 109 } 110 ostream = log.StreamHandler(output, log.TerminalFormat(usecolor)) 111 glogger = log.NewGlogHandler(ostream) 112 } 113 114 // Setup initializes profiling and logging based on the CLI flags. 115 // It should be called as early as possible in the program. 116 func Setup(ctx *cli.Context, logdir string) error { 117 // logging 118 log.PrintOrigins(ctx.GlobalBool(debugFlag.Name)) 119 if logdir != "" { 120 rfh, err := log.RotatingFileHandler( 121 logdir, 122 262144, 123 log.JSONFormatOrderedEx(false, true), 124 ) 125 if err != nil { 126 return err 127 } 128 glogger.SetHandler(log.MultiHandler(ostream, rfh)) 129 } 130 glogger.Verbosity(log.Lvl(ctx.GlobalInt(verbosityFlag.Name))) 131 glogger.Vmodule(ctx.GlobalString(vmoduleFlag.Name)) 132 glogger.BacktraceAt(ctx.GlobalString(backtraceAtFlag.Name)) 133 log.Root().SetHandler(glogger) 134 135 // profiling, tracing 136 runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name) 137 Handler.SetBlockProfileRate(ctx.GlobalInt(blockprofilerateFlag.Name)) 138 if traceFile := ctx.GlobalString(traceFlag.Name); traceFile != "" { 139 if err := Handler.StartGoTrace(traceFile); err != nil { 140 return err 141 } 142 } 143 if cpuFile := ctx.GlobalString(cpuprofileFlag.Name); cpuFile != "" { 144 if err := Handler.StartCPUProfile(cpuFile); err != nil { 145 return err 146 } 147 } 148 149 // pprof server 150 if ctx.GlobalBool(pprofFlag.Name) { 151 address := fmt.Sprintf("%s:%d", ctx.GlobalString(pprofAddrFlag.Name), ctx.GlobalInt(pprofPortFlag.Name)) 152 StartPProf(address) 153 } 154 return nil 155 } 156 157 func StartPProf(address string) { 158 // Hook go-metrics into expvar on any /debug/metrics request, load all vars 159 // from the registry into expvar, and execute regular expvar handler. 160 exp.Exp(metrics.DefaultRegistry) 161 http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize)) 162 log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) 163 go func() { 164 if err := http.ListenAndServe(address, nil); err != nil { 165 log.Error("Failure in running pprof server", "err", err) 166 } 167 }() 168 } 169 170 // Exit stops all running profiles, flushing their output to the 171 // respective file. 172 func Exit() { 173 Handler.StopCPUProfile() 174 Handler.StopGoTrace() 175 }