vec.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. // Copyright 2014 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. "sync"
  17. "github.com/prometheus/common/model"
  18. )
  19. // MetricVec is a Collector to bundle metrics of the same name that
  20. // differ in their label values. MetricVec is usually not used directly but as a
  21. // building block for implementations of vectors of a given metric
  22. // type. GaugeVec, CounterVec, SummaryVec, and UntypedVec are examples already
  23. // provided in this package.
  24. type MetricVec struct {
  25. mtx sync.RWMutex // Protects the children.
  26. children map[uint64][]metricWithLabelValues
  27. desc *Desc
  28. newMetric func(labelValues ...string) Metric
  29. hashAdd func(h uint64, s string) uint64 // replace hash function for testing collision handling
  30. hashAddByte func(h uint64, b byte) uint64
  31. }
  32. // newMetricVec returns an initialized MetricVec. The concrete value is
  33. // returned for embedding into another struct.
  34. func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *MetricVec {
  35. return &MetricVec{
  36. children: map[uint64][]metricWithLabelValues{},
  37. desc: desc,
  38. newMetric: newMetric,
  39. hashAdd: hashAdd,
  40. hashAddByte: hashAddByte,
  41. }
  42. }
  43. // metricWithLabelValues provides the metric and its label values for
  44. // disambiguation on hash collision.
  45. type metricWithLabelValues struct {
  46. values []string
  47. metric Metric
  48. }
  49. // Describe implements Collector. The length of the returned slice
  50. // is always one.
  51. func (m *MetricVec) Describe(ch chan<- *Desc) {
  52. ch <- m.desc
  53. }
  54. // Collect implements Collector.
  55. func (m *MetricVec) Collect(ch chan<- Metric) {
  56. m.mtx.RLock()
  57. defer m.mtx.RUnlock()
  58. for _, metrics := range m.children {
  59. for _, metric := range metrics {
  60. ch <- metric.metric
  61. }
  62. }
  63. }
  64. // GetMetricWithLabelValues returns the Metric for the given slice of label
  65. // values (same order as the VariableLabels in Desc). If that combination of
  66. // label values is accessed for the first time, a new Metric is created.
  67. //
  68. // It is possible to call this method without using the returned Metric to only
  69. // create the new Metric but leave it at its start value (e.g. a Summary or
  70. // Histogram without any observations). See also the SummaryVec example.
  71. //
  72. // Keeping the Metric for later use is possible (and should be considered if
  73. // performance is critical), but keep in mind that Reset, DeleteLabelValues and
  74. // Delete can be used to delete the Metric from the MetricVec. In that case, the
  75. // Metric will still exist, but it will not be exported anymore, even if a
  76. // Metric with the same label values is created later. See also the CounterVec
  77. // example.
  78. //
  79. // An error is returned if the number of label values is not the same as the
  80. // number of VariableLabels in Desc.
  81. //
  82. // Note that for more than one label value, this method is prone to mistakes
  83. // caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
  84. // an alternative to avoid that type of mistake. For higher label numbers, the
  85. // latter has a much more readable (albeit more verbose) syntax, but it comes
  86. // with a performance overhead (for creating and processing the Labels map).
  87. // See also the GaugeVec example.
  88. func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) {
  89. h, err := m.hashLabelValues(lvs)
  90. if err != nil {
  91. return nil, err
  92. }
  93. return m.getOrCreateMetricWithLabelValues(h, lvs), nil
  94. }
  95. // GetMetricWith returns the Metric for the given Labels map (the label names
  96. // must match those of the VariableLabels in Desc). If that label map is
  97. // accessed for the first time, a new Metric is created. Implications of
  98. // creating a Metric without using it and keeping the Metric for later use are
  99. // the same as for GetMetricWithLabelValues.
  100. //
  101. // An error is returned if the number and names of the Labels are inconsistent
  102. // with those of the VariableLabels in Desc.
  103. //
  104. // This method is used for the same purpose as
  105. // GetMetricWithLabelValues(...string). See there for pros and cons of the two
  106. // methods.
  107. func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) {
  108. h, err := m.hashLabels(labels)
  109. if err != nil {
  110. return nil, err
  111. }
  112. return m.getOrCreateMetricWithLabels(h, labels), nil
  113. }
  114. // WithLabelValues works as GetMetricWithLabelValues, but panics if an error
  115. // occurs. The method allows neat syntax like:
  116. // httpReqs.WithLabelValues("404", "POST").Inc()
  117. func (m *MetricVec) WithLabelValues(lvs ...string) Metric {
  118. metric, err := m.GetMetricWithLabelValues(lvs...)
  119. if err != nil {
  120. panic(err)
  121. }
  122. return metric
  123. }
  124. // With works as GetMetricWith, but panics if an error occurs. The method allows
  125. // neat syntax like:
  126. // httpReqs.With(Labels{"status":"404", "method":"POST"}).Inc()
  127. func (m *MetricVec) With(labels Labels) Metric {
  128. metric, err := m.GetMetricWith(labels)
  129. if err != nil {
  130. panic(err)
  131. }
  132. return metric
  133. }
  134. // DeleteLabelValues removes the metric where the variable labels are the same
  135. // as those passed in as labels (same order as the VariableLabels in Desc). It
  136. // returns true if a metric was deleted.
  137. //
  138. // It is not an error if the number of label values is not the same as the
  139. // number of VariableLabels in Desc. However, such inconsistent label count can
  140. // never match an actual Metric, so the method will always return false in that
  141. // case.
  142. //
  143. // Note that for more than one label value, this method is prone to mistakes
  144. // caused by an incorrect order of arguments. Consider Delete(Labels) as an
  145. // alternative to avoid that type of mistake. For higher label numbers, the
  146. // latter has a much more readable (albeit more verbose) syntax, but it comes
  147. // with a performance overhead (for creating and processing the Labels map).
  148. // See also the CounterVec example.
  149. func (m *MetricVec) DeleteLabelValues(lvs ...string) bool {
  150. m.mtx.Lock()
  151. defer m.mtx.Unlock()
  152. h, err := m.hashLabelValues(lvs)
  153. if err != nil {
  154. return false
  155. }
  156. return m.deleteByHashWithLabelValues(h, lvs)
  157. }
  158. // Delete deletes the metric where the variable labels are the same as those
  159. // passed in as labels. It returns true if a metric was deleted.
  160. //
  161. // It is not an error if the number and names of the Labels are inconsistent
  162. // with those of the VariableLabels in the Desc of the MetricVec. However, such
  163. // inconsistent Labels can never match an actual Metric, so the method will
  164. // always return false in that case.
  165. //
  166. // This method is used for the same purpose as DeleteLabelValues(...string). See
  167. // there for pros and cons of the two methods.
  168. func (m *MetricVec) Delete(labels Labels) bool {
  169. m.mtx.Lock()
  170. defer m.mtx.Unlock()
  171. h, err := m.hashLabels(labels)
  172. if err != nil {
  173. return false
  174. }
  175. return m.deleteByHashWithLabels(h, labels)
  176. }
  177. // deleteByHashWithLabelValues removes the metric from the hash bucket h. If
  178. // there are multiple matches in the bucket, use lvs to select a metric and
  179. // remove only that metric.
  180. func (m *MetricVec) deleteByHashWithLabelValues(h uint64, lvs []string) bool {
  181. metrics, ok := m.children[h]
  182. if !ok {
  183. return false
  184. }
  185. i := m.findMetricWithLabelValues(metrics, lvs)
  186. if i >= len(metrics) {
  187. return false
  188. }
  189. if len(metrics) > 1 {
  190. m.children[h] = append(metrics[:i], metrics[i+1:]...)
  191. } else {
  192. delete(m.children, h)
  193. }
  194. return true
  195. }
  196. // deleteByHashWithLabels removes the metric from the hash bucket h. If there
  197. // are multiple matches in the bucket, use lvs to select a metric and remove
  198. // only that metric.
  199. func (m *MetricVec) deleteByHashWithLabels(h uint64, labels Labels) bool {
  200. metrics, ok := m.children[h]
  201. if !ok {
  202. return false
  203. }
  204. i := m.findMetricWithLabels(metrics, labels)
  205. if i >= len(metrics) {
  206. return false
  207. }
  208. if len(metrics) > 1 {
  209. m.children[h] = append(metrics[:i], metrics[i+1:]...)
  210. } else {
  211. delete(m.children, h)
  212. }
  213. return true
  214. }
  215. // Reset deletes all metrics in this vector.
  216. func (m *MetricVec) Reset() {
  217. m.mtx.Lock()
  218. defer m.mtx.Unlock()
  219. for h := range m.children {
  220. delete(m.children, h)
  221. }
  222. }
  223. func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) {
  224. if len(vals) != len(m.desc.variableLabels) {
  225. return 0, errInconsistentCardinality
  226. }
  227. h := hashNew()
  228. for _, val := range vals {
  229. h = m.hashAdd(h, val)
  230. h = m.hashAddByte(h, model.SeparatorByte)
  231. }
  232. return h, nil
  233. }
  234. func (m *MetricVec) hashLabels(labels Labels) (uint64, error) {
  235. if len(labels) != len(m.desc.variableLabels) {
  236. return 0, errInconsistentCardinality
  237. }
  238. h := hashNew()
  239. for _, label := range m.desc.variableLabels {
  240. val, ok := labels[label]
  241. if !ok {
  242. return 0, fmt.Errorf("label name %q missing in label map", label)
  243. }
  244. h = m.hashAdd(h, val)
  245. h = m.hashAddByte(h, model.SeparatorByte)
  246. }
  247. return h, nil
  248. }
  249. // getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
  250. // or creates it and returns the new one.
  251. //
  252. // This function holds the mutex.
  253. func (m *MetricVec) getOrCreateMetricWithLabelValues(hash uint64, lvs []string) Metric {
  254. m.mtx.RLock()
  255. metric, ok := m.getMetricWithLabelValues(hash, lvs)
  256. m.mtx.RUnlock()
  257. if ok {
  258. return metric
  259. }
  260. m.mtx.Lock()
  261. defer m.mtx.Unlock()
  262. metric, ok = m.getMetricWithLabelValues(hash, lvs)
  263. if !ok {
  264. // Copy to avoid allocation in case wo don't go down this code path.
  265. copiedLVs := make([]string, len(lvs))
  266. copy(copiedLVs, lvs)
  267. metric = m.newMetric(copiedLVs...)
  268. m.children[hash] = append(m.children[hash], metricWithLabelValues{values: copiedLVs, metric: metric})
  269. }
  270. return metric
  271. }
  272. // getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
  273. // or creates it and returns the new one.
  274. //
  275. // This function holds the mutex.
  276. func (m *MetricVec) getOrCreateMetricWithLabels(hash uint64, labels Labels) Metric {
  277. m.mtx.RLock()
  278. metric, ok := m.getMetricWithLabels(hash, labels)
  279. m.mtx.RUnlock()
  280. if ok {
  281. return metric
  282. }
  283. m.mtx.Lock()
  284. defer m.mtx.Unlock()
  285. metric, ok = m.getMetricWithLabels(hash, labels)
  286. if !ok {
  287. lvs := m.extractLabelValues(labels)
  288. metric = m.newMetric(lvs...)
  289. m.children[hash] = append(m.children[hash], metricWithLabelValues{values: lvs, metric: metric})
  290. }
  291. return metric
  292. }
  293. // getMetricWithLabelValues gets a metric while handling possible collisions in
  294. // the hash space. Must be called while holding read mutex.
  295. func (m *MetricVec) getMetricWithLabelValues(h uint64, lvs []string) (Metric, bool) {
  296. metrics, ok := m.children[h]
  297. if ok {
  298. if i := m.findMetricWithLabelValues(metrics, lvs); i < len(metrics) {
  299. return metrics[i].metric, true
  300. }
  301. }
  302. return nil, false
  303. }
  304. // getMetricWithLabels gets a metric while handling possible collisions in
  305. // the hash space. Must be called while holding read mutex.
  306. func (m *MetricVec) getMetricWithLabels(h uint64, labels Labels) (Metric, bool) {
  307. metrics, ok := m.children[h]
  308. if ok {
  309. if i := m.findMetricWithLabels(metrics, labels); i < len(metrics) {
  310. return metrics[i].metric, true
  311. }
  312. }
  313. return nil, false
  314. }
  315. // findMetricWithLabelValues returns the index of the matching metric or
  316. // len(metrics) if not found.
  317. func (m *MetricVec) findMetricWithLabelValues(metrics []metricWithLabelValues, lvs []string) int {
  318. for i, metric := range metrics {
  319. if m.matchLabelValues(metric.values, lvs) {
  320. return i
  321. }
  322. }
  323. return len(metrics)
  324. }
  325. // findMetricWithLabels returns the index of the matching metric or len(metrics)
  326. // if not found.
  327. func (m *MetricVec) findMetricWithLabels(metrics []metricWithLabelValues, labels Labels) int {
  328. for i, metric := range metrics {
  329. if m.matchLabels(metric.values, labels) {
  330. return i
  331. }
  332. }
  333. return len(metrics)
  334. }
  335. func (m *MetricVec) matchLabelValues(values []string, lvs []string) bool {
  336. if len(values) != len(lvs) {
  337. return false
  338. }
  339. for i, v := range values {
  340. if v != lvs[i] {
  341. return false
  342. }
  343. }
  344. return true
  345. }
  346. func (m *MetricVec) matchLabels(values []string, labels Labels) bool {
  347. if len(labels) != len(values) {
  348. return false
  349. }
  350. for i, k := range m.desc.variableLabels {
  351. if values[i] != labels[k] {
  352. return false
  353. }
  354. }
  355. return true
  356. }
  357. func (m *MetricVec) extractLabelValues(labels Labels) []string {
  358. labelValues := make([]string, len(labels))
  359. for i, k := range m.desc.variableLabels {
  360. labelValues[i] = labels[k]
  361. }
  362. return labelValues
  363. }