Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

102 строки
3.0 KiB

  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 internal
  14. import (
  15. "sort"
  16. dto "github.com/prometheus/client_model/go"
  17. )
  18. // LabelPairSorter implements sort.Interface. It is used to sort a slice of
  19. // dto.LabelPair pointers.
  20. type LabelPairSorter []*dto.LabelPair
  21. func (s LabelPairSorter) Len() int {
  22. return len(s)
  23. }
  24. func (s LabelPairSorter) Swap(i, j int) {
  25. s[i], s[j] = s[j], s[i]
  26. }
  27. func (s LabelPairSorter) Less(i, j int) bool {
  28. return s[i].GetName() < s[j].GetName()
  29. }
  30. // MetricSorter is a sortable slice of *dto.Metric.
  31. type MetricSorter []*dto.Metric
  32. func (s MetricSorter) Len() int {
  33. return len(s)
  34. }
  35. func (s MetricSorter) Swap(i, j int) {
  36. s[i], s[j] = s[j], s[i]
  37. }
  38. func (s MetricSorter) Less(i, j int) bool {
  39. if len(s[i].Label) != len(s[j].Label) {
  40. // This should not happen. The metrics are
  41. // inconsistent. However, we have to deal with the fact, as
  42. // people might use custom collectors or metric family injection
  43. // to create inconsistent metrics. So let's simply compare the
  44. // number of labels in this case. That will still yield
  45. // reproducible sorting.
  46. return len(s[i].Label) < len(s[j].Label)
  47. }
  48. for n, lp := range s[i].Label {
  49. vi := lp.GetValue()
  50. vj := s[j].Label[n].GetValue()
  51. if vi != vj {
  52. return vi < vj
  53. }
  54. }
  55. // We should never arrive here. Multiple metrics with the same
  56. // label set in the same scrape will lead to undefined ingestion
  57. // behavior. However, as above, we have to provide stable sorting
  58. // here, even for inconsistent metrics. So sort equal metrics
  59. // by their timestamp, with missing timestamps (implying "now")
  60. // coming last.
  61. if s[i].TimestampMs == nil {
  62. return false
  63. }
  64. if s[j].TimestampMs == nil {
  65. return true
  66. }
  67. return s[i].GetTimestampMs() < s[j].GetTimestampMs()
  68. }
  69. // NormalizeMetricFamilies returns a MetricFamily slice with empty
  70. // MetricFamilies pruned and the remaining MetricFamilies sorted by name within
  71. // the slice, with the contained Metrics sorted within each MetricFamily.
  72. func NormalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily {
  73. for _, mf := range metricFamiliesByName {
  74. sort.Sort(MetricSorter(mf.Metric))
  75. }
  76. names := make([]string, 0, len(metricFamiliesByName))
  77. for name, mf := range metricFamiliesByName {
  78. if len(mf.Metric) > 0 {
  79. names = append(names, name)
  80. }
  81. }
  82. sort.Strings(names)
  83. result := make([]*dto.MetricFamily, 0, len(names))
  84. for _, name := range names {
  85. result = append(result, metricFamiliesByName[name])
  86. }
  87. return result
  88. }