github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/internal/debug/flags.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package debug 13 14 import ( 15 "fmt" 16 "io" 17 "net/http" 18 _ "net/http/pprof" 19 "os" 20 "runtime" 21 22 "github.com/Sberex/go-sberex/log" 23 "github.com/Sberex/go-sberex/log/term" 24 "github.com/Sberex/go-sberex/metrics" 25 "github.com/Sberex/go-sberex/metrics/exp" 26 colorable "github.com/mattn/go-colorable" 27 "gopkg.in/urfave/cli.v1" 28 ) 29 30 var ( 31 verbosityFlag = cli.IntFlag{ 32 Name: "verbosity", 33 Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail", 34 Value: 3, 35 } 36 vmoduleFlag = cli.StringFlag{ 37 Name: "vmodule", 38 Usage: "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=5,p2p=4)", 39 Value: "", 40 } 41 backtraceAtFlag = cli.StringFlag{ 42 Name: "backtrace", 43 Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", 44 Value: "", 45 } 46 debugFlag = cli.BoolFlag{ 47 Name: "debug", 48 Usage: "Prepends log messages with call-site location (file and line number)", 49 } 50 pprofFlag = cli.BoolFlag{ 51 Name: "pprof", 52 Usage: "Enable the pprof HTTP server", 53 } 54 pprofPortFlag = cli.IntFlag{ 55 Name: "pprofport", 56 Usage: "pprof HTTP server listening port", 57 Value: 6060, 58 } 59 pprofAddrFlag = cli.StringFlag{ 60 Name: "pprofaddr", 61 Usage: "pprof HTTP server listening interface", 62 Value: "127.0.0.1", 63 } 64 memprofilerateFlag = cli.IntFlag{ 65 Name: "memprofilerate", 66 Usage: "Turn on memory profiling with the given rate", 67 Value: runtime.MemProfileRate, 68 } 69 blockprofilerateFlag = cli.IntFlag{ 70 Name: "blockprofilerate", 71 Usage: "Turn on block profiling with the given rate", 72 } 73 cpuprofileFlag = cli.StringFlag{ 74 Name: "cpuprofile", 75 Usage: "Write CPU profile to the given file", 76 } 77 traceFlag = cli.StringFlag{ 78 Name: "trace", 79 Usage: "Write execution trace to the given file", 80 } 81 ) 82 83 // Flags holds all command-line flags required for debugging. 84 var Flags = []cli.Flag{ 85 verbosityFlag, vmoduleFlag, backtraceAtFlag, debugFlag, 86 pprofFlag, pprofAddrFlag, pprofPortFlag, 87 memprofilerateFlag, blockprofilerateFlag, cpuprofileFlag, traceFlag, 88 } 89 90 var glogger *log.GlogHandler 91 92 func init() { 93 usecolor := term.IsTty(os.Stderr.Fd()) && os.Getenv("TERM") != "dumb" 94 output := io.Writer(os.Stderr) 95 if usecolor { 96 output = colorable.NewColorableStderr() 97 } 98 glogger = log.NewGlogHandler(log.StreamHandler(output, log.TerminalFormat(usecolor))) 99 } 100 101 // Setup initializes profiling and logging based on the CLI flags. 102 // It should be called as early as possible in the program. 103 func Setup(ctx *cli.Context) error { 104 // logging 105 log.PrintOrigins(ctx.GlobalBool(debugFlag.Name)) 106 glogger.Verbosity(log.Lvl(ctx.GlobalInt(verbosityFlag.Name))) 107 glogger.Vmodule(ctx.GlobalString(vmoduleFlag.Name)) 108 glogger.BacktraceAt(ctx.GlobalString(backtraceAtFlag.Name)) 109 log.Root().SetHandler(glogger) 110 111 // profiling, tracing 112 runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name) 113 Handler.SetBlockProfileRate(ctx.GlobalInt(blockprofilerateFlag.Name)) 114 if traceFile := ctx.GlobalString(traceFlag.Name); traceFile != "" { 115 if err := Handler.StartGoTrace(traceFile); err != nil { 116 return err 117 } 118 } 119 if cpuFile := ctx.GlobalString(cpuprofileFlag.Name); cpuFile != "" { 120 if err := Handler.StartCPUProfile(cpuFile); err != nil { 121 return err 122 } 123 } 124 125 // pprof server 126 if ctx.GlobalBool(pprofFlag.Name) { 127 // Hook go-metrics into expvar on any /debug/metrics request, load all vars 128 // from the registry into expvar, and execute regular expvar handler. 129 exp.Exp(metrics.DefaultRegistry) 130 131 address := fmt.Sprintf("%s:%d", ctx.GlobalString(pprofAddrFlag.Name), ctx.GlobalInt(pprofPortFlag.Name)) 132 go func() { 133 log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) 134 if err := http.ListenAndServe(address, nil); err != nil { 135 log.Error("Failure in running pprof server", "err", err) 136 } 137 }() 138 } 139 return nil 140 } 141 142 // Exit stops all running profiles, flushing their output to the 143 // respective file. 144 func Exit() { 145 Handler.StopCPUProfile() 146 Handler.StopGoTrace() 147 }