rename expanded -> single view

This commit is contained in:
Bradley Cicenas
2017-08-05 11:28:20 +00:00
parent 3ed9912bcb
commit 27e272c58f
13 changed files with 33 additions and 33 deletions

32
cwidgets/single/cpu.go Normal file
View File

@@ -0,0 +1,32 @@
package single
import (
ui "github.com/gizak/termui"
)
type Cpu struct {
*ui.LineChart
hist FloatHist
}
func NewCpu() *Cpu {
cpu := &Cpu{ui.NewLineChart(), NewFloatHist(55)}
cpu.Mode = "dot"
cpu.BorderLabel = "CPU"
cpu.Height = 12
cpu.Width = colWidth[0]
cpu.X = 0
cpu.DataLabels = cpu.hist.Labels
// hack to force the default minY scale to 0
tmpData := []float64{20}
cpu.Data = tmpData
_ = cpu.Buffer()
cpu.Data = cpu.hist.Data
return cpu
}
func (w *Cpu) Update(val int) {
w.hist.Append(float64(val))
}

60
cwidgets/single/hist.go Normal file
View File

@@ -0,0 +1,60 @@
package single
type IntHist struct {
Val int // most current data point
Data []int // historical data points
Labels []string
}
func NewIntHist(max int) *IntHist {
return &IntHist{
Data: make([]int, max),
Labels: make([]string, max),
}
}
func (h *IntHist) Append(val int) {
if len(h.Data) == cap(h.Data) {
h.Data = append(h.Data[:0], h.Data[1:]...)
}
h.Val = val
h.Data = append(h.Data, val)
}
type DiffHist struct {
*IntHist
lastVal int
}
func NewDiffHist(max int) *DiffHist {
return &DiffHist{NewIntHist(max), -1}
}
func (h *DiffHist) Append(val int) {
if h.lastVal >= 0 { // skip append if this is the initial update
diff := val - h.lastVal
h.IntHist.Append(diff)
}
h.lastVal = val
}
type FloatHist struct {
Val float64 // most current data point
Data []float64 // historical data points
Labels []string
}
func NewFloatHist(max int) FloatHist {
return FloatHist{
Data: make([]float64, max),
Labels: make([]string, max),
}
}
func (h FloatHist) Append(val float64) {
if len(h.Data) == cap(h.Data) {
h.Data = append(h.Data[:0], h.Data[1:]...)
}
h.Val = val
h.Data = append(h.Data, val)
}

58
cwidgets/single/info.go Normal file
View File

@@ -0,0 +1,58 @@
package single
import (
"strings"
ui "github.com/gizak/termui"
)
var displayInfo = []string{"id", "name", "image", "ports", "state", "created"}
type Info struct {
*ui.Table
data map[string]string
}
func NewInfo(id string) *Info {
p := ui.NewTable()
p.Height = 4
p.Width = colWidth[0]
p.FgColor = ui.ThemeAttr("par.text.fg")
p.Separator = false
i := &Info{p, make(map[string]string)}
i.Set("id", id)
return i
}
func (w *Info) Set(k, v string) {
w.data[k] = v
// rebuild rows
w.Rows = [][]string{}
for _, k := range displayInfo {
if v, ok := w.data[k]; ok {
w.Rows = append(w.Rows, mkInfoRows(k, v)...)
}
}
w.Height = len(w.Rows) + 2
}
// Build row(s) from a key and value string
func mkInfoRows(k, v string) (rows [][]string) {
lines := strings.Split(v, "\n")
// initial row with field name
rows = append(rows, []string{k, lines[0]})
// append any additional lines in seperate row
if len(lines) > 1 {
for _, line := range lines[1:] {
if line != "" {
rows = append(rows, []string{"", line})
}
}
}
return rows
}

51
cwidgets/single/io.go Normal file
View File

@@ -0,0 +1,51 @@
package single
import (
"fmt"
"strings"
"github.com/bcicen/ctop/cwidgets"
ui "github.com/gizak/termui"
)
type IO struct {
*ui.Sparklines
readHist *DiffHist
writeHist *DiffHist
}
func NewIO() *IO {
io := &IO{ui.NewSparklines(), NewDiffHist(60), NewDiffHist(60)}
io.BorderLabel = "IO"
io.Height = 6
io.Width = colWidth[0]
io.X = 0
io.Y = 24
read := ui.NewSparkline()
read.Title = "READ"
read.Height = 1
read.Data = io.readHist.Data
read.LineColor = ui.ColorGreen
write := ui.NewSparkline()
write.Title = "WRITE"
write.Height = 1
write.Data = io.writeHist.Data
write.LineColor = ui.ColorYellow
io.Lines = []ui.Sparkline{read, write}
return io
}
func (w *IO) Update(read int64, write int64) {
var rate string
w.readHist.Append(int(read))
rate = strings.ToLower(cwidgets.ByteFormatInt(w.readHist.Val))
w.Lines[0].Title = fmt.Sprintf("read [%s/s]", rate)
w.writeHist.Append(int(write))
rate = strings.ToLower(cwidgets.ByteFormatInt(w.writeHist.Val))
w.Lines[1].Title = fmt.Sprintf("write [%s/s]", rate)
}

