You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

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