You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.3 KiB

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