83
cwidgets/single/logs.go Normal file
View File

@@ -0,0 +1,83 @@
package single
import (
"time"
"github.com/bcicen/ctop/models"
ui "github.com/gizak/termui"
)
type LogLines struct {
ts []time.Time
data []string
}
func NewLogLines(max int) *LogLines {
ll := &LogLines{
ts: make([]time.Time, max),
data: make([]string, max),
}
return ll
}
func (ll *LogLines) tail(n int) []string {
lines := make([]string, n)
for i := 0; i < n; i++ {
lines = append(lines, ll.data[len(ll.data)-i])
}
return lines
}
func (ll *LogLines) getLines(start, end int) []string {
if end < 0 {
return ll.data[start:]
}
return ll.data[start:end]
}
func (ll *LogLines) add(l models.Log) {
if len(ll.data) == cap(ll.data) {
ll.data = append(ll.data[:0], ll.data[1:]...)
ll.ts = append(ll.ts[:0], ll.ts[1:]...)
}
ll.ts = append(ll.ts, l.Timestamp)
ll.data = append(ll.data, l.Message)
log.Debugf("recorded log line: %v", l)
}
type Logs struct {
*ui.List
lines *LogLines
}
func NewLogs(stream chan models.Log) *Logs {
p := ui.NewList()
p.Y = ui.TermHeight() / 2
p.X = 0
p.Height = ui.TermHeight() - p.Y
p.Width = ui.TermWidth()
//p.Overflow = "wrap"
p.ItemFgColor = ui.ThemeAttr("par.text.fg")
i := &Logs{p, NewLogLines(4098)}
go func() {
for line := range stream {
i.lines.add(line)
ui.Render(i)
}
}()
return i
}
func (w *Logs) Align() {
w.X = colWidth[0]
w.List.Align()
}
func (w *Logs) Buffer() ui.Buffer {
maxLines := w.Height - 2
offset := len(w.lines.data) - maxLines
w.Items = w.lines.getLines(offset, -1)
return w.List.Buffer()
}
// number of rows a line will occupy at current panel width
func (w *Logs) lineHeight(s string) int { return (len(s) / w.InnerWidth()) + 1 }

128
cwidgets/single/main.go Normal file
View File

@@ -0,0 +1,128 @@
package single
import (
"github.com/bcicen/ctop/logging"
"github.com/bcicen/ctop/models"
ui "github.com/gizak/termui"
)
var (
log = logging.Init()
sizeError = termSizeError()
colWidth = [2]int{65, 0} // left,right column width
)
type Single struct {
Info *Info
Net *Net
Cpu *Cpu
Mem *Mem
IO *IO
X, Y int
Width int
}
func NewSingle(id string) *Single {
if len(id) > 12 {
id = id[:12]
}
return &Single{
Info: NewInfo(id),
Net: NewNet(),
Cpu: NewCpu(),
Mem: NewMem(),
IO: NewIO(),
Width: ui.TermWidth(),
}
}
func (e *Single) Up() {
if e.Y < 0 {
e.Y++
e.Align()
ui.Render(e)
}
}
func (e *Single) Down() {
if e.Y > (ui.TermHeight() - e.GetHeight()) {
e.Y--
e.Align()
ui.Render(e)
}
}
func (e *Single) SetWidth(w int) { e.Width = w }
func (e *Single) SetMeta(k, v string) { e.Info.Set(k, v) }
func (e *Single) SetMetrics(m models.Metrics) {
e.Cpu.Update(m.CPUUtil)
e.Net.Update(m.NetRx, m.NetTx)
e.Mem.Update(int(m.MemUsage), int(m.MemLimit))
e.IO.Update(m.IOBytesRead, m.IOBytesWrite)
}
// Return total column height
func (e *Single) GetHeight() (h int) {
h += e.Info.Height
h += e.Net.Height
h += e.Cpu.Height
h += e.Mem.Height
h += e.IO.Height
return h
}
func (e *Single) Align() {
// reset offset if needed
if e.GetHeight() <= ui.TermHeight() {
e.Y = 0
}
y := e.Y
for _, i := range e.all() {
i.SetY(y)
y += i.GetHeight()
}
if e.Width > colWidth[0] {
colWidth[1] = e.Width - (colWidth[0] + 1)
}
e.Mem.Align()
log.Debugf("align: width=%v left-col=%v right-col=%v", e.Width, colWidth[0], colWidth[1])
}
func calcWidth(w int) {
}
func (e *Single) Buffer() ui.Buffer {
buf := ui.NewBuffer()
if e.Width < (colWidth[0] + colWidth[1]) {
ui.Clear()
buf.Merge(sizeError.Buffer())
return buf
}
buf.Merge(e.Info.Buffer())
buf.Merge(e.Cpu.Buffer())
buf.Merge(e.Mem.Buffer())
buf.Merge(e.Net.Buffer())
buf.Merge(e.IO.Buffer())
return buf
}
func (e *Single) all() []ui.GridBufferer {
return []ui.GridBufferer{
e.Info,
e.Cpu,
e.Mem,
e.Net,
e.IO,
}
}
func termSizeError() *ui.Par {
p := ui.NewPar("screen too small!")
p.Height = 1
p.Width = 20
p.Border = false
return p
}

