diff --git a/data.go b/data.go index 60771b1..4afc248 100644 --- a/data.go +++ b/data.go @@ -9,6 +9,7 @@ type UIData struct { LastTimestamp time.Time SparklineData []*SparklineData + HasBarchart bool } // SparklineData holds additional data needed for sparklines. @@ -37,9 +38,21 @@ func NewUIData(vars []VarName, services []*Service) *UIData { for i, _ := range services { sp[i] = NewSparklineData(vars) } + + hasGCPauses := func(vars []VarName) bool { + for _, v := range vars { + if v.Kind() == KindGCPauses { + return true + } + } + return false + } + return &UIData{ Services: services, Vars: vars, SparklineData: sp, + + HasBarchart: hasGCPauses(vars), } } diff --git a/service.go b/service.go index 1d48ded..9294085 100644 --- a/service.go +++ b/service.go @@ -83,7 +83,6 @@ func (s *Service) Update(wg *sync.WaitGroup) { value, err := expvar.GetValue(name.ToSlice()...) if err != nil { v.Set(nil) - continue } v.Set(value) } diff --git a/ui_single.go b/ui_single.go index e267cda..2dcedf3 100644 --- a/ui_single.go +++ b/ui_single.go @@ -2,8 +2,6 @@ package main import ( "fmt" - "github.com/divan/gcpauses" - "runtime" "time" "gopkg.in/gizak/termui.v1" @@ -113,7 +111,7 @@ func (t *TermUISingle) Update(data UIData) { spl := &t.Sparkline.Lines[i] - max := data.SparklineData[i].Stats[name].Max().String() + max := data.SparklineData[0].Stats[name].Max().String() spl.Title = fmt.Sprintf("%s: %v (max: %v)", name.Long(), service.Value(name), max) spl.TitleColor = colorByKind(name.Kind()) spl.LineColor = colorByKind(name.Kind()) @@ -122,25 +120,36 @@ func (t *TermUISingle) Update(data UIData) { } // BarChart - var m runtime.MemStats - runtime.ReadMemStats(&m) - p := gcpauses.NewGCPauses(&m) - values, counts := p.Histogram(25) - vals := make([]int, 0, len(counts)) - labels := make([]string, 0, len(counts)) - for i := 0; i < len(counts); i++ { - vals = append(vals, int(counts[i])) - d := time.Duration(values[i]) - labels = append(labels, d.String()) + if data.HasBarchart { + var gcpauses *GCPauses + for _, v := range service.Vars { + if v.Kind() == KindGCPauses { + gcpauses = v.(*GCPauses) + break + } + } + hist := gcpauses.Histogram(20) + values, counts := hist.BarchartData() + vals := make([]int, 0, len(counts)) + labels := make([]string, 0, len(counts)) + for i := 0; i < len(counts); i++ { + vals = append(vals, int(counts[i])) + d := roundDuration(time.Duration(values[i])) + labels = append(labels, d.String()) + } + t.BarChart.Data = vals + t.BarChart.DataLabels = labels + t.BarChart.Border.Label = "GC Pauses (last 256)" + t.BarChart.BarWidth = 7 } - t.BarChart.Data = vals - t.BarChart.DataLabels = labels - t.BarChart.Border.Label = fmt.Sprintf("%v", len(counts)) t.Relayout() var widgets []termui.Bufferer - widgets = append(widgets, t.Title, t.Status, t.Sparkline, t.BarChart) + widgets = append(widgets, t.Title, t.Status, t.Sparkline) + if data.HasBarchart { + widgets = append(widgets, t.BarChart) + } for _, par := range t.Pars { widgets = append(widgets, par) } @@ -185,15 +194,19 @@ func (t *TermUISingle) Relayout() { h -= secondRowH // Third row: Sparklines + calcHeight := len(t.Sparkline.Lines) * 2 + if calcHeight > (h / 2) { + calcHeight = h / 2 + } + t.Sparkline.Width = tw - t.Sparkline.Height = h / 2 + t.Sparkline.Height = calcHeight t.Sparkline.Y = th - h // Fourth row: Barchart t.BarChart.Width = tw - t.BarChart.Height = h / 2 - t.BarChart.Y = th - h/2 - t.BarChart.BarWidth = 10 + t.BarChart.Height = h - calcHeight + t.BarChart.Y = th - t.BarChart.Height } func formatMax(max interface{}) string { diff --git a/var.go b/var.go index 0a396c3..cf2e0b4 100644 --- a/var.go +++ b/var.go @@ -74,6 +74,10 @@ func (v *Number) String() string { return fmt.Sprintf("%.02f", v.val) } func (v *Number) Set(j *jason.Value) { + if j == nil { + v.val = 0 + return + } if n, err := j.Float64(); err == nil { v.val = n } else if n, err := j.Int64(); err == nil { @@ -98,6 +102,10 @@ func (v *Memory) String() string { return fmt.Sprintf("%s", byten.Size(v.bytes)) } func (v *Memory) Set(j *jason.Value) { + if j == nil { + v.bytes = 0 + return + } if n, err := j.Int64(); err == nil { v.bytes = n } else { @@ -122,6 +130,10 @@ func (v *Duration) String() string { } func (v *Duration) Set(j *jason.Value) { + if j == nil { + v.dur = 0 + return + } if n, err := j.Int64(); err == nil { v.dur = time.Duration(n) } else if n, err := j.Float64(); err == nil { @@ -145,6 +157,10 @@ type String struct { func (v *String) Kind() VarKind { return KindString } func (v *String) String() string { return v.str } func (v *String) Set(j *jason.Value) { + if j == nil { + v.str = "N/A" + return + } if n, err := j.String(); err == nil { v.str = n } else { @@ -165,6 +181,9 @@ func (v *GCPauses) Kind() VarKind { return KindGCPauses } func (v *GCPauses) String() string { return "" } func (v *GCPauses) Set(j *jason.Value) { v.pauses = [256]uint64{} + if j == nil { + return + } if arr, err := j.Array(); err == nil { for i := 0; i < len(arr); i++ { p, _ := arr[i].Int64() @@ -175,7 +194,12 @@ func (v *GCPauses) Set(j *jason.Value) { func (v *GCPauses) Histogram(bins int) *Histogram { hist := NewHistogram(bins) for i := 0; i < 256; i++ { - hist.Add(v.pauses[i]) + // we ignore zeros, since + // its never the case, but + // we have zeros on the very beginning + if v.pauses[i] > 0 { + hist.Add(v.pauses[i]) + } } return hist }