func (ui *tatui) showMessages() { ui.current = uiMessages ui.selectedPane = uiMessages ui.send.BorderLabel = " ✎ Action or New Message " termui.Body.Rows = nil ui.selectedPaneMessages = 0 if len(ui.currentListMessages) == 0 { ui.currentListMessages[0] = nil } if _, ok := ui.uilists[uiTopics]; !ok || len(ui.uilists[uiTopics]) == 0 { ui.msg.Text = "Please select a topic before doing this action" ui.showHome() return } if _, ok := ui.currentFilterMessages[ui.currentTopic.Topic]; !ok { ui.clearFilterOnCurrentTopic() } ui.initMessages() go func() { for { if ui.current != uiMessages { break } mutex.Lock() ui.updateMessages() ui.firstCallMessages = true mutex.Unlock() time.Sleep(5 * time.Second) } }() ui.uilists[uiTopics][0].list.BorderRight = true ui.prepareTopMenu() if len(ui.currentFilterMessages[ui.currentTopic.Topic]) > 1 { // preserve order for k := 0; k < len(ui.currentFilterMessages[ui.currentTopic.Topic]); k++ { termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, ui.uilists[uiMessages][k].list))) } } else { termui.Body.AddRows( termui.NewRow( termui.NewCol(3, 0, ui.uilists[uiTopics][0].list), termui.NewCol(9, 0, ui.uilists[uiMessages][0].list), ), ) } ui.prepareSendRow() ui.colorizedPanes() termui.Clear() ui.render() }
func (t *TerminalUI) AdjustMemory(stats Statistics) { // memory gauges mem := make([]*ui.Gauge, len(stats.Instances)) for i, idx := range stats.Instances { // show max 8 instances if i > 7 { break } memory := uint64(stats.Data[idx].Stats.Usage.Memory) quota := uint64(stats.Data[idx].Stats.MemoryQuota) percent := int(math.Ceil((float64(memory) / float64(quota)) * 100.0)) mem[i] = ui.NewGauge() mem[i].Percent = percent mem[i].Height = 13 - min(len(stats.Instances), 8) mem[i].Border.Label = fmt.Sprintf("Memory - Instance %d: %d%% (%s / %s)", i, percent, bytefmt.ByteSize(memory), bytefmt.ByteSize(quota)) mem[i].Border.FgColor = ui.ColorWhite mem[i].Border.LabelFgColor = ui.ColorWhite mem[i].BarColor = colors[i%6] mem[i].PercentColor = ui.ColorWhite } t.Memory = mem // update layout ui.Body.Rows = []*ui.Row{ ui.NewRow( ui.NewCol(3, 0, t.Usage), ui.NewCol(3, 0, t.Summary), ui.NewCol(6, 0, t.Disk)), ui.NewRow( ui.NewCol(6, 0, t.CPU), t.newMemCol(6, 0, t.Memory)), } }
func main() { err := ui.Init() if err != nil { panic(err) } defer ui.Close() w11 := ui.NewPar("Hello world") w11.Height = 10 w11.Border.Label = "Hello" w11.Border.LabelFgColor = ui.ColorGreen w12 := ui.NewPar("first") w12.Height = 20 w2 := ui.NewPar("second") w2.Height = 20 ui.Body.AddRows( ui.NewRow( ui.NewCol(6, 0, w11), ui.NewCol(6, 0, w12)), ui.NewRow( ui.NewCol(12, 0, w2))) ui.Body.Align() ui.Render(ui.Body) <-ui.EventCh() }
func BuildUI() { ui.Init() defer ui.Close() receiveBox := CreateReceiveBox() sendBox := CreateSendBox() ui.Body.AddRows( ui.NewRow(ui.NewCol(12, 0, receiveBox)), ui.NewRow(ui.NewCol(12, 0, sendBox)), ) ui.Body.Align() ui.Render(ui.Body) ui.Handle("/sys/kbd/C-x", func(e ui.Event) { ui.StopLoop() }) ui.Handle("/timer/1s", func(e ui.Event) { ReceiveBoxHeight = ui.TermHeight() - SendBoxHeight receiveBox.Height = ReceiveBoxHeight ui.Body.Align() ui.Render(ui.Body) }) // Leaving this commented out for now // I'd like to get this method of screen refreshing working instead of the 1s method, // but this crashes on resize. // ui.Handle("/sys/wnd/resize", func(e ui.Event) { // ui.Body.Align() // ui.Render(ui.Body) // }) ui.Loop() }
func (s *Stats) Start() { s.cfUI.Say("Starting Stats...") err := termui.Init() if err != nil { s.cfUI.Warn(err.Error()) return } defer termui.Close() go func() { sinkTypeChart := &charts.SinkTypeChart{} sinkTypeChart.Init(s.cfUI) uaaChart := &charts.UAAChart{} uaaChart.Init(s.cfUI) msgLossChart := &charts.MsgLossChart{} msgLossChart.Init(s.cfUI) notesChart := &charts.NotesChart{} notesChart.Init() s.client.Sift( []charts.Chart{ sinkTypeChart, uaaChart, msgLossChart, }, ) termui.Body.AddRows( termui.NewRow( termui.NewCol(6, 0, sinkTypeChart), termui.NewCol(6, 0, uaaChart), ), termui.NewRow( termui.NewCol(6, 0, msgLossChart), termui.NewCol(6, 0, notesChart), ), ) for { termui.Body.Align() termui.Render(termui.Body) time.Sleep(1 * time.Second) } }() termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Loop() }
func (ui *tatui) prepareTopMenu() { if !strings.Contains(ui.uiTopicCommands[ui.currentTopic.Topic], " /hide-top") { termui.Body.AddRows( termui.NewRow( termui.NewCol(4, 0, ui.header), termui.NewCol(6, 0, ui.msg), termui.NewCol(2, 0, ui.lastRefresh), ), ) } }
// TODO make new widget traffic light // Waiting for canvas from termui func initWidgets() (*ui.List, *ui.Par, *ui.Par, *ui.Par, *ui.Par) { ui.UseTheme("Jenkins Term UI") title := "q to quit - " + *jenkinsUrl if *filter != "" { title += " filter on " + *filter } p := ui.NewPar(title) _, h := tm.Size() p.Height = 3 p.TextFgColor = ui.ColorWhite p.Border.Label = "Go Jenkins Dashboard" p.Border.FgColor = ui.ColorCyan info := ui.NewPar("") info.Height = 3 info.Y = h - 3 info.TextFgColor = ui.ColorWhite info.Border.FgColor = ui.ColorWhite ls := ui.NewList() ls.ItemFgColor = ui.ColorYellow ls.Border.Label = "Jobs" ls.Y = 3 ls.Height = h - 6 width, height := 4, 5 redbox, yellowbox, greenbox := ui.NewPar(""), ui.NewPar(""), ui.NewPar("") redbox.HasBorder, yellowbox.HasBorder, greenbox.HasBorder = false, false, false redbox.Height, yellowbox.Height, greenbox.Height = height, height, height redbox.Width, yellowbox.Width, greenbox.Width = width, width, width redbox.BgColor = ui.ColorRed yellowbox.BgColor = ui.ColorYellow greenbox.BgColor = ui.ColorGreen ui.Body.AddRows( ui.NewRow( ui.NewCol(12, 0, p), ), ui.NewRow( ui.NewCol(10, 0, ls), ui.NewCol(2, 0, redbox, yellowbox, greenbox), ), ui.NewRow( ui.NewCol(12, 0, info), ), ) ui.Body.Align() ui.Render(ui.Body) return ls, info, redbox, yellowbox, greenbox }
func setupBody() { height := termui.TermHeight() - 23 prompt := termui.NewPar("") prompt.Height = 1 prompt.Border = false parMap["prompt"] = prompt input := termui.NewPar("") input.Height = 3 input.BorderLabel = "Input" input.BorderFg = termui.ColorYellow parMap["input"] = input moveHistory := termui.NewPar("") moveHistory.Height = height - 4 moveHistory.BorderLabel = "Move History" moveHistory.BorderFg = termui.ColorBlue parMap["moveHistory"] = moveHistory linesMap["moveHistory"] = NewLines() output := termui.NewPar("") output.Height = height output.BorderLabel = "Output" output.BorderFg = termui.ColorGreen parMap["output"] = output linesMap["output"] = NewLines() board := termui.NewPar("") board.Height = 23 board.Width = 37 board.BorderLabel = "Board" board.BorderFg = termui.ColorRed parMap["board"] = board // build layout termui.Body.AddRows( termui.NewRow( termui.NewCol(6, 0, parMap["prompt"], parMap["input"], parMap["moveHistory"]), termui.NewCol(6, 0, parMap["output"]), ), termui.NewRow( termui.NewCol(12, 0, parMap["board"]), ), ) changeState(0) }
func (m *Monitor) Start(conn *net.Conn) { if err := ui.Init(); err != nil { panic(err) } defer ui.Close() help := ui.NewPar(":PRESS q TO QUIT") help.Height = 3 help.Width = 50 help.TextFgColor = ui.ColorWhite help.BorderLabel = "Help" help.BorderFg = ui.ColorCyan // build ui.Body.AddRows( ui.NewRow( ui.NewCol(6, 0, help), ), ) draw := func(t int) { ui.Body.Align() ui.Render(ui.Body) } draw(0) ui.Handle("/sys/kbd/q", func(ui.Event) { ui.StopLoop() }) ui.Handle("/timer/1s", func(e ui.Event) { t := e.Data.(ui.EvtTimer) draw(int(t.Count)) }) ui.Loop() }
func addSparkLine(serviceName string, titles []string, color ui.Attribute) *ui.Sparklines { var sparkLines []ui.Sparkline for _, title := range titles { sparkLine := ui.NewSparkline() sparkLine.Height = 1 sparkLine.Data = []int{} sparkLine.Title = title sparkLine.TitleColor = titleColor sparkLine.LineColor = color sparkLines = append(sparkLines, sparkLine) } sp := ui.NewSparklines(sparkLines...) sp.Height = 11 sp.BorderLabel = serviceName ui.Body.AddRows( ui.NewRow(ui.NewCol(12, 0, sp)), ) ui.Body.Align() ui.Render(sp) ui.Render(ui.Body) return sp }
func (ui *tatui) showHome() { ui.current = uiHome ui.selectedPane = uiActionBox termui.Body.Rows = nil ui.prepareTopMenu() termui.Body.AddRows( termui.NewRow( termui.NewCol(5, 0, ui.homeLeft), termui.NewCol(7, 0, ui.homeRight), ), ) ui.prepareSendRow() termui.Clear() ui.colorizedPanes() ui.render() }
func main() { err := ui.Init() fmt.Println(daemon.UpSince()) if err != nil { fmt.Println("Could not initialise UI") } defer ui.Close() ut, _ := daemon.Uptime() p := ui.NewPar(ut.String()) p.Height = 3 p.Width = 50 p.TextFgColor = ui.ColorWhite p.Border.Label = "Uptime" p.Border.FgColor = ui.ColorCyan g0 := ui.NewGauge() g0.Percent = 40 g0.Width = 50 g0.Height = 3 g0.Border.Label = "Memory" g0.BarColor = ui.ColorRed g0.Border.FgColor = ui.ColorWhite g0.Border.LabelFgColor = ui.ColorCyan g2 := ui.NewGauge() g2.Percent = 60 g2.Width = 50 g2.Height = 3 g2.PercentColor = ui.ColorBlue g2.Y = 3 g2.Border.Label = "CPU" g2.BarColor = ui.ColorYellow g2.Border.FgColor = ui.ColorWhite ui.Body.AddRows(ui.NewRow(ui.NewCol(6, 0, g0), ui.NewCol(6, 0, p)), ui.NewRow(ui.NewCol(6, 0, g2))) ui.Body.Align() ui.Render(ui.Body) go updateMemCPU(g2, g0) go updateUptime(p) <-ui.EventCh() }
// render Paints the different widgest that compose Lazarus func render(ctx *cli.Context) { err := termui.Init() if err != nil { panic(err) } ui.Title.Label = fmt.Sprintf("*********** %s (%s) ***********", ctx.App.Name, ctx.App.Version) termui.Body.AddRows( termui.NewRow( termui.NewCol(12, 0, ui.Title), ), termui.NewRow( termui.NewCol(12, 0, ui.Songs), ), termui.NewRow( termui.NewCol(6, 0, ui.Quit), ), ) }
func (ui *tatui) prepareSendRow() { if strings.Contains(ui.uiTopicCommands[ui.currentTopic.Topic], " /hide-bottom") { return } if !strings.Contains(ui.uiTopicCommands[ui.currentTopic.Topic], " /hide-top") { termui.Body.AddRows( termui.NewRow( termui.NewCol(12, 0, ui.send), ), ) } else { termui.Body.AddRows( termui.NewRow( termui.NewCol(5, 0, ui.send), termui.NewCol(5, 0, ui.msg), termui.NewCol(2, 0, ui.lastRefresh), ), ) } }
func draw() { display = ui.NewPar("") display.Height = 1 display.Border = false prompt = ui.NewPar(promptMsg) prompt.Height = 1 prompt.Border = false help := ui.NewPar(`:c, :h for profiles; :f to filter; ↓ and ↑ to paginate`) help.Height = 1 help.Border = false help.TextBgColor = ui.ColorBlue help.Bg = ui.ColorBlue help.TextFgColor = ui.ColorWhite gs := ui.Sparkline{} gs.Title = "goroutines" gs.Height = 4 gs.LineColor = ui.ColorCyan ts := ui.Sparkline{} ts.Title = "threads" ts.Height = 4 ts.LineColor = ui.ColorCyan sp = ui.NewSparklines(gs, ts) sp.Height = 10 sp.Border = false ls = ui.NewList() ls.Border = false ui.Body.AddRows( ui.NewRow(ui.NewCol(4, 0, prompt), ui.NewCol(8, 0, help)), ui.NewRow(ui.NewCol(12, 0, sp)), ui.NewRow(ui.NewCol(12, 0, display)), ui.NewRow(ui.NewCol(12, 0, ls)), ) }
func (ui *tatui) showMessage() { ui.current = uiMessage ui.selectedPane = uiMessage ui.send.BorderLabel = " ✎ Action or New Reply " termui.Body.Rows = nil if ui.uilists[uiMessages][ui.selectedPaneMessages].list == nil || ui.uilists[uiMessages][ui.selectedPaneMessages].position < 0 { return } ui.uilists[uiMessage] = make(map[int]*uilist) ui.initMessage() go func() { for { if ui.current != uiMessage { break } mutex.Lock() ui.updateMessage() mutex.Unlock() time.Sleep(5 * time.Second) } }() ui.addMarker(ui.uilists[uiMessage][0], 0) ui.prepareTopMenu() termui.Body.AddRows( termui.NewRow( termui.NewCol(3, 0, ui.uilists[uiTopics][0].list), termui.NewCol(9, 0, ui.uilists[uiMessage][0].list), ), ) ui.prepareSendRow() ui.colorizedPanes() termui.Clear() ui.render() }
func DisplayDiscovering() { p := ui.NewPar("Discovering Pip-Boys") p.Width = 22 p.Height = 3 discoverUi := ui.NewGrid( ui.NewRow( ui.NewCol(4, 4, p), ), ) discoverUi.Width = ui.Body.Width discoverUi.Align() ui.Render(discoverUi) }
func (u Ui) refresh() { grid := termui.NewGrid( termui.NewRow( termui.NewCol(9, 0, u.headerWidget), termui.NewCol(3, 0, u.infoWidget), ), termui.NewRow( termui.NewCol(12, 0, u.feedsWidget), ), ) for _, widget := range u.activeDownloadWidgets { grid.AddRows( termui.NewRow( termui.NewCol(12, 0, widget), ), ) } grid.Width = u.gridWidth grid.Align() termui.Render(grid) }
func (v *ViewEvent) SwitchToView() View { ResetView() statusRow := termui.NewRow( termui.NewCol(12, 0, v.dash.Widget()), ) termui.Body.AddRows( termui.NewRow( termui.NewCol(1, 0, v.mongosWidget.Widget()), termui.NewCol(1, 0, v.replica1Widget.Widget()), ), termui.NewRow( termui.NewCol(1, 0, v.mongosWidget_2.Widget()), termui.NewCol(1, 0, v.replica1Widget_2.Widget()), ), statusRow, ) // calculate layout termui.Body.Align() return v }
func (t *TerminalUI) ScaleApp(appName string, instances int) { // scaling text scaling := ui.NewPar(fmt.Sprintf("\nSCALING [%s] TO [%d] INSTANCES...\n", appName, instances)) scaling.Height = 5 scaling.TextFgColor = ui.ColorYellow scaling.Border.Label = "Scale" scaling.Border.FgColor = ui.ColorRed scaling.Border.LabelFgColor = ui.ColorWhite scaling.Border.LabelBgColor = ui.ColorRed ui.Body.Rows = []*ui.Row{ui.NewRow( ui.NewCol(8, 2, scaling), )} term.Render() }
func (t *TerminalUI) newMemCol(span, offset int, mem []*ui.Gauge) *ui.Row { // soooo ugly.. :( switch len(mem) { case 0: return ui.NewCol(span, offset, nil) case 1: return ui.NewCol(span, offset, mem[0]) case 2: return ui.NewCol(span, offset, mem[0], mem[1]) case 3: return ui.NewCol(span, offset, mem[0], mem[1], mem[2]) case 4: return ui.NewCol(span, offset, mem[0], mem[1], mem[2], mem[3]) case 5: return ui.NewCol(span, offset, mem[0], mem[1], mem[2], mem[3], mem[4]) case 6: return ui.NewCol(span, offset, mem[0], mem[1], mem[2], mem[3], mem[4], mem[5]) case 7: return ui.NewCol(span, offset, mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6]) default: return ui.NewCol(span, offset, mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6], mem[7]) } return nil }
func (ui *tatui) showResult(cmdResult, result string) { ui.current = uiResult ui.send.BorderLabel = " ✎ Action" termui.Body.Rows = nil p := termui.NewPar(`Result of ` + cmdResult + `: ` + result + ` `) p.Height = termui.TermHeight() - uiHeightTop - uiHeightSend p.TextFgColor = termui.ColorWhite p.BorderTop = true ui.prepareTopMenu() termui.Body.AddRows( termui.NewRow( termui.NewCol(12, 0, p), ), ) ui.prepareSendRow() termui.Clear() }
func addSparkLine(serviceName string, data [][]int) *ui.Sparklines { titles := []string{"CPU", "Disk Read", "Disk Write", "Memory", "Net RX", "Net TX"} var sparkLines []ui.Sparkline for i, title := range titles { sparkLine := ui.NewSparkline() sparkLine.Height = 1 sparkLine.Data = data[i] sparkLine.Title = title sparkLines = append(sparkLines, sparkLine) } sp := ui.NewSparklines(sparkLines...) sp.Height = 14 sp.Border.Label = serviceName ui.Body.AddRows( ui.NewRow(ui.NewCol(12, 0, sp)), ) ui.Body.Align() ui.Render(sp) return sp }
func (ui *tatui) showTopics() { ui.current = uiTopics ui.selectedPane = uiTopics ui.send.BorderLabel = " ✎ Action " ui.msg.Text = "tab or enter to select topic" termui.Body.Rows = nil ui.initTopics() ui.updateTopics() go func() { for { if ui.current != uiTopics { break } time.Sleep(10 * time.Second) mutex.Lock() ui.updateTopics() mutex.Unlock() } }() ui.uilists[uiTopics][0].list.BorderRight = false ui.prepareTopMenu() termui.Body.AddRows( termui.NewRow( termui.NewCol(12, 0, ui.uilists[uiTopics][0].list), ), ) ui.prepareSendRow() termui.Clear() ui.colorizedPanes() ui.render() }
func (v *View) SetLayout() { ui.Body.AddRows( ui.NewRow( ui.NewCol(12, 0, v.Header), ), ui.NewRow( ui.NewCol(12, 0, v.InfoBar), ), ui.NewRow( ui.NewCol(12, 0, v.CpuChart), ), ui.NewRow( ui.NewCol(12, 0, v.MemChart), ), ui.NewRow( ui.NewCol(3, 0, v.NameList), ui.NewCol(9, 0, v.InfoList), ), ) }
func main() { //set log file logFileName := "btc.log" logFile, logErr := os.OpenFile(logFileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666) if logErr != nil { fmt.Println("Fail to find", *logFile, "cServer start Failed") return } log.SetOutput(logFile) log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) log.Printf("cpu num %d", runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU()) if err := ui.Init(); err != nil { log.Printf("ui init err : %s", err) return } defer ui.Close() par = ui.NewPar("Last Price") par.Height = 3 par.TextFgColor = ui.ColorWhite par.BorderLabel = "Last Price" infoPar = ui.NewPar("Price Info") infoPar.Height = 3 infoPar.TextFgColor = ui.ColorWhite infoPar.BorderLabel = "Price Info" currentTime := time.Now().Format("2006-01-02 15:04:05") timePar := ui.NewPar(currentTime) timePar.Height = 3 timePar.TextFgColor = ui.ColorYellow timePar.BorderLabel = "Current Time" strItems := []string{} delegateList = ui.NewList() delegateList.Items = strItems delegateList.ItemFgColor = ui.ColorYellow delegateList.BorderLabel = "Delegate List" delegateList.Height = 23 dealList = ui.NewList() dealList.Items = strItems dealList.ItemFgColor = ui.ColorYellow dealList.Height = 23 dealList.BorderLabel = "Deal List" ui.Body.AddRows( ui.NewRow( ui.NewCol(6, 0, par), ui.NewCol(6, 0, timePar))) ui.Body.AddRows( ui.NewRow( ui.NewCol(12, 0, infoPar))) ui.Body.AddRows( ui.NewRow( ui.NewCol(6, 0, delegateList), ui.NewCol(6, 0, dealList))) ui.Body.Align() ui.Render(ui.Body) // websocket connect log.Printf("connecting to %s", url) c, _, err := websocket.DefaultDialer.Dial(url, nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() // message done chan done := make(chan struct{}) exit := func() { err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { log.Printf("write close: %s", err) } else { select { case <-done: case <-time.After(time.Second): } c.Close() } ui.StopLoop() } ui.Handle("/sys/kbd/q", func(ui.Event) { exit() }) ui.Handle("/sys/kbd/p", func(ui.Event) { if !uiPaused { uiPaused = true } else { uiPaused = false } }) ui.Handle("/sys/wnd/resize", func(e ui.Event) { ui.Body.Width = ui.TermWidth() ui.Body.Align() ui.Render(ui.Body) }) ui.Handle("/timer/1s", func(e ui.Event) { currentTime := time.Now().Format("2006-01-02 15:04:05") timePar.Text = currentTime }) go func() { for { //or use message if !uiPaused { time.Sleep(time.Millisecond * 50) ui.Render(ui.Body) } else { time.Sleep(time.Millisecond * 200) } } }() //----------------------- stocket message -------------- msgChan := make(chan []byte) //获取消息 go func() { defer c.Close() defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Printf("read err: %s", err) return } msgChan <- message } }() //订阅消息 sendSubChannel(c) //heart check via pingChan go func() { defer close(pingChan) for { if c.WriteMessage(websocket.TextMessage, []byte("{\"event\": \"ping\"}")); err != nil { log.Printf("send ping message err: %s", err) break } log.Println("send ping message") select { case <-pingChan: log.Println("server is alive") //收到数据 1s 后继续发送心跳 time.Sleep(time.Second) case <-time.After(time.Second * 1): //超时 重新连接 socket reConnectTimes := 0 for { if reConnectTimes > 5 { log.Fatal("websocket connect failed") break } _c, _, err := websocket.DefaultDialer.Dial(url, nil) if err != nil { log.Println("re-connect websocket faild dial:", err) log.Println("after 3s retry connect websocket") reConnectTimes++ time.Sleep(time.Second * 3) } else { log.Println("re-connect websocket success") c = _c sendSubChannel(c) break } } } } }() //开启10个worker 处理消息 for i := 0; i < 10; i++ { go processMessage(msgChan) } //开始阻塞 循环terminal ui ui.Loop() }
// CmdMetrics prints out metrics for a given service or if the service is not // specified, metrics for the entire environment are printed. func CmdMetrics(svcName string, metricType MetricType, jsonFlag, csvFlag, textFlag, sparkFlag, streamFlag bool, mins int, im IMetrics, is services.IServices) error { if sparkFlag { logrus.Warnln("The \"--spark\" flag has been deprecated! Please use \"--csv\", \"--json\", or \"--text\" instead. \"--spark\" will be removed in the next CLI update.") } if streamFlag && (jsonFlag || csvFlag || mins != 1) { return fmt.Errorf("--stream cannot be used with CSV or JSON formats and multiple records") } if mins > 1440 { return fmt.Errorf("--mins cannot be greater than 1440") } var mt Transformer if jsonFlag { mt = &JSONTransformer{} } else if csvFlag { buffer := &bytes.Buffer{} mt = &CSVTransformer{ HeadersWritten: false, GroupMode: false, Buffer: buffer, Writer: csv.NewWriter(buffer), } } else if sparkFlag { // the spark lines interface stays up until closed by the user, so // we might as well keep updating it as long as it is there streamFlag = true mins = 30 err := ui.Init() if err != nil { return err } defer ui.Close() p := ui.NewPar("PRESS q TO QUIT") p.Border = false p2 := ui.NewPar(fmt.Sprintf("%s Usage Metrics", metricsTypeToString(metricType))) p2.Border = false ui.Body.AddRows( ui.NewRow(ui.NewCol(12, 0, p)), ui.NewRow(ui.NewCol(12, 0, p2)), ) ui.Body.Align() ui.Render(ui.Body) mt = &SparkTransformer{ SparkLines: map[string]*ui.Sparklines{}, } } else if textFlag { mt = &TextTransformer{} } if svcName != "" { service, err := is.RetrieveByLabel(svcName) if err != nil { return err } if service == nil { return fmt.Errorf("Could not find a service with the label \"%s\"", svcName) } return CmdServiceMetrics(metricType, streamFlag, sparkFlag, mins, service, mt, im) } return CmdEnvironmentMetrics(metricType, streamFlag, sparkFlag, mins, mt, im) }
// monitor starts a terminal UI based monitoring tool for the requested metrics. func monitor(ctx *cli.Context) { var ( client comms.EthereumClient err error ) // Attach to an Ethereum node over IPC or RPC endpoint := ctx.String(monitorCommandAttachFlag.Name) if client, err = comms.ClientFromEndpoint(endpoint, codec.JSON); err != nil { utils.Fatalf("Unable to attach to geth node: %v", err) } defer client.Close() xeth := rpc.NewXeth(client) // Retrieve all the available metrics and resolve the user pattens metrics, err := retrieveMetrics(xeth) if err != nil { utils.Fatalf("Failed to retrieve system metrics: %v", err) } monitored := resolveMetrics(metrics, ctx.Args()) if len(monitored) == 0 { list := expandMetrics(metrics, "") sort.Strings(list) if len(list) > 0 { utils.Fatalf("No metrics specified.\n\nAvailable:\n - %s", strings.Join(list, "\n - ")) } else { utils.Fatalf("No metrics collected by geth (--%s).\n", utils.MetricsEnabledFlag.Name) } } sort.Strings(monitored) if cols := len(monitored) / ctx.Int(monitorCommandRowsFlag.Name); cols > 6 { utils.Fatalf("Requested metrics (%d) spans more that 6 columns:\n - %s", len(monitored), strings.Join(monitored, "\n - ")) } // Create and configure the chart UI defaults if err := termui.Init(); err != nil { utils.Fatalf("Unable to initialize terminal UI: %v", err) } defer termui.Close() termui.UseTheme("helloworld") rows := len(monitored) if max := ctx.Int(monitorCommandRowsFlag.Name); rows > max { rows = max } cols := (len(monitored) + rows - 1) / rows for i := 0; i < rows; i++ { termui.Body.AddRows(termui.NewRow()) } // Create each individual data chart footer := termui.NewPar("") footer.HasBorder = true footer.Height = 3 charts := make([]*termui.LineChart, len(monitored)) units := make([]int, len(monitored)) data := make([][]float64, len(monitored)) for i := 0; i < len(monitored); i++ { charts[i] = createChart((termui.TermHeight() - footer.Height) / rows) row := termui.Body.Rows[i%rows] row.Cols = append(row.Cols, termui.NewCol(12/cols, 0, charts[i])) } termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, footer))) refreshCharts(xeth, monitored, data, units, charts, ctx, footer) termui.Body.Align() termui.Render(termui.Body) // Watch for various system events, and periodically refresh the charts refresh := time.Tick(time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second) for { select { case event := <-termui.EventCh(): if event.Type == termui.EventKey && event.Key == termui.KeyCtrlC { return } if event.Type == termui.EventResize { termui.Body.Width = termui.TermWidth() for _, chart := range charts { chart.Height = (termui.TermHeight() - footer.Height) / rows } termui.Body.Align() termui.Render(termui.Body) } case <-refresh: if refreshCharts(xeth, monitored, data, units, charts, ctx, footer) { termui.Body.Align() } termui.Render(termui.Body) } } }
func main() { err := ui.Init() if err != nil { panic(err) } defer ui.Close() sinps := (func() []float64 { n := 400 ps := make([]float64, n) for i := range ps { ps[i] = 1 + math.Sin(float64(i)/5) } return ps })() sinpsint := (func() []int { ps := make([]int, len(sinps)) for i, v := range sinps { ps[i] = int(100*v + 10) } return ps })() // ui.UseTheme("helloworld") spark := ui.Sparkline{} spark.Height = 8 spdata := sinpsint spark.Data = spdata[:100] spark.LineColor = ui.ColorCyan spark.TitleColor = ui.ColorWhite sp := ui.NewSparklines(spark) sp.Height = 11 sp.Border.Label = "Sparkline" lc := ui.NewLineChart() lc.Border.Label = "braille-mode Line Chart" lc.Data = sinps lc.Height = 11 lc.AxesColor = ui.ColorWhite lc.LineColor = ui.ColorYellow | ui.AttrBold gs := make([]*ui.Gauge, 3) for i := range gs { gs[i] = ui.NewGauge() gs[i].Height = 2 gs[i].HasBorder = false gs[i].Percent = i * 10 gs[i].PaddingBottom = 1 gs[i].BarColor = ui.ColorRed } ls := ui.NewList() ls.HasBorder = false ls.Items = []string{ "[1] Downloading File 1", "", // == \newline "[2] Downloading File 2", "", "[3] Uploading File 3", } ls.Height = 5 par := ui.NewPar("<> This row has 3 columns\n<- Widgets can be stacked up like left side\n<- Stacked widgets are treated as a single widget") par.Height = 5 par.Border.Label = "Demonstration" // build layout ui.Body.AddRows( ui.NewRow( ui.NewCol(6, 0, sp), ui.NewCol(6, 0, lc)), ui.NewRow( ui.NewCol(3, 0, ls), ui.NewCol(3, 0, gs[0], gs[1], gs[2]), ui.NewCol(6, 0, par))) // calculate layout ui.Body.Align() done := make(chan bool) redraw := make(chan bool) /* update := func() { for i := 0; i < 103; i++ { for _, g := range gs { g.Percent = (g.Percent + 3) % 100 } sp.Lines[0].Data = spdata[:100+i] lc.Data = sinps[2*i:] time.Sleep(time.Second / 2) redraw <- true } done <- true } */ evt := ui.EventCh() ui.Render(ui.Body) // go update() for { select { case e := <-evt: if e.Type == ui.EventKey && e.Ch == 'q' { return } if e.Type == ui.EventResize { ui.Body.Width = ui.TermWidth() ui.Body.Align() go func() { redraw <- true }() } case <-done: return case <-redraw: ui.Render(ui.Body) } } }
func main() { configFile := flag.String("config", "config.json", "Configuration file") flag.Parse() monitors := readConfig(*configFile) updates := make(chan monitor.CheckUpdate) logbuf := new(bytes.Buffer) log.SetOutput(logbuf) err := termui.Init() if err != nil { log.Fatalf("Unable to init termui: %v\n", err) } defer termui.Close() list := termui.NewList() var urls []string for _, m := range monitors { e := fmt.Sprintf("[%v] %v", m.index, m.monitor.Source()) urls = append(urls, e) if list.Width < int(float64(len(e))*float64(1.5)) { list.Width = int(float64(len(e)) * float64(1.5)) } } list.Items = urls list.ItemFgColor = termui.ColorYellow list.BorderLabel = "URLs" list.Height = 8 list.Y = 0 list.X = 0 sp := termui.NewSparklines() sp.BorderLabel = "Response times" sp.Y = list.Height sp.X = 0 sp.Height = list.Height for i, _ := range urls { spark := termui.Sparkline{} spark.Height = 1 spark.Title = fmt.Sprintf("URL %v", i) spark.LineColor = termui.ColorCyan spark.TitleColor = termui.ColorYellow sp.Add(spark) } logPar := termui.NewPar(logbuf.String()) logPar.Height = 20 termui.Body.AddRows( termui.NewRow( termui.NewCol(6, 0, list), termui.NewCol(6, 0, sp)), termui.NewRow( termui.NewCol(12, 0, logPar))) termui.Body.Align() for _, m := range monitors { go m.monitor.Check(updates, m.index) } loop: for { select { case u := <-updates: if u.Healthy && u.Err == nil { sp.Lines[u.Id].LineColor = COLOR_OK } else { sp.Lines[u.Id].LineColor = COLOR_KO } case <-time.After(2 * time.Second): break loop } } termui.Render(termui.Body) termui.Handle("/sys/kbd/q", func(termui.Event) { termui.StopLoop() }) termui.Handle("/timer/1s", func(e termui.Event) { t := e.Data.(termui.EvtTimer) if t.Count%5 == 0 { for _, m := range monitors { go m.monitor.Check(updates, m.index) } loop: for { select { case u := <-updates: sp.Lines[u.Id].Data = append(sp.Lines[u.Id].Data, int(u.Duration)) if u.Healthy && u.Err == nil { sp.Lines[u.Id].LineColor = COLOR_OK } else { sp.Lines[u.Id].LineColor = COLOR_KO } case <-time.After(2 * time.Second): break loop } } logPar.Text = logbuf.String() termui.Render(termui.Body) } }) termui.Loop() }