83
cwidgets/single/mem.go Normal file
View File

@@ -0,0 +1,83 @@
package single
import (
"fmt"
"github.com/bcicen/ctop/cwidgets"
ui "github.com/gizak/termui"
)
type Mem struct {
*ui.Block
Chart *ui.MBarChart
InnerLabel *ui.Par
valHist *IntHist
limitHist *IntHist
}
func NewMem() *Mem {
mem := &Mem{
Block: ui.NewBlock(),
Chart: newMemChart(),
InnerLabel: newMemLabel(),
valHist: NewIntHist(9),
limitHist: NewIntHist(9),
}
mem.Height = 13
mem.Width = colWidth[0]
mem.BorderLabel = "MEM"
mem.Chart.Data[0] = mem.valHist.Data
mem.Chart.Data[1] = mem.limitHist.Data
mem.Chart.DataLabels = mem.valHist.Labels
return mem
}
func (w *Mem) Align() {
y := w.Y + 1
w.InnerLabel.SetY(y)
w.Chart.SetY(y + w.InnerLabel.Height)
w.Chart.Height = w.Height - w.InnerLabel.Height - 2
w.Chart.SetWidth(w.Width - 2)
}
func (w *Mem) Buffer() ui.Buffer {
buf := ui.NewBuffer()
buf.Merge(w.Block.Buffer())
buf.Merge(w.InnerLabel.Buffer())
buf.Merge(w.Chart.Buffer())
return buf
}
func newMemLabel() *ui.Par {
p := ui.NewPar("-")
p.X = 1
p.Border = false
p.Height = 1
p.Width = 20
return p
}
func newMemChart() *ui.MBarChart {
mbar := ui.NewMBarChart()
mbar.X = 1
mbar.Border = false
mbar.BarGap = 1
mbar.BarWidth = 6
mbar.BarColor[1] = ui.ColorBlack
mbar.NumColor[1] = ui.ColorBlack
mbar.NumFmt = cwidgets.ByteFormatInt
//mbar.ShowScale = true
return mbar
}
func (w *Mem) Update(val int, limit int) {
w.valHist.Append(val)
w.limitHist.Append(limit - val)
w.InnerLabel.Text = fmt.Sprintf("%v / %v", cwidgets.ByteFormatInt(val), cwidgets.ByteFormatInt(limit))
//w.Data[0] = w.hist.data
}

51
cwidgets/single/net.go Normal file
View File

@@ -0,0 +1,51 @@
package single
import (
"fmt"
"strings"
"github.com/bcicen/ctop/cwidgets"
ui "github.com/gizak/termui"
)
type Net struct {
*ui.Sparklines
rxHist *DiffHist
txHist *DiffHist
}
func NewNet() *Net {
net := &Net{ui.NewSparklines(), NewDiffHist(60), NewDiffHist(60)}
net.BorderLabel = "NET"
net.Height = 6
net.Width = colWidth[0]
net.X = 0
net.Y = 24
rx := ui.NewSparkline()
rx.Title = "RX"
rx.Height = 1
rx.Data = net.rxHist.Data
rx.LineColor = ui.ColorGreen
tx := ui.NewSparkline()
tx.Title = "TX"
tx.Height = 1
tx.Data = net.txHist.Data
tx.LineColor = ui.ColorYellow
net.Lines = []ui.Sparkline{rx, tx}
return net
}
func (w *Net) Update(rx int64, tx int64) {
var rate string
w.rxHist.Append(int(rx))
rate = strings.ToLower(cwidgets.ByteFormatInt(w.rxHist.Val))
w.Lines[0].Title = fmt.Sprintf("RX [%s/s]", rate)
w.txHist.Append(int(tx))
rate = strings.ToLower(cwidgets.ByteFormatInt(w.txHist.Val))
w.Lines[1].Title = fmt.Sprintf("TX [%s/s]", rate)
}