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