github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/internal/debug/flags.go (about) 1 // Copyright 2016 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum 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/SmartMeshFoundation/Spectrum/log" 28 "github.com/SmartMeshFoundation/Spectrum/log/term" 29 colorable "github.com/mattn/go-colorable" 30 "gopkg.in/urfave/cli.v1" 31 ) 32 33 var ( 34 verbosityFlag = cli.IntFlag{ 35 Name: "verbosity", 36 Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail", 37 Value: 3, 38 } 39 vmoduleFlag = cli.StringFlag{ 40 Name: "vmodule", 41 Usage: "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=5,p2p=4)", 42 Value: "", 43 } 44 backtraceAtFlag = cli.StringFlag{ 45 Name: "backtrace", 46 Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", 47 Value: "", 48 } 49 debugFlag = cli.BoolFlag{ 50 Name: "debug", 51 Usage: "Prepends log messages with call-site location (file and line number)", 52 } 53 pprofFlag = cli.BoolFlag{ 54 Name: "pprof", 55 Usage: "Enable the pprof HTTP server", 56 } 57 pprofPortFlag = cli.IntFlag{ 58 Name: "pprofport", 59 Usage: "pprof HTTP server listening port", 60 Value: 6060, 61 } 62 pprofAddrFlag = cli.StringFlag{ 63 Name: "pprofaddr", 64 Usage: "pprof HTTP server listening interface", 65 Value: "127.0.0.1", 66 } 67 memprofilerateFlag = cli.IntFlag{ 68 Name: "memprofilerate", 69 Usage: "Turn on memory profiling with the given rate", 70 Value: runtime.MemProfileRate, 71 } 72 blockprofilerateFlag = cli.IntFlag{ 73 Name: "blockprofilerate", 74 Usage: "Turn on block profiling with the given rate", 75 } 76 cpuprofileFlag = cli.StringFlag{ 77 Name: "cpuprofile", 78 Usage: "Write CPU profile to the given file", 79 } 80 traceFlag = cli.StringFlag{ 81 Name: "trace", 82 Usage: "Write execution trace to the given file", 83 } 84 ) 85 86 // Flags holds all command-line flags required for debugging. 87 var Flags = []cli.Flag{ 88 verbosityFlag, 89 vmoduleFlag, 90 backtraceAtFlag, 91 debugFlag, 92 pprofFlag, 93 pprofAddrFlag, 94 pprofPortFlag, 95 memprofilerateFlag, blockprofilerateFlag, cpuprofileFlag, traceFlag, 96 } 97 98 var glogger *log.GlogHandler 99 100 func init() { 101 usecolor := term.IsTty(os.Stderr.Fd()) && os.Getenv("TERM") != "dumb" 102 output := io.Writer(os.Stderr) 103 if usecolor { 104 output = colorable.NewColorableStderr() 105 } 106 glogger = log.NewGlogHandler(log.StreamHandler(output, log.TerminalFormat(usecolor))) 107 } 108 109 // Setup initializes profiling and logging based on the CLI flags. 110 // It should be called as early as possible in the program. 111 func Setup(ctx *cli.Context) error { 112 // logging 113 log.PrintOrigins(ctx.GlobalBool(debugFlag.Name)) 114 glogger.Verbosity(log.Lvl(ctx.GlobalInt(verbosityFlag.Name))) 115 glogger.Vmodule(ctx.GlobalString(vmoduleFlag.Name)) 116 glogger.BacktraceAt(ctx.GlobalString(backtraceAtFlag.Name)) 117 log.Root().SetHandler(glogger) 118 119 // profiling, tracing 120 runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name) 121 Handler.SetBlockProfileRate(ctx.GlobalInt(blockprofilerateFlag.Name)) 122 if traceFile := ctx.GlobalString(traceFlag.Name); traceFile != "" { 123 if err := Handler.StartGoTrace(traceFile); err != nil { 124 return err 125 } 126 } 127 if cpuFile := ctx.GlobalString(cpuprofileFlag.Name); cpuFile != "" { 128 if err := Handler.StartCPUProfile(cpuFile); err != nil { 129 return err 130 } 131 } 132 133 // pprof server 134 if ctx.GlobalBool(pprofFlag.Name) { 135 address := fmt.Sprintf("%s:%d", ctx.GlobalString(pprofAddrFlag.Name), ctx.GlobalInt(pprofPortFlag.Name)) 136 go func() { 137 log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) 138 if err := http.ListenAndServe(address, nil); err != nil { 139 log.Error("Failure in running pprof server", "err", err) 140 } 141 }() 142 } 143 return nil 144 } 145 146 // Exit stops all running profiles, flushing their output to the 147 // respective file. 148 func Exit() { 149 Handler.StopCPUProfile() 150 Handler.StopGoTrace() 151 }