Skip to content

Commit ff586ea

Browse files
committed
Add garbage collection stats
1 parent 6efaf95 commit ff586ea

File tree

2 files changed

+68
-3
lines changed

2 files changed

+68
-3
lines changed

prometheus/go_collector.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package prometheus
22

33
import (
44
"runtime"
5+
"runtime/debug"
56
)
67

78
type goCollector struct {
89
goroutines Gauge
10+
gcDesc *Desc
911
}
1012

1113
// NewGoCollector returns a collector which exports metrics about the current
@@ -16,16 +18,26 @@ func NewGoCollector() *goCollector {
1618
Name: "process_goroutines",
1719
Help: "Number of goroutines that currently exist.",
1820
}),
21+
gcDesc: NewDesc(
22+
"go_gc_duration_seconds",
23+
"A summary of the GC invocation durations.",
24+
nil, nil),
1925
}
2026
}
2127

2228
// Describe returns all descriptions of the collector.
2329
func (c *goCollector) Describe(ch chan<- *Desc) {
2430
ch <- c.goroutines.Desc()
31+
ch <- c.gcDesc
2532
}
2633

2734
// Collect returns the current state of all metrics of the collector.
2835
func (c *goCollector) Collect(ch chan<- Metric) {
2936
c.goroutines.Set(float64(runtime.NumGoroutine()))
3037
ch <- c.goroutines
38+
39+
var stats debug.GCStats
40+
debug.ReadGCStats(&stats)
41+
42+
ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), nil)
3143
}

prometheus/go_collector_test.go

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package prometheus
22

33
import (
4-
"reflect"
4+
"runtime/debug"
55
"testing"
66
"time"
77

@@ -35,6 +35,9 @@ func TestGoCollector(t *testing.T) {
3535
case Gauge:
3636
pb := &dto.Metric{}
3737
m.Write(pb)
38+
if pb.GetGauge() == nil {
39+
continue
40+
}
3841

3942
if old == -1 {
4043
old = int(pb.GetGauge().GetValue())
@@ -48,8 +51,58 @@ func TestGoCollector(t *testing.T) {
4851
}
4952

5053
return
51-
default:
52-
t.Errorf("want type Gauge, got %s", reflect.TypeOf(metric))
54+
}
55+
case <-time.After(1 * time.Second):
56+
t.Fatalf("expected collect timed out")
57+
}
58+
}
59+
}
60+
61+
func TestGCCollector(t *testing.T) {
62+
var (
63+
c = NewGoCollector()
64+
ch = make(chan Metric)
65+
waitc = make(chan struct{})
66+
closec = make(chan struct{})
67+
oldGC uint64
68+
oldPause float64
69+
)
70+
defer close(closec)
71+
72+
go func() {
73+
c.Collect(ch)
74+
// force GC
75+
debug.FreeOSMemory()
76+
<-waitc
77+
c.Collect(ch)
78+
}()
79+
80+
first := true
81+
for {
82+
select {
83+
case metric := <-ch:
84+
switch m := metric.(type) {
85+
case *constSummary, *value:
86+
pb := &dto.Metric{}
87+
m.Write(pb)
88+
if pb.GetSummary() == nil {
89+
continue
90+
}
91+
92+
if first {
93+
first = false
94+
oldGC = *pb.GetSummary().SampleCount
95+
oldPause = *pb.GetSummary().SampleSum
96+
close(waitc)
97+
continue
98+
}
99+
if diff := *pb.GetSummary().SampleCount - oldGC; diff != 1 {
100+
t.Errorf("want 1 new garbage collection run, got %d", diff)
101+
}
102+
if diff := *pb.GetSummary().SampleSum - oldPause; diff <= 0 {
103+
t.Errorf("want moar pause, got %f", diff)
104+
}
105+
return
53106
}
54107
case <-time.After(1 * time.Second):
55108
t.Fatalf("expected collect timed out")

0 commit comments

Comments
 (0)