diff --git a/prometheus/go_collector.go b/prometheus/go_collector.go index 6dea674..cbbc635 100644 --- a/prometheus/go_collector.go +++ b/prometheus/go_collector.go @@ -9,6 +9,7 @@ import ( type goCollector struct { goroutines Gauge + threads Gauge gcDesc *Desc // metrics to describe and collect @@ -24,6 +25,11 @@ func NewGoCollector() Collector { Name: "goroutines", Help: "Number of goroutines that currently exist.", }), + threads: NewGauge(GaugeOpts{ + Namespace: "go", + Name: "threads", + Help: "Number of threads created.", + }), gcDesc: NewDesc( "go_gc_duration_seconds", "A summary of the GC invocation durations.", @@ -225,8 +231,8 @@ func memstatNamespace(s string) string { // Describe returns all descriptions of the collector. func (c *goCollector) Describe(ch chan<- *Desc) { ch <- c.goroutines.Desc() + ch <- c.threads.Desc() ch <- c.gcDesc - for _, i := range c.metrics { ch <- i.desc } @@ -236,6 +242,9 @@ func (c *goCollector) Describe(ch chan<- *Desc) { func (c *goCollector) Collect(ch chan<- Metric) { c.goroutines.Set(float64(runtime.NumGoroutine())) ch <- c.goroutines + n, _ := runtime.ThreadCreateProfile(nil) + c.threads.Set(float64(n)) + ch <- c.threads var stats debug.GCStats stats.PauseQuantiles = make([]time.Duration, 5) diff --git a/prometheus/go_collector_test.go b/prometheus/go_collector_test.go index 9a8858c..486ffad 100644 --- a/prometheus/go_collector_test.go +++ b/prometheus/go_collector_test.go @@ -33,6 +33,9 @@ func TestGoCollector(t *testing.T) { switch m := metric.(type) { // Attention, this also catches Counter... case Gauge: + if m.Desc().fqName != "go_goroutines" { + continue + } pb := &dto.Metric{} m.Write(pb) if pb.GetGauge() == nil { @@ -50,10 +53,11 @@ func TestGoCollector(t *testing.T) { t.Errorf("want 1 new goroutine, got %d", diff) } - // GoCollector performs two sends per call. + // GoCollector performs three sends per call. // On line 27 we need to receive the second send // to shut down cleanly. <-ch + <-ch return } case <-time.After(1 * time.Second):