(buf io.Writer, nodes []*observerpb.Node)
| 88 | } |
| 89 | |
| 90 | func nodeTableOutput(buf io.Writer, nodes []*observerpb.Node) error { |
| 91 | tw := tabwriter.NewWriter(buf, 2, 0, 3, ' ', 0) |
| 92 | fmt.Fprint(tw, "NAME\tSTATUS\tAGE\tFLOWS/S\tCURRENT/MAX-FLOWS") |
| 93 | if listOpts.output == "wide" { |
| 94 | fmt.Fprint(tw, "\tVERSION\tADDRESS\tTLS") |
| 95 | } |
| 96 | fmt.Fprintln(tw) |
| 97 | |
| 98 | for _, n := range nodes { |
| 99 | age := notAvailable |
| 100 | flowsPerSec := notAvailable |
| 101 | if uptime := time.Duration(n.GetUptimeNs()).Round(time.Second); uptime > 0 { |
| 102 | age = uptime.String() |
| 103 | flowsPerSec = fmt.Sprintf("%.2f", float64(n.GetSeenFlows())/uptime.Seconds()) |
| 104 | } |
| 105 | flowsRatio := notAvailable |
| 106 | if maxFlows := n.GetMaxFlows(); maxFlows > 0 { |
| 107 | flowsRatio = fmt.Sprintf("%d/%d (%6.2f%%)", n.GetNumFlows(), maxFlows, (float64(n.GetNumFlows())/float64(maxFlows))*100) |
| 108 | } |
| 109 | version := notAvailable |
| 110 | if v := n.GetVersion(); v != "" { |
| 111 | version = v |
| 112 | } |
| 113 | fmt.Fprint(tw, n.GetName(), "\t", strings.Title(nodeStateToString(n.GetState())), "\t", age, "\t", flowsPerSec, "\t", flowsRatio) |
| 114 | if listOpts.output == "wide" { |
| 115 | tls := notAvailable |
| 116 | if t := n.GetTls(); t != nil { |
| 117 | tls = "Disabled" |
| 118 | if t.GetEnabled() { |
| 119 | tls = "Enabled" |
| 120 | } |
| 121 | } |
| 122 | fmt.Fprint(tw, "\t", version, "\t", n.GetAddress(), "\t", tls) |
| 123 | } |
| 124 | fmt.Fprintln(tw) |
| 125 | } |
| 126 | return tw.Flush() |
| 127 | } |
| 128 | |
| 129 | func nodeStateToString(state relaypb.NodeState) string { |
| 130 | switch state { |
searching dependent graphs…