forked from mirror/client_golang
Merge pull request #113 from oliver006/add_gc_metrics
Add garbage collection stats
This commit is contained in:
commit
86bd077f30
|
@ -2,10 +2,13 @@ package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"runtime/debug"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type goCollector struct {
|
type goCollector struct {
|
||||||
goroutines Gauge
|
goroutines Gauge
|
||||||
|
gcDesc *Desc
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGoCollector returns a collector which exports metrics about the current
|
// NewGoCollector returns a collector which exports metrics about the current
|
||||||
|
@ -16,16 +19,32 @@ func NewGoCollector() *goCollector {
|
||||||
Name: "process_goroutines",
|
Name: "process_goroutines",
|
||||||
Help: "Number of goroutines that currently exist.",
|
Help: "Number of goroutines that currently exist.",
|
||||||
}),
|
}),
|
||||||
|
gcDesc: NewDesc(
|
||||||
|
"go_gc_duration_seconds",
|
||||||
|
"A summary of the GC invocation durations.",
|
||||||
|
nil, nil),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe returns all descriptions of the collector.
|
// Describe returns all descriptions of the collector.
|
||||||
func (c *goCollector) Describe(ch chan<- *Desc) {
|
func (c *goCollector) Describe(ch chan<- *Desc) {
|
||||||
ch <- c.goroutines.Desc()
|
ch <- c.goroutines.Desc()
|
||||||
|
ch <- c.gcDesc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect returns the current state of all metrics of the collector.
|
// Collect returns the current state of all metrics of the collector.
|
||||||
func (c *goCollector) Collect(ch chan<- Metric) {
|
func (c *goCollector) Collect(ch chan<- Metric) {
|
||||||
c.goroutines.Set(float64(runtime.NumGoroutine()))
|
c.goroutines.Set(float64(runtime.NumGoroutine()))
|
||||||
ch <- c.goroutines
|
ch <- c.goroutines
|
||||||
|
|
||||||
|
var stats debug.GCStats
|
||||||
|
stats.PauseQuantiles = make([]time.Duration, 5)
|
||||||
|
debug.ReadGCStats(&stats)
|
||||||
|
|
||||||
|
quantiles := make(map[float64]float64)
|
||||||
|
for idx, pq := range stats.PauseQuantiles[1:] {
|
||||||
|
quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds()
|
||||||
|
}
|
||||||
|
quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
|
||||||
|
ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), quantiles)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -35,6 +35,9 @@ func TestGoCollector(t *testing.T) {
|
||||||
case Gauge:
|
case Gauge:
|
||||||
pb := &dto.Metric{}
|
pb := &dto.Metric{}
|
||||||
m.Write(pb)
|
m.Write(pb)
|
||||||
|
if pb.GetGauge() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if old == -1 {
|
if old == -1 {
|
||||||
old = int(pb.GetGauge().GetValue())
|
old = int(pb.GetGauge().GetValue())
|
||||||
|
@ -48,8 +51,66 @@ func TestGoCollector(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
default:
|
}
|
||||||
t.Errorf("want type Gauge, got %s", reflect.TypeOf(metric))
|
case <-time.After(1 * time.Second):
|
||||||
|
t.Fatalf("expected collect timed out")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGCCollector(t *testing.T) {
|
||||||
|
var (
|
||||||
|
c = NewGoCollector()
|
||||||
|
ch = make(chan Metric)
|
||||||
|
waitc = make(chan struct{})
|
||||||
|
closec = make(chan struct{})
|
||||||
|
oldGC uint64
|
||||||
|
oldPause float64
|
||||||
|
)
|
||||||
|
defer close(closec)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
c.Collect(ch)
|
||||||
|
// force GC
|
||||||
|
runtime.GC()
|
||||||
|
<-waitc
|
||||||
|
c.Collect(ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
first := true
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case metric := <-ch:
|
||||||
|
switch m := metric.(type) {
|
||||||
|
case *constSummary, *value:
|
||||||
|
pb := &dto.Metric{}
|
||||||
|
m.Write(pb)
|
||||||
|
if pb.GetSummary() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pb.GetSummary().Quantile) != 5 {
|
||||||
|
t.Errorf("expected 4 buckets, got %d", len(pb.GetSummary().Quantile))
|
||||||
|
}
|
||||||
|
for idx, want := range []float64{0.0, 0.25, 0.5, 0.75, 1.0} {
|
||||||
|
if *pb.GetSummary().Quantile[idx].Quantile != want {
|
||||||
|
t.Errorf("bucket #%d is off, got %f, want %f", idx, *pb.GetSummary().Quantile[idx].Quantile, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
oldGC = *pb.GetSummary().SampleCount
|
||||||
|
oldPause = *pb.GetSummary().SampleSum
|
||||||
|
close(waitc)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if diff := *pb.GetSummary().SampleCount - oldGC; diff != 1 {
|
||||||
|
t.Errorf("want 1 new garbage collection run, got %d", diff)
|
||||||
|
}
|
||||||
|
if diff := *pb.GetSummary().SampleSum - oldPause; diff <= 0 {
|
||||||
|
t.Errorf("want moar pause, got %f", diff)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
case <-time.After(1 * time.Second):
|
case <-time.After(1 * time.Second):
|
||||||
t.Fatalf("expected collect timed out")
|
t.Fatalf("expected collect timed out")
|
||||||
|
|
Loading…
Reference in New Issue