github.com/evdatsion/aphelion-dpos-bft@v0.32.1/tools/tm-monitor/ton.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "text/tabwriter" 8 "time" 9 10 monitor "github.com/evdatsion/aphelion-dpos-bft/tools/tm-monitor/monitor" 11 ) 12 13 const ( 14 // Default refresh rate - 200ms 15 defaultRefreshRate = time.Millisecond * 200 16 ) 17 18 // Ton - table of nodes. 19 // 20 // It produces the unordered list of nodes and updates it periodically. 21 // 22 // Default output is stdout, but it could be changed. Note if you want for 23 // refresh to work properly, output must support [ANSI escape 24 // codes](http://en.wikipedia.org/wiki/ANSI_escape_code). 25 // 26 // Ton was inspired by [Linux top 27 // program](https://en.wikipedia.org/wiki/Top_(software)) as the name suggests. 28 type Ton struct { 29 monitor *monitor.Monitor 30 31 RefreshRate time.Duration 32 Output io.Writer 33 quit chan struct{} 34 } 35 36 func NewTon(m *monitor.Monitor) *Ton { 37 return &Ton{ 38 RefreshRate: defaultRefreshRate, 39 Output: os.Stdout, 40 quit: make(chan struct{}), 41 monitor: m, 42 } 43 } 44 45 func (o *Ton) Start() { 46 clearScreen(o.Output) 47 o.Print() 48 go o.refresher() 49 } 50 51 func (o *Ton) Print() { 52 moveCursor(o.Output, 1, 1) 53 o.printHeader() 54 fmt.Println() 55 o.printTable() 56 } 57 58 func (o *Ton) Stop() { 59 close(o.quit) 60 } 61 62 func (o *Ton) printHeader() { 63 n := o.monitor.Network 64 fmt.Fprintf(o.Output, "%v up %.2f%%\n", n.StartTime(), n.Uptime()) 65 fmt.Println() 66 fmt.Fprintf(o.Output, "Height: %d\n", n.Height) 67 fmt.Fprintf(o.Output, "Avg block time: %.3f ms\n", n.AvgBlockTime) 68 fmt.Fprintf(o.Output, "Avg tx throughput: %.0f per sec\n", n.AvgTxThroughput) 69 fmt.Fprintf(o.Output, "Avg block latency: %.3f ms\n", n.AvgBlockLatency) 70 fmt.Fprintf(o.Output, "Active nodes: %d/%d (health: %s) Validators: %d\n", n.NumNodesMonitoredOnline, n.NumNodesMonitored, n.GetHealthString(), n.NumValidators) 71 } 72 73 func (o *Ton) printTable() { 74 w := tabwriter.NewWriter(o.Output, 0, 0, 5, ' ', 0) 75 fmt.Fprintln(w, "NAME\tHEIGHT\tBLOCK LATENCY\tONLINE\tVALIDATOR\t") 76 for _, n := range o.monitor.Nodes { 77 fmt.Fprintln(w, fmt.Sprintf("%s\t%d\t%.3f ms\t%v\t%v\t", n.Name, n.Height, n.BlockLatency, n.Online, n.IsValidator)) 78 } 79 w.Flush() 80 } 81 82 // Internal loop for refreshing 83 func (o *Ton) refresher() { 84 for { 85 select { 86 case <-o.quit: 87 return 88 case <-time.After(o.RefreshRate): 89 o.Print() 90 } 91 } 92 } 93 94 func clearScreen(w io.Writer) { 95 fmt.Fprint(w, "\033[2J") 96 } 97 98 func moveCursor(w io.Writer, x int, y int) { 99 fmt.Fprintf(w, "\033[%d;%dH", x, y) 100 }