go_collector.go 9.1 KB

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