1package prometheus
2
3import (
4	"fmt"
5	"runtime"
6	"runtime/debug"
7	"time"
8)
9
10type goCollector struct {
11	goroutines Gauge
12	gcDesc     *Desc
13
14	// metrics to describe and collect
15	metrics memStatsMetrics
16}
17
18// NewGoCollector returns a collector which exports metrics about the current
19// go process.
20func NewGoCollector() *goCollector {
21	return &goCollector{
22		goroutines: NewGauge(GaugeOpts{
23			Namespace: "go",
24			Name:      "goroutines",
25			Help:      "Number of goroutines that currently exist.",
26		}),
27		gcDesc: NewDesc(
28			"go_gc_duration_seconds",
29			"A summary of the GC invocation durations.",
30			nil, nil),
31		metrics: memStatsMetrics{
32			{
33				desc: NewDesc(
34					memstatNamespace("alloc_bytes"),
35					"Number of bytes allocated and still in use.",
36					nil, nil,
37				),
38				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
39				valType: GaugeValue,
40			}, {
41				desc: NewDesc(
42					memstatNamespace("alloc_bytes_total"),
43					"Total number of bytes allocated, even if freed.",
44					nil, nil,
45				),
46				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
47				valType: CounterValue,
48			}, {
49				desc: NewDesc(
50					memstatNamespace("sys_bytes"),
51					"Number of bytes obtained by system. Sum of all system allocations.",
52					nil, nil,
53				),
54				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
55				valType: GaugeValue,
56			}, {
57				desc: NewDesc(
58					memstatNamespace("lookups_total"),
59					"Total number of pointer lookups.",
60					nil, nil,
61				),
62				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) },
63				valType: CounterValue,
64			}, {
65				desc: NewDesc(
66					memstatNamespace("mallocs_total"),
67					"Total number of mallocs.",
68					nil, nil,
69				),
70				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
71				valType: CounterValue,
72			}, {
73				desc: NewDesc(
74					memstatNamespace("frees_total"),
75					"Total number of frees.",
76					nil, nil,
77				),
78				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
79				valType: CounterValue,
80			}, {
81				desc: NewDesc(
82					memstatNamespace("heap_alloc_bytes"),
83					"Number of heap bytes allocated and still in use.",
84					nil, nil,
85				),
86				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
87				valType: GaugeValue,
88			}, {
89				desc: NewDesc(
90					memstatNamespace("heap_sys_bytes"),
91					"Number of heap bytes obtained from system.",
92					nil, nil,
93				),
94				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
95				valType: GaugeValue,
96			}, {
97				desc: NewDesc(
98					memstatNamespace("heap_idle_bytes"),
99					"Number of heap bytes waiting to be used.",
100					nil, nil,
101				),
102				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
103				valType: GaugeValue,
104			}, {
105				desc: NewDesc(
106					memstatNamespace("heap_inuse_bytes"),
107					"Number of heap bytes that are in use.",
108					nil, nil,
109				),
110				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
111				valType: GaugeValue,
112			}, {
113				desc: NewDesc(
114					memstatNamespace("heap_released_bytes_total"),
115					"Total number of heap bytes released to OS.",
116					nil, nil,
117				),
118				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
119				valType: CounterValue,
120			}, {
121				desc: NewDesc(
122					memstatNamespace("heap_objects"),
123					"Number of allocated objects.",
124					nil, nil,
125				),
126				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
127				valType: GaugeValue,
128			}, {
129				desc: NewDesc(
130					memstatNamespace("stack_inuse_bytes"),
131					"Number of bytes in use by the stack allocator.",
132					nil, nil,
133				),
134				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
135				valType: GaugeValue,
136			}, {
137				desc: NewDesc(
138					memstatNamespace("stack_sys_bytes"),
139					"Number of bytes obtained from system for stack allocator.",
140					nil, nil,
141				),
142				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
143				valType: GaugeValue,
144			}, {
145				desc: NewDesc(
146					memstatNamespace("mspan_inuse_bytes"),
147					"Number of bytes in use by mspan structures.",
148					nil, nil,
149				),
150				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
151				valType: GaugeValue,
152			}, {
153				desc: NewDesc(
154					memstatNamespace("mspan_sys_bytes"),
155					"Number of bytes used for mspan structures obtained from system.",
156					nil, nil,
157				),
158				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
159				valType: GaugeValue,
160			}, {
161				desc: NewDesc(
162					memstatNamespace("mcache_inuse_bytes"),
163					"Number of bytes in use by mcache structures.",
164					nil, nil,
165				),
166				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
167				valType: GaugeValue,
168			}, {
169				desc: NewDesc(
170					memstatNamespace("mcache_sys_bytes"),
171					"Number of bytes used for mcache structures obtained from system.",
172					nil, nil,
173				),
174				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
175				valType: GaugeValue,
176			}, {
177				desc: NewDesc(
178					memstatNamespace("buck_hash_sys_bytes"),
179					"Number of bytes used by the profiling bucket hash table.",
180					nil, nil,
181				),
182				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
183				valType: GaugeValue,
184			}, {
185				desc: NewDesc(
186					memstatNamespace("gc_sys_bytes"),
187					"Number of bytes used for garbage collection system metadata.",
188					nil, nil,
189				),
190				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
191				valType: GaugeValue,
192			}, {
193				desc: NewDesc(
194					memstatNamespace("other_sys_bytes"),
195					"Number of bytes used for other system allocations.",
196					nil, nil,
197				),
198				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
199				valType: GaugeValue,
200			}, {
201				desc: NewDesc(
202					memstatNamespace("next_gc_bytes"),
203					"Number of heap bytes when next garbage collection will take place.",
204					nil, nil,
205				),
206				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
207				valType: GaugeValue,
208			}, {
209				desc: NewDesc(
210					memstatNamespace("last_gc_time_seconds"),
211					"Number of seconds since 1970 of last garbage collection.",
212					nil, nil,
213				),
214				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.LastGC*10 ^ 9) },
215				valType: GaugeValue,
216			},
217		},
218	}
219}
220
221func memstatNamespace(s string) string {
222	return fmt.Sprintf("go_memstats_%s", s)
223}
224
225// Describe returns all descriptions of the collector.
226func (c *goCollector) Describe(ch chan<- *Desc) {
227	ch <- c.goroutines.Desc()
228	ch <- c.gcDesc
229
230	for _, i := range c.metrics {
231		ch <- i.desc
232	}
233}
234
235// Collect returns the current state of all metrics of the collector.
236func (c *goCollector) Collect(ch chan<- Metric) {
237	c.goroutines.Set(float64(runtime.NumGoroutine()))
238	ch <- c.goroutines
239
240	var stats debug.GCStats
241	stats.PauseQuantiles = make([]time.Duration, 5)
242	debug.ReadGCStats(&stats)
243
244	quantiles := make(map[float64]float64)
245	for idx, pq := range stats.PauseQuantiles[1:] {
246		quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds()
247	}
248	quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
249	ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), quantiles)
250
251	ms := &runtime.MemStats{}
252	runtime.ReadMemStats(ms)
253	for _, i := range c.metrics {
254		ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms))
255	}
256}
257
258// memStatsMetrics provide description, value, and value type for memstat metrics.
259type memStatsMetrics []struct {
260	desc    *Desc
261	eval    func(*runtime.MemStats) float64
262	valType ValueType
263}
264