Beispiel #1
0
func (this *TopBroker) drawDashboard() {
	termui.Init()
	width := termui.TermWidth()
	height := termui.TermHeight()
	termui.Close()
	maxWidth := width - 23

	var totalMaxQps, totalMaxBrokerQps float64
	for {
		time.Sleep(this.interval)

		this.startAll()
		this.collectAll()

		datas, maxQps, totalQps := this.showAndResetCounters()
		if maxQps < 1 {
			// draw empty lines
			for _, data := range datas {
				this.Ui.Output(fmt.Sprintf("%20s", data.host))
			}

			continue
		}

		if maxQps > totalMaxBrokerQps {
			totalMaxBrokerQps = maxQps
		}
		if totalQps > totalMaxQps {
			totalMaxQps = totalQps
		}

		refreshScreen()

		for idx, data := range datas {
			if idx >= height-2 {
				break
			}

			if data.qps < 0 {
				panic("negative qps")
			}

			this.renderQpsRow(data.host, data.qps, maxQps, maxWidth)
		}

		this.Ui.Output(fmt.Sprintf("%20s brokers:%d total:%s cum max[broker:%.1f total:%.1f]",
			"-SUMMARY-",
			len(datas), color.Green("%.1f", totalQps), totalMaxBrokerQps, totalMaxQps))
	}

}
Beispiel #2
0
func (this *Redis) runTop(zkzone *zk.ZkZone, interval time.Duration) {
	termui.Init()
	this.mainScreen = true
	this.w, this.h = termbox.Size()
	this.rows = this.h - 3 // head,max/total
	if this.batchMode {
		termbox.Close()
	} else {
		defer termui.Close()

		termbox.SetInputMode(termbox.InputEsc | termbox.InputMouse)
		eventChan := make(chan termbox.Event, 16)
		go this.handleEvents(eventChan)
		go func() {
			for {
				ev := termbox.PollEvent()
				eventChan <- ev
			}
		}()

		this.drawSplash()
	}

	this.topInfos = make([]redisTopInfo, 0, 100)
	this.topInfos1 = make([]redisTopInfo, 0, 100)
	for {
		var wg sync.WaitGroup

		this.mu.Lock()
		this.topInfos1 = this.topInfos1[:0]
		freezedPorts := make(map[string]struct{})

		// clone freezedPorts to avoid concurrent map access
		if len(this.freezedPorts) > 0 {
			for port, _ := range this.freezedPorts {
				freezedPorts[port] = struct{}{}
			}
		}
		this.mu.Unlock()

		for _, hostPort := range zkzone.AllRedis() {
			host, port, err := net.SplitHostPort(hostPort)
			if err != nil {
				log.Error("invalid redis instance: %s", hostPort)
				continue
			}

			if len(this.ports) > 0 {
				if _, present := this.ports[port]; !present {
					continue
				}
			}
			if len(freezedPorts) > 0 {
				if _, present := freezedPorts[port]; !present {
					continue
				}
			}

			nport, err := strconv.Atoi(port)
			if err != nil || nport < 0 {
				log.Error("invalid redis instance: %s", hostPort)
				continue
			}

			wg.Add(1)
			go this.updateRedisInfo(&wg, host, nport) // update happens on topInfos1
		}
		wg.Wait()

		this.mu.Lock()
		this.topInfos1, this.topInfos = this.topInfos, this.topInfos1
		this.mu.Unlock()

		if this.mainScreen {
			this.render()
		}

		select {
		case <-time.After(interval):

		case <-this.quit:
			return
		}
	}
}
Beispiel #3
0
func (this *Histogram) drawAll(offsetTs []time.Time, offsets []int64,
	netTs []time.Time, rx []int64, tx []int64) {
	err := termui.Init()
	swallow(err)
	defer termui.Close()

	termui.UseTheme("helloworld")

	w, h := termbox.Size()

	bc1 := termui.NewBarChart()
	bc1.Border.Label = "Messages Produced/in million"
	data := make([]int, 0)
	for _, off := range offsets {
		data = append(data, int(off/1000000)) // in million
	}
	bclabels := make([]string, 0)
	for _, t := range offsetTs {
		bclabels = append(bclabels, fmt.Sprintf("%02d", t.Hour()))
	}
	bc1.Data = data
	bc1.Width = w
	bc1.SetY(0)
	bc1.Height = h / 3
	bc1.DataLabels = bclabels
	bc1.TextColor = termui.ColorWhite
	bc1.BarColor = termui.ColorRed
	bc1.NumColor = termui.ColorYellow

	bclabels = make([]string, 0) // shared between bc2 and bc3
	for _, t := range netTs {
		bclabels = append(bclabels, fmt.Sprintf("%02d", t.Hour()))
	}

	bc2 := termui.NewBarChart()
	bc2.Border.Label = "Network RX/in 10GB"
	data = make([]int, 0)
	for _, r := range rx {
		data = append(data, int(r>>30)/10)
	}
	bc2.Data = data
	bc2.Width = w
	bc2.SetY(h / 3)
	bc2.Height = h / 3
	bc2.DataLabels = bclabels
	bc2.TextColor = termui.ColorGreen
	bc2.BarColor = termui.ColorRed
	bc2.NumColor = termui.ColorYellow

	bc3 := termui.NewBarChart()
	bc3.Border.Label = "Network TX/in 10GB"
	data = make([]int, 0)
	for _, t := range tx {
		data = append(data, int(t>>30)/10)
	}
	bc3.Data = data
	bc3.Width = w
	bc3.SetY(h * 2 / 3)
	bc3.Height = h / 3
	bc3.DataLabels = bclabels
	bc3.TextColor = termui.ColorGreen
	bc3.BarColor = termui.ColorRed
	bc3.NumColor = termui.ColorYellow

	termui.Render(bc1, bc2, bc3)

	termbox.PollEvent()
}
Beispiel #4
0
func drawDashboard() {
	hosts = HostsOfGroup(group)
	data = make([][]float64, len(hosts))

	// title
	titlePanel := ui.NewPar(fmt.Sprintf("%s: %s / %v", group, itemName, tick*dataSize))
	titlePanel.Height = titleHeight
	titlePanel.PaddingLeft = 1
	titlePanel.HasBorder = false
	titlePanel.TextFgColor = ui.ColorCyan

	// charts
	charts := make([]*ui.LineChart, 0)
	for i := 0; i < len(data); i++ {
		chart := ui.NewLineChart()
		chart.Border.Label = hosts[i].Name
		chart.Data = fetchData(i, dataSize)
		chart.Height = panelHeight
		chart.PaddingTop = chartPaddingTop
		chart.AxesColor = axesColor
		chart.LineColor = lineColor

		charts = append(charts, chart)
	}

	draw := func(size int) {
		if size > 0 {
			for i := 0; i < len(data); i++ {
				charts[i].Data = fetchData(i, size)
			}
		}

		ui.Render(ui.Body)
	}

	err := ui.Init()
	must(err)
	defer ui.Close()

	ui.UseTheme(uiTheme)

	// auto layout
	rows := make([]*ui.Row, 1)
	rows[0] = ui.NewRow(ui.NewCol(panelSpan*panelsPerRow, panelOffset, titlePanel))
	for i := 0; i < len(hosts); i += panelsPerRow {
		if i+1 == len(hosts) {
			// the last single panel
			rows = append(rows,
				ui.NewRow(ui.NewCol(panelSpan, panelOffset, charts[i])))
		} else {
			rows = append(rows,
				ui.NewRow(ui.NewCol(panelSpan, panelOffset, charts[i]),
					ui.NewCol(panelSpan, panelOffset, charts[i+1])))
		}

	}
	ui.Body.AddRows(rows...)
	ui.Body.Align()

	// draw the history data
	draw(0)

	evt := make(chan tm.Event)
	go func() {
		for {
			evt <- tm.PollEvent()
		}
	}()

	for {
		select {
		case e := <-evt:
			if e.Type == tm.EventKey && e.Ch == 'q' {
				return
			}
			if e.Type == tm.EventResize {
				ui.Body.Width = ui.TermWidth()
				ui.Body.Align()
			}

		case <-time.After(tick):
			draw(1)
		}
	}
}
Beispiel #5
0
func (this *Top) Run(args []string) (exitCode int) {
	cmdFlags := flag.NewFlagSet("top", flag.ContinueOnError)
	cmdFlags.Usage = func() { this.Ui.Output(this.Help()) }
	cmdFlags.StringVar(&this.zone, "z", ctx.ZkDefaultZone(), "")
	cmdFlags.StringVar(&this.topicPattern, "t", "", "")
	cmdFlags.DurationVar(&this.topInterval, "i", time.Second*5, "refresh interval")
	cmdFlags.StringVar(&this.clusterPattern, "c", "", "")
	cmdFlags.IntVar(&this.limit, "n", 0, "")
	cmdFlags.BoolVar(&this.skipIpPrefix, "shortip", true, "")
	cmdFlags.StringVar(&this.who, "who", "producer", "")
	cmdFlags.BoolVar(&this.dashboardGraph, "d", false, "")
	cmdFlags.DurationVar(&this.duration, "for", time.Hour, "")
	cmdFlags.BoolVar(&this.longFmt, "l", false, "")
	cmdFlags.BoolVar(&this.batchMode, "b", false, "")
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	if this.limit == 0 {
		termui.Init()
		this.limit = termui.TermHeight() - 6 // 5=header+footer+cursor line
		termui.Close()
	}

	if this.dashboardGraph {
		if this.topInterval.Seconds() < 20 {
			this.topInterval = 20 * time.Second
		}
		this.who = "both"
		go this.clusterOffsetSummary()
	}

	if this.who == "c" || this.who == "consumer" {
		if this.topInterval.Seconds() < 20 {
			this.topInterval = 20 * time.Second // consumer groups only refresh offset per minute
		}

	}

	this.brokers = make(map[string][]string)
	this.counters = make(map[string]float64)
	this.lastCounters = make(map[string]float64)
	this.partitions = make(map[string]int)
	this.consumerCounters = make(map[string]float64)
	this.totalMps = make([]float64, 0, 1000)
	this.totalConsumerMps = make([]float64, 0, 1000)

	zkzone := zk.NewZkZone(zk.DefaultConfig(this.zone, ctx.ZoneZkAddrs(this.zone)))
	zkzone.ForSortedClusters(func(zkcluster *zk.ZkCluster) {
		if !patternMatched(zkcluster.Name(), this.clusterPattern) {
			return
		}

		switch this.who {
		case "p", "producer":
			go this.clusterTopProducers(zkcluster)

		case "c", "consumer":
			go this.clusterTopConsumers(zkcluster)

		case "both":
			go this.clusterTopConsumers(zkcluster)
			go this.clusterTopProducers(zkcluster)

		default:
			this.Ui.Error(fmt.Sprintf("unknown type: %s", this.who))
		}
	})

	if this.dashboardGraph {
		this.drawDashboard()
		return
	}

	ticker := time.NewTicker(this.topInterval)
	defer ticker.Stop()
	keyboardPressed := make(chan struct{})
	go func() {
		var b []byte = make([]byte, 1)
		for {
			os.Stdin.Read(b)
			keyboardPressed <- struct{}{}
		}
	}()

	startAt := time.Now()
	for {
		select {
		case <-keyboardPressed:
		case <-ticker.C:
		}

		if time.Since(startAt) >= this.duration {
			break
		}

		if this.batchMode {
			this.Ui.Output(bjtime.TimeToString(bjtime.NowBj()))
		} else {
			refreshScreen()
		}

		// header
		if this.longFmt {
			this.Ui.Output(fmt.Sprintf("%-9s %15s %-30s %42s %20s %15s",
				this.who, "cluster", "brokers", "topic", "cum num", "mps")) // mps=msg per second
			this.Ui.Output(fmt.Sprintf(strings.Repeat("-", 136)))
		} else {
			this.Ui.Output(fmt.Sprintf("%-9s %20s %50s %20s %15s",
				this.who, "cluster", "topic", "cum num", "mps")) // mps=msg per second
			this.Ui.Output(fmt.Sprintf(strings.Repeat("-", 118)))
		}

		this.showAndResetCounters()
	}

	return
}
Beispiel #6
0
func (this *Top) drawDashboard() {
	err := termui.Init()
	swallow(err)
	defer termui.Close()

	termui.UseTheme("helloworld")

	maxRound := termui.TermWidth() / 2
	refreshProducerData := func(round int) []float64 {
		this.showAndResetCounters()
		if round%maxRound == (maxRound - 5) {
			this.mu.Lock()
			tailLen := len(this.totalMps) - 2
			tail := this.totalMps[tailLen:]
			this.totalMps = make([]float64, 2, 1000)
			copy(this.totalMps, tail)
			this.mu.Unlock()
		}
		return this.totalMps
	}

	refreshConsumerData := func(round int) []float64 {
		if round%maxRound == (maxRound - 5) {
			this.mu.Lock()
			tailLen := len(this.totalConsumerMps) - 2
			tail := this.totalConsumerMps[tailLen:]
			this.totalConsumerMps = make([]float64, 2, 1000)
			copy(this.totalConsumerMps, tail)
			this.mu.Unlock()
		}
		return this.totalConsumerMps
	}

	producerChart := termui.NewLineChart()
	producerChart.Mode = "dot"
	producerChart.Border.Label = fmt.Sprintf("producer mps totals: %s %s %s",
		this.zone, this.clusterPattern, this.topicPattern)
	producerChart.Data = refreshProducerData(0)
	producerChart.Width = termui.TermWidth() / 2
	producerChart.Height = termui.TermHeight()
	producerChart.X = 0
	producerChart.Y = 0
	producerChart.AxesColor = termui.ColorWhite
	producerChart.LineColor = termui.ColorGreen | termui.AttrBold

	consumerChart := termui.NewLineChart()
	consumerChart.Mode = "dot"
	consumerChart.Border.Label = fmt.Sprintf("consumer mps totals: %s %s %s",
		this.zone, this.clusterPattern, this.topicPattern)
	consumerChart.Data = refreshConsumerData(0)
	consumerChart.Width = termui.TermWidth() / 2
	consumerChart.Height = termui.TermHeight()
	consumerChart.X = termui.TermWidth() / 2
	consumerChart.Y = 0
	consumerChart.AxesColor = termui.ColorWhite
	consumerChart.LineColor = termui.ColorRed | termui.AttrBold

	evt := make(chan termbox.Event)
	go func() {
		for {
			evt <- termbox.PollEvent()
		}
	}()

	termui.Render(producerChart, consumerChart)
	tick := time.NewTicker(this.topInterval)
	defer tick.Stop()
	rounds := 0
	for {
		select {
		case e := <-evt:
			if e.Type == termbox.EventKey && e.Ch == 'q' {
				return
			}

		case <-tick.C:
			// refresh data, and skip the first 2 rounds
			rounds++
			if rounds > 1 {
				producerChart.Data = refreshProducerData(rounds)
				consumerChart.Data = refreshConsumerData(rounds)
				termui.Render(producerChart, consumerChart)
			}

		}
	}
}