github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/cmd/geth/log_display_dash.go (about) 1 // --- 2 //┌Import | local_head ◼ n=5047652 ⬡=0x33f6878a… txs=1 time=21s ago──────────────────────────────────┐ 3 //│ │ 4 //└──────────────────────────────────────────────────────────────────────────────────────────────────┘ 5 //┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 6 //│n=5047652] ∆ blks=1 (inserted_at=2017-12-19 09:51:35 -0600 CST took=23ms) │ 7 //│ │ 8 //│ │ 9 //│ │ 10 //│n=5047652] ∑ mgas= 0/ 1blks │ 11 //│ │ 12 //│ │ 13 //│ │ 14 //│n=5047652] ∑ txs= 1/ 1blks │ 15 //│ ▃ ▆ ▅ ▇ │ 16 //│ ▃ ▁ ▁ ▂ ▄ ▆ ▁▂ ▄ ▃ ▅ ▁ ▁ ▇▆ ▂ │ 17 //│▁▇ ▃ ▆ ▁▁▁ ▁ ▂ ▂▁▂▂▆▂▁▁▁ ▁▄▁ ▃▁▂▅▇ ▅ ▄ ▁ ▂ ▆ ▂▄▇ ▁ ▁ ▃▅▄▇▃ ▃ ▃ ▂ ▁ ▁▁│ 18 //│ │ 19 //└──────────────────────────────────────────────────────────────────────────────────────────────────┘ 20 //┌Peers (13 / 25)───────────────────────────────────────────────────────────────────────────────────┐ 21 //│ │ 22 //│ │ 23 //│ │ 24 //│ │ 25 //│ │ 26 //│ │ 27 // 28 //│Peer id=5701cea16e32cb06 eth/63 [Parity/v1.7.9-stable-12940e4-20171113/x86_64-linux-gnu/rustc1.21…│ 29 //│Peer id=8310b1f98b9b7afe eth/63 [Parity/v1.7.0-unstable-5f2cabd-20170727/x86_64-linux-gnu/rustc1.…│ 30 //│Peer id=5fbfb426fbb46f8b eth/63 [Parity/v1.7.7-stable-eb7c648-20171015/x86_64-linux-gnu/rustc1.20…│ 31 //│Peer id=1922bfd2acc1e82f eth/63 [Parity/v1.8.2-beta-1b6588c-20171025/x86_64-linux-gnu/rustc1.21.0…│ 32 //│Peer id=8ed199326f981ae9 eth/63 [Parity/v1.8.0-beta-9882902-20171015/x86_64-linux-gnu/rustc1.20.0…│ 33 //│Peer id=c89d548e2a55d324 eth/63 [Parity/v1.8.2-beta-1b6588c-20171025/x86_64-linux-gnu/rustc1.21.0…│ 34 //│Peer id=13c960f1da9a6337 eth/63 [Parity/v1.8.4-beta-c74c8c1-20171211/x86_64-linux-gnu/rustc1.22.1…│ 35 //│Peer id=021eb56de4a7b725 eth/63 [Parity/v1.6.9-stable-d44b008-20170716/x86_64-linux-gnu/rustc1.18…│ 36 //│Peer id=385ffdfb7f7cd2f5 eth/63 [Geth/v4.0.0/windows/go1.8] [hs 0.00/s, bs 0.00/s, rs 0.00/s, ss …│ 37 //│Peer id=d5a5d20cb8b77e14 eth/63 [Parity/v1.8.2-beta-1b6588c-20171025/x86_64-linux-gnu/rustc1.21.0…│ 38 //│Peer id=5f259d71e80f710b eth/63 [Parity/v1.7.9-stable-12940e4-20171113/x86_64-linux-gnu/rustc1.21…│ 39 //│Peer id=e7f3c98896581fee eth/63 [Parity/v1.7.9-unstable-12940e4-20171113/x86_64-linux-gnu/rustc1.…│ 40 //│Peer id=cb0e1d693f950573 eth/63 [Parity/v1.7.10-stable-3931713-20171211/x86_64-linux-gnu/rustc1.2…│ 41 //│ │ 42 //│ │ 43 //└──────────────────────────────────────────────────────────────────────────────────────────────────┘ 44 // --- 45 46 package main 47 48 import ( 49 "fmt" 50 "time" 51 52 "github.com/ethereumproject/go-ethereum/core" 53 "github.com/ethereumproject/go-ethereum/eth" 54 "github.com/ethereumproject/go-ethereum/logger" 55 "github.com/ethereumproject/go-ethereum/logger/glog" 56 "github.com/ethereumproject/go-ethereum/metrics" 57 "github.com/gizak/termui" 58 "gopkg.in/urfave/cli.v1" 59 ) 60 61 const ( 62 tuiHeaderHeight = 2 63 tuiHeaderStart = 1 64 tuiSmallHeight = 3 65 tuiMediumHeight = 5 66 tuiLargeHeight = 8 67 tuiSmallWidth = 20 68 tuiMediumWidth = 50 69 tuiLargeWidth = 100 70 71 tuiSpaceHeight = 1 72 73 tuiDataLimit = 100 74 ) 75 76 var ( 77 headerInfo *termui.Par 78 syncheightGauge *termui.Gauge 79 80 peerCountSpark termui.Sparkline 81 peerCountSparkHolder *termui.Sparklines 82 83 peerList *termui.List 84 peerListData []string 85 86 mgasSpark termui.Sparkline 87 txsSpark termui.Sparkline 88 blkSpark termui.Sparkline 89 blkMgasTxsSparkHolder *termui.Sparklines 90 ) 91 92 func tuiDrawDash(e *eth.Ethereum) { 93 if currentMode == lsModeImport || currentMode == lsModeDiscover { 94 syncheightGauge.Label = "" 95 } 96 if e != nil && e.IsListening() { 97 cb := e.BlockChain().GetBlockByNumber(currentBlockNumber) 98 cid := e.ChainConfig().GetChainID() 99 cnet := e.NetVersion() 100 cname := "" 101 if id := core.GetCacheChainIdentity(); id != "" { 102 cname = id 103 } 104 headerInfo.Text = fmt.Sprintf(" Mode=%s Chain=%v(%d) Chain Id=%d \n"+ 105 " local_head ◼ n=%d ⬡=%s txs=%d time=%v ago", 106 currentMode, cname, cnet, cid, currentBlockNumber, cb.Hash().Hex()[:10]+"…", cb.Transactions().Len(), 107 time.Since(time.Unix(cb.Time().Int64(), 0)).Round(time.Second)) 108 syncheightGauge.BorderLabel = fmt.Sprintf("Sync") 109 110 } 111 termui.Render(headerInfo, syncheightGauge, peerCountSparkHolder, peerList, blkMgasTxsSparkHolder) 112 } 113 114 func tuiSetupDashComponents() { 115 116 /// Config Info Header 117 headerInfo = termui.NewPar("") 118 headerInfo.Height = tuiHeaderHeight 119 headerInfo.Border = false 120 headerInfo.X = tuiHeaderStart 121 headerInfo.TextBgColor = termui.ColorWhite 122 headerInfo.TextFgColor = termui.ColorBlack 123 headerInfo.SetWidth(termui.TermWidth() - 1) 124 //// Sync height gauge 125 syncheightGauge = termui.NewGauge() 126 syncheightGauge.Percent = 0 127 syncheightGauge.BarColor = termui.ColorRed 128 syncheightGauge.Height = tuiSmallHeight 129 syncheightGauge.Width = tuiLargeWidth 130 syncheightGauge.Y = tuiHeaderHeight + 1 131 //// Mgas spark 132 mgasSpark = termui.Sparkline{} 133 mgasSpark.Title = "Mgas" 134 mgasSpark.Data = []int{} 135 mgasSpark.Height = tuiSmallHeight 136 mgasSpark.LineColor = termui.ColorYellow 137 //// Txs spark 138 txsSpark = termui.Sparkline{} 139 txsSpark.Title = "Txs" 140 txsSpark.Data = []int{} 141 txsSpark.Height = tuiSmallHeight 142 txsSpark.LineColor = termui.ColorMagenta 143 //// Blk spark 144 blkSpark = termui.Sparkline{} 145 blkSpark.Title = "Blks" 146 blkSpark.Data = []int{} 147 blkSpark.Height = tuiSmallHeight 148 blkSpark.LineColor = termui.ColorGreen 149 //// MgasTxs spark holder 150 blkMgasTxsSparkHolder = termui.NewSparklines(blkSpark, mgasSpark, txsSpark) 151 blkMgasTxsSparkHolder.Height = mgasSpark.Height + txsSpark.Height + blkSpark.Height + tuiSpaceHeight*6 152 blkMgasTxsSparkHolder.Width = syncheightGauge.Width 153 blkMgasTxsSparkHolder.Y = syncheightGauge.Y + syncheightGauge.Height 154 blkMgasTxsSparkHolder.X = syncheightGauge.X 155 156 //// Peer count spark 157 peerCountSpark = termui.Sparkline{} 158 peerCountSpark.LineColor = termui.ColorBlue 159 peerCountSpark.Data = []int{0} 160 peerCountSpark.Height = tuiMediumHeight 161 //// Peer count spark holder 162 peerCountSparkHolder = termui.NewSparklines(peerCountSpark) 163 peerCountSparkHolder.BorderLabel = "Peers (0) | Bytes (0 rx / 0 tx) | Mean Rate (0 rx / 0 tx)" 164 peerCountSparkHolder.BorderLabelFg = termui.ColorBlue 165 peerCountSparkHolder.BorderBottom = false 166 peerCountSparkHolder.X = 0 167 peerCountSparkHolder.Y = blkMgasTxsSparkHolder.Y + blkMgasTxsSparkHolder.Height 168 peerCountSparkHolder.Height = tuiMediumHeight + tuiSpaceHeight*3 169 peerCountSparkHolder.Width = syncheightGauge.Width 170 171 //// Peer list 172 peerList = termui.NewList() 173 peerList.Items = peerListData 174 peerList.X = 0 175 peerList.Y = peerCountSparkHolder.Y + peerCountSparkHolder.Height 176 peerList.Width = peerCountSparkHolder.Width 177 peerList.Height = tuiLargeHeight * 2 178 peerList.BorderTop = false 179 } 180 181 func addDataWithLimit(sl []int, dataPoint int, maxLen int) []int { 182 if len(sl) > maxLen { 183 sl = append(sl[1:], dataPoint) 184 return sl 185 } 186 sl = append(sl, dataPoint) 187 return sl 188 } 189 190 // dashDisplaySystem is an experimental display system intended as a proof of concept for the display dispatch system 191 var dashDisplaySystem = displayEventHandlers{ 192 { 193 eventT: logEventBefore, 194 handlers: displayEventHandlerFns{ 195 func(ctx *cli.Context, e *eth.Ethereum, evData interface{}, tickerInterval time.Duration) { 196 // Disable display logging. 197 d := glog.GetDisplayable() 198 glog.SetD(0) 199 go func() { 200 // Reset display logs. 201 defer glog.SetD(int(*d)) 202 203 err := termui.Init() 204 if err != nil { 205 panic(err) 206 } 207 tuiSetupDashComponents() 208 tuiSetupHandlers() 209 if currentBlockNumber == 0 { 210 _, c, _, _, _ := e.Downloader().Progress() 211 currentBlockNumber = c 212 } 213 tuiDrawDash(e) 214 215 termui.Loop() 216 }() 217 }, 218 }, 219 }, 220 { 221 eventT: logEventCoreChainInsert, 222 ev: core.ChainInsertEvent{}, 223 handlers: displayEventHandlerFns{ 224 func(ctx *cli.Context, e *eth.Ethereum, evData interface{}, tickerInterval time.Duration) { 225 switch d := evData.(type) { 226 case core.ChainInsertEvent: 227 localheight := d.LastNumber 228 _, head, syncheight, _, _ := e.Downloader().Progress() 229 if head > localheight { 230 localheight = head 231 } 232 syncheightGauge.Percent = int(calcPercent(localheight, syncheight)) 233 234 if localheight >= syncheight { 235 syncheightGauge.Label = fmt.Sprintf("%d", localheight) 236 syncheightGauge.BarColor = termui.ColorGreen 237 } else { 238 syncheightGauge.Label = fmt.Sprintf("%d / %d", localheight, syncheight) 239 syncheightGauge.BarColor = termui.ColorRed 240 } 241 242 if currentBlockNumber != 0 { 243 b := e.BlockChain().GetBlockByNumber(localheight) 244 if b == nil { 245 return 246 } 247 blks, txs, mgas := calcBlockDiff(e, currentBlockNumber, b) 248 // blk 249 blkMgasTxsSparkHolder.Lines[0].Data = addDataWithLimit(blkMgasTxsSparkHolder.Lines[0].Data, blks, tuiDataLimit) 250 blkMgasTxsSparkHolder.Lines[0].Title = fmt.Sprintf("n=%d] ∆ blks=%d (inserted_at=%v took=%v)", localheight, blks, time.Now().Round(time.Second), d.Elasped.Round(time.Millisecond)) 251 // mgas 252 blkMgasTxsSparkHolder.Lines[1].Data = addDataWithLimit(blkMgasTxsSparkHolder.Lines[1].Data, mgas, tuiDataLimit) 253 blkMgasTxsSparkHolder.Lines[1].Title = fmt.Sprintf("n=%d] ∑ mgas=%2d/%4dblks", localheight, mgas, blks) 254 // txs 255 blkMgasTxsSparkHolder.Lines[2].Data = addDataWithLimit(blkMgasTxsSparkHolder.Lines[2].Data, txs, tuiDataLimit) 256 blkMgasTxsSparkHolder.Lines[2].Title = fmt.Sprintf("n=%d] ∑ txs=%3d/%4dblks", localheight, txs, blks) 257 } 258 currentBlockNumber = localheight 259 tuiDrawDash(e) 260 default: 261 panic(d) 262 } 263 }, 264 }, 265 }, 266 { 267 eventT: logEventAfter, 268 handlers: displayEventHandlerFns{ 269 func(ctx *cli.Context, e *eth.Ethereum, evData interface{}, tickerInterval time.Duration) { 270 termui.StopLoop() 271 termui.Close() 272 return 273 274 }, 275 }, 276 }, 277 { 278 eventT: logEventInterval, 279 handlers: displayEventHandlerFns{ 280 func(ctx *cli.Context, e *eth.Ethereum, evData interface{}, tickerInterval time.Duration) { 281 rxP2P := metrics.P2PInBytes 282 txP2P := metrics.P2POutBytes 283 rxBytes := rxP2P.Count() 284 txByes := txP2P.Count() 285 rxRateMean := rxP2P.RateMean() 286 txRateMean := txP2P.RateMean() 287 peers := e.Downloader().GetPeers() 288 peerCountSparkHolder.Lines[0].Data = addDataWithLimit(peerCountSparkHolder.Lines[0].Data, int(peers.Len()), tuiDataLimit) 289 peerCountSparkHolder.BorderLabel = fmt.Sprintf("Peers (%d / %d) | Bytes (%d rx / %d tx) | Mean Rate (%.2f rx / %.2f tx)", 290 int(peers.Len()), ctx.GlobalInt(aliasableName(MaxPeersFlag.Name, ctx)), rxBytes, txByes, rxRateMean, txRateMean) 291 peerListData = []string{} 292 for _, p := range peers.AllPeers() { 293 peerListData = append(peerListData, p.String()) 294 } 295 peerList.Items = peerListData 296 tuiDrawDash(e) 297 }, 298 }, 299 }, 300 } 301 302 func tuiSetupHandlers() { 303 termui.Handle("interrupt", func(tue termui.Event) { 304 glog.V(logger.Error).Errorln("interrupt 1") 305 termui.StopLoop() 306 termui.Close() 307 }) 308 termui.Handle("/interrupt", func(tue termui.Event) { 309 glog.V(logger.Error).Errorln("interrupt 2") 310 termui.StopLoop() 311 termui.Close() 312 }) 313 termui.Handle("/sys/interrupt", func(tue termui.Event) { 314 glog.V(logger.Error).Errorln("interrupt 3") 315 termui.StopLoop() 316 termui.Close() 317 }) 318 termui.Handle("/sys/kbd/C-c", func(tue termui.Event) { 319 glog.V(logger.Error).Errorln("/sys/kbd/C-c") 320 termui.StopLoop() 321 termui.Close() 322 }) 323 termui.Handle("/sys/kbd/C-x", func(tue termui.Event) { 324 glog.V(logger.Error).Errorln("/sys/kbd/C-x") 325 termui.StopLoop() 326 termui.Close() 327 }) 328 termui.Handle("/sys/kbd/C-z", func(tue termui.Event) { 329 glog.V(logger.Error).Errorln("/sys/kbd/C-z") 330 termui.StopLoop() 331 termui.Close() 332 }) 333 termui.Handle("/sys/kbd/q", func(tue termui.Event) { 334 glog.V(logger.Error).Errorln("/sys/kbd/q") 335 termui.StopLoop() 336 termui.Close() 337 }) 338 termui.Handle("/sys/kbd/r", func(tue termui.Event) { 339 // Just check for len > 1 for an arbitrary set because they're all updated simultaneously. 340 // This is also a totally opinionated and convenience thing. 341 if len(blkMgasTxsSparkHolder.Lines[0].Data) > 1 { 342 blkMgasTxsSparkHolder.Lines[0].Data = blkMgasTxsSparkHolder.Lines[0].Data[1:] 343 blkMgasTxsSparkHolder.Lines[1].Data = blkMgasTxsSparkHolder.Lines[1].Data[1:] 344 blkMgasTxsSparkHolder.Lines[2].Data = blkMgasTxsSparkHolder.Lines[2].Data[1:] 345 } 346 }) 347 }