blob: ba3b9333edde0d95b7c573fb81d44edab5bb5fd9 [file] [log] [blame]
khenaidooffe076b2019-01-15 16:08:08 -05001// Copyright 2018 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package prometheus
15
16import (
17 "fmt"
18 "runtime"
19 "runtime/debug"
20 "time"
21)
22
23type goCollector struct {
24 goroutinesDesc *Desc
25 threadsDesc *Desc
26 gcDesc *Desc
27 goInfoDesc *Desc
28
29 // metrics to describe and collect
30 metrics memStatsMetrics
31}
32
33// NewGoCollector returns a collector which exports metrics about the current Go
34// process. This includes memory stats. To collect those, runtime.ReadMemStats
35// is called. This causes a stop-the-world, which is very short with Go1.9+
36// (~25µs). However, with older Go versions, the stop-the-world duration depends
37// on the heap size and can be quite significant (~1.7 ms/GiB as per
38// https://go-review.googlesource.com/c/go/+/34937).
39func NewGoCollector() Collector {
40 return &goCollector{
41 goroutinesDesc: NewDesc(
42 "go_goroutines",
43 "Number of goroutines that currently exist.",
44 nil, nil),
45 threadsDesc: NewDesc(
46 "go_threads",
47 "Number of OS threads created.",
48 nil, nil),
49 gcDesc: NewDesc(
50 "go_gc_duration_seconds",
51 "A summary of the GC invocation durations.",
52 nil, nil),
53 goInfoDesc: NewDesc(
54 "go_info",
55 "Information about the Go environment.",
56 nil, Labels{"version": runtime.Version()}),
57 metrics: memStatsMetrics{
58 {
59 desc: NewDesc(
60 memstatNamespace("alloc_bytes"),
61 "Number of bytes allocated and still in use.",
62 nil, nil,
63 ),
64 eval: func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
65 valType: GaugeValue,
66 }, {
67 desc: NewDesc(
68 memstatNamespace("alloc_bytes_total"),
69 "Total number of bytes allocated, even if freed.",
70 nil, nil,
71 ),
72 eval: func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
73 valType: CounterValue,
74 }, {
75 desc: NewDesc(
76 memstatNamespace("sys_bytes"),
77 "Number of bytes obtained from system.",
78 nil, nil,
79 ),
80 eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
81 valType: GaugeValue,
82 }, {
83 desc: NewDesc(
84 memstatNamespace("lookups_total"),
85 "Total number of pointer lookups.",
86 nil, nil,
87 ),
88 eval: func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) },
89 valType: CounterValue,
90 }, {
91 desc: NewDesc(
92 memstatNamespace("mallocs_total"),
93 "Total number of mallocs.",
94 nil, nil,
95 ),
96 eval: func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
97 valType: CounterValue,
98 }, {
99 desc: NewDesc(
100 memstatNamespace("frees_total"),
101 "Total number of frees.",
102 nil, nil,
103 ),
104 eval: func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
105 valType: CounterValue,
106 }, {
107 desc: NewDesc(
108 memstatNamespace("heap_alloc_bytes"),
109 "Number of heap bytes allocated and still in use.",
110 nil, nil,
111 ),
112 eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
113 valType: GaugeValue,
114 }, {
115 desc: NewDesc(
116 memstatNamespace("heap_sys_bytes"),
117 "Number of heap bytes obtained from system.",
118 nil, nil,
119 ),
120 eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
121 valType: GaugeValue,
122 }, {
123 desc: NewDesc(
124 memstatNamespace("heap_idle_bytes"),
125 "Number of heap bytes waiting to be used.",
126 nil, nil,
127 ),
128 eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
129 valType: GaugeValue,
130 }, {
131 desc: NewDesc(
132 memstatNamespace("heap_inuse_bytes"),
133 "Number of heap bytes that are in use.",
134 nil, nil,
135 ),
136 eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
137 valType: GaugeValue,
138 }, {
139 desc: NewDesc(
140 memstatNamespace("heap_released_bytes"),
141 "Number of heap bytes released to OS.",
142 nil, nil,
143 ),
144 eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
145 valType: GaugeValue,
146 }, {
147 desc: NewDesc(
148 memstatNamespace("heap_objects"),
149 "Number of allocated objects.",
150 nil, nil,
151 ),
152 eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
153 valType: GaugeValue,
154 }, {
155 desc: NewDesc(
156 memstatNamespace("stack_inuse_bytes"),
157 "Number of bytes in use by the stack allocator.",
158 nil, nil,
159 ),
160 eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
161 valType: GaugeValue,
162 }, {
163 desc: NewDesc(
164 memstatNamespace("stack_sys_bytes"),
165 "Number of bytes obtained from system for stack allocator.",
166 nil, nil,
167 ),
168 eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
169 valType: GaugeValue,
170 }, {
171 desc: NewDesc(
172 memstatNamespace("mspan_inuse_bytes"),
173 "Number of bytes in use by mspan structures.",
174 nil, nil,
175 ),
176 eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
177 valType: GaugeValue,
178 }, {
179 desc: NewDesc(
180 memstatNamespace("mspan_sys_bytes"),
181 "Number of bytes used for mspan structures obtained from system.",
182 nil, nil,
183 ),
184 eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
185 valType: GaugeValue,
186 }, {
187 desc: NewDesc(
188 memstatNamespace("mcache_inuse_bytes"),
189 "Number of bytes in use by mcache structures.",
190 nil, nil,
191 ),
192 eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
193 valType: GaugeValue,
194 }, {
195 desc: NewDesc(
196 memstatNamespace("mcache_sys_bytes"),
197 "Number of bytes used for mcache structures obtained from system.",
198 nil, nil,
199 ),
200 eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
201 valType: GaugeValue,
202 }, {
203 desc: NewDesc(
204 memstatNamespace("buck_hash_sys_bytes"),
205 "Number of bytes used by the profiling bucket hash table.",
206 nil, nil,
207 ),
208 eval: func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
209 valType: GaugeValue,
210 }, {
211 desc: NewDesc(
212 memstatNamespace("gc_sys_bytes"),
213 "Number of bytes used for garbage collection system metadata.",
214 nil, nil,
215 ),
216 eval: func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
217 valType: GaugeValue,
218 }, {
219 desc: NewDesc(
220 memstatNamespace("other_sys_bytes"),
221 "Number of bytes used for other system allocations.",
222 nil, nil,
223 ),
224 eval: func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
225 valType: GaugeValue,
226 }, {
227 desc: NewDesc(
228 memstatNamespace("next_gc_bytes"),
229 "Number of heap bytes when next garbage collection will take place.",
230 nil, nil,
231 ),
232 eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
233 valType: GaugeValue,
234 }, {
235 desc: NewDesc(
236 memstatNamespace("last_gc_time_seconds"),
237 "Number of seconds since 1970 of last garbage collection.",
238 nil, nil,
239 ),
240 eval: func(ms *runtime.MemStats) float64 { return float64(ms.LastGC) / 1e9 },
241 valType: GaugeValue,
242 }, {
243 desc: NewDesc(
244 memstatNamespace("gc_cpu_fraction"),
245 "The fraction of this program's available CPU time used by the GC since the program started.",
246 nil, nil,
247 ),
248 eval: func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction },
249 valType: GaugeValue,
250 },
251 },
252 }
253}
254
255func memstatNamespace(s string) string {
256 return fmt.Sprintf("go_memstats_%s", s)
257}
258
259// Describe returns all descriptions of the collector.
260func (c *goCollector) Describe(ch chan<- *Desc) {
261 ch <- c.goroutinesDesc
262 ch <- c.threadsDesc
263 ch <- c.gcDesc
264 ch <- c.goInfoDesc
265 for _, i := range c.metrics {
266 ch <- i.desc
267 }
268}
269
270// Collect returns the current state of all metrics of the collector.
271func (c *goCollector) Collect(ch chan<- Metric) {
272 ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine()))
273 n, _ := runtime.ThreadCreateProfile(nil)
274 ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n))
275
276 var stats debug.GCStats
277 stats.PauseQuantiles = make([]time.Duration, 5)
278 debug.ReadGCStats(&stats)
279
280 quantiles := make(map[float64]float64)
281 for idx, pq := range stats.PauseQuantiles[1:] {
282 quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds()
283 }
284 quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
285 ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), stats.PauseTotal.Seconds(), quantiles)
286
287 ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1)
288
289 ms := &runtime.MemStats{}
290 runtime.ReadMemStats(ms)
291 for _, i := range c.metrics {
292 ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms))
293 }
294}
295
296// memStatsMetrics provide description, value, and value type for memstat metrics.
297type memStatsMetrics []struct {
298 desc *Desc
299 eval func(*runtime.MemStats) float64
300 valType ValueType
301}