mirror of
https://github.com/divan/expvarmon.git
synced 2025-04-29 13:49:19 +08:00
Add BarChart for GC pauses
This commit is contained in:
parent
86e5c63eaf
commit
794515330a
13
data.go
13
data.go
@ -9,6 +9,7 @@ type UIData struct {
|
|||||||
LastTimestamp time.Time
|
LastTimestamp time.Time
|
||||||
|
|
||||||
SparklineData []*SparklineData
|
SparklineData []*SparklineData
|
||||||
|
HasBarchart bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SparklineData holds additional data needed for sparklines.
|
// SparklineData holds additional data needed for sparklines.
|
||||||
@ -37,9 +38,21 @@ func NewUIData(vars []VarName, services []*Service) *UIData {
|
|||||||
for i, _ := range services {
|
for i, _ := range services {
|
||||||
sp[i] = NewSparklineData(vars)
|
sp[i] = NewSparklineData(vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasGCPauses := func(vars []VarName) bool {
|
||||||
|
for _, v := range vars {
|
||||||
|
if v.Kind() == KindGCPauses {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return &UIData{
|
return &UIData{
|
||||||
Services: services,
|
Services: services,
|
||||||
Vars: vars,
|
Vars: vars,
|
||||||
SparklineData: sp,
|
SparklineData: sp,
|
||||||
|
|
||||||
|
HasBarchart: hasGCPauses(vars),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,6 @@ func (s *Service) Update(wg *sync.WaitGroup) {
|
|||||||
value, err := expvar.GetValue(name.ToSlice()...)
|
value, err := expvar.GetValue(name.ToSlice()...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
v.Set(nil)
|
v.Set(nil)
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
v.Set(value)
|
v.Set(value)
|
||||||
}
|
}
|
||||||
|
55
ui_single.go
55
ui_single.go
@ -2,8 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/divan/gcpauses"
|
|
||||||
"runtime"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/gizak/termui.v1"
|
"gopkg.in/gizak/termui.v1"
|
||||||
@ -113,7 +111,7 @@ func (t *TermUISingle) Update(data UIData) {
|
|||||||
|
|
||||||
spl := &t.Sparkline.Lines[i]
|
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.Title = fmt.Sprintf("%s: %v (max: %v)", name.Long(), service.Value(name), max)
|
||||||
spl.TitleColor = colorByKind(name.Kind())
|
spl.TitleColor = colorByKind(name.Kind())
|
||||||
spl.LineColor = colorByKind(name.Kind())
|
spl.LineColor = colorByKind(name.Kind())
|
||||||
@ -122,25 +120,36 @@ func (t *TermUISingle) Update(data UIData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BarChart
|
// BarChart
|
||||||
var m runtime.MemStats
|
if data.HasBarchart {
|
||||||
runtime.ReadMemStats(&m)
|
var gcpauses *GCPauses
|
||||||
p := gcpauses.NewGCPauses(&m)
|
for _, v := range service.Vars {
|
||||||
values, counts := p.Histogram(25)
|
if v.Kind() == KindGCPauses {
|
||||||
vals := make([]int, 0, len(counts))
|
gcpauses = v.(*GCPauses)
|
||||||
labels := make([]string, 0, len(counts))
|
break
|
||||||
for i := 0; i < len(counts); i++ {
|
}
|
||||||
vals = append(vals, int(counts[i]))
|
}
|
||||||
d := time.Duration(values[i])
|
hist := gcpauses.Histogram(20)
|
||||||
labels = append(labels, d.String())
|
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()
|
t.Relayout()
|
||||||
|
|
||||||
var widgets []termui.Bufferer
|
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 {
|
for _, par := range t.Pars {
|
||||||
widgets = append(widgets, par)
|
widgets = append(widgets, par)
|
||||||
}
|
}
|
||||||
@ -185,15 +194,19 @@ func (t *TermUISingle) Relayout() {
|
|||||||
h -= secondRowH
|
h -= secondRowH
|
||||||
|
|
||||||
// Third row: Sparklines
|
// Third row: Sparklines
|
||||||
|
calcHeight := len(t.Sparkline.Lines) * 2
|
||||||
|
if calcHeight > (h / 2) {
|
||||||
|
calcHeight = h / 2
|
||||||
|
}
|
||||||
|
|
||||||
t.Sparkline.Width = tw
|
t.Sparkline.Width = tw
|
||||||
t.Sparkline.Height = h / 2
|
t.Sparkline.Height = calcHeight
|
||||||
t.Sparkline.Y = th - h
|
t.Sparkline.Y = th - h
|
||||||
|
|
||||||
// Fourth row: Barchart
|
// Fourth row: Barchart
|
||||||
t.BarChart.Width = tw
|
t.BarChart.Width = tw
|
||||||
t.BarChart.Height = h / 2
|
t.BarChart.Height = h - calcHeight
|
||||||
t.BarChart.Y = th - h/2
|
t.BarChart.Y = th - t.BarChart.Height
|
||||||
t.BarChart.BarWidth = 10
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatMax(max interface{}) string {
|
func formatMax(max interface{}) string {
|
||||||
|
26
var.go
26
var.go
@ -74,6 +74,10 @@ func (v *Number) String() string {
|
|||||||
return fmt.Sprintf("%.02f", v.val)
|
return fmt.Sprintf("%.02f", v.val)
|
||||||
}
|
}
|
||||||
func (v *Number) Set(j *jason.Value) {
|
func (v *Number) Set(j *jason.Value) {
|
||||||
|
if j == nil {
|
||||||
|
v.val = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
if n, err := j.Float64(); err == nil {
|
if n, err := j.Float64(); err == nil {
|
||||||
v.val = n
|
v.val = n
|
||||||
} else if n, err := j.Int64(); err == nil {
|
} 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))
|
return fmt.Sprintf("%s", byten.Size(v.bytes))
|
||||||
}
|
}
|
||||||
func (v *Memory) Set(j *jason.Value) {
|
func (v *Memory) Set(j *jason.Value) {
|
||||||
|
if j == nil {
|
||||||
|
v.bytes = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
if n, err := j.Int64(); err == nil {
|
if n, err := j.Int64(); err == nil {
|
||||||
v.bytes = n
|
v.bytes = n
|
||||||
} else {
|
} else {
|
||||||
@ -122,6 +130,10 @@ func (v *Duration) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *Duration) Set(j *jason.Value) {
|
func (v *Duration) Set(j *jason.Value) {
|
||||||
|
if j == nil {
|
||||||
|
v.dur = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
if n, err := j.Int64(); err == nil {
|
if n, err := j.Int64(); err == nil {
|
||||||
v.dur = time.Duration(n)
|
v.dur = time.Duration(n)
|
||||||
} else if n, err := j.Float64(); err == nil {
|
} 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) Kind() VarKind { return KindString }
|
||||||
func (v *String) String() string { return v.str }
|
func (v *String) String() string { return v.str }
|
||||||
func (v *String) Set(j *jason.Value) {
|
func (v *String) Set(j *jason.Value) {
|
||||||
|
if j == nil {
|
||||||
|
v.str = "N/A"
|
||||||
|
return
|
||||||
|
}
|
||||||
if n, err := j.String(); err == nil {
|
if n, err := j.String(); err == nil {
|
||||||
v.str = n
|
v.str = n
|
||||||
} else {
|
} else {
|
||||||
@ -165,6 +181,9 @@ func (v *GCPauses) Kind() VarKind { return KindGCPauses }
|
|||||||
func (v *GCPauses) String() string { return "" }
|
func (v *GCPauses) String() string { return "" }
|
||||||
func (v *GCPauses) Set(j *jason.Value) {
|
func (v *GCPauses) Set(j *jason.Value) {
|
||||||
v.pauses = [256]uint64{}
|
v.pauses = [256]uint64{}
|
||||||
|
if j == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if arr, err := j.Array(); err == nil {
|
if arr, err := j.Array(); err == nil {
|
||||||
for i := 0; i < len(arr); i++ {
|
for i := 0; i < len(arr); i++ {
|
||||||
p, _ := arr[i].Int64()
|
p, _ := arr[i].Int64()
|
||||||
@ -175,7 +194,12 @@ func (v *GCPauses) Set(j *jason.Value) {
|
|||||||
func (v *GCPauses) Histogram(bins int) *Histogram {
|
func (v *GCPauses) Histogram(bins int) *Histogram {
|
||||||
hist := NewHistogram(bins)
|
hist := NewHistogram(bins)
|
||||||
for i := 0; i < 256; i++ {
|
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
|
return hist
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user