registry.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #pragma once
  2. #include <map>
  3. #include <memory>
  4. #include <mutex>
  5. #include <string>
  6. #include <vector>
  7. #include "prometheus/collectable.h"
  8. #include "prometheus/family.h"
  9. namespace prometheus {
  10. /// \brief Manages the collection of a number of metrics.
  11. ///
  12. /// The Registry is responsible to expose data to a class/method/function
  13. /// "bridge", which returns the metrics in a format Prometheus supports.
  14. ///
  15. /// The key class is the Collectable. This has a method - called Collect() -
  16. /// that returns zero or more metrics and their samples. The metrics are
  17. /// represented by the class Family<>, which implements the Collectable
  18. /// interface. A new metric is registered with BuildCounter(), BuildGauge(),
  19. /// BuildHistogram() or BuildSummary().
  20. ///
  21. /// The class is thread-safe. No concurrent call to any API of this type causes
  22. /// a data race.
  23. class Registry : public Collectable {
  24. public:
  25. /// \brief How to deal with repeatedly added family names for a type.
  26. ///
  27. /// Adding a family with the same name but different types is always an error
  28. /// and will lead to an exception.
  29. enum class InsertBehavior {
  30. /// \brief If a family with the same name and labels already exists return
  31. /// the existing one. If no family with that name exists create it.
  32. /// Otherwise throw.
  33. Merge,
  34. /// \brief Throws if a family with the same name already exists.
  35. Throw,
  36. /// \brief Never merge and always create a new family. This violates the
  37. /// prometheus specification but was the default behavior in earlier
  38. /// versions
  39. NonStandardAppend,
  40. };
  41. using FamilyPtr = std::unique_ptr<Family>;
  42. using Families = std::vector<FamilyPtr>;
  43. const InsertBehavior insert_behavior;
  44. mutable std::mutex mutex;
  45. Families families;
  46. /// \brief name Create a new registry.
  47. ///
  48. /// \param insert_behavior How to handle families with the same name.
  49. Registry (InsertBehavior insert_behavior_ = InsertBehavior::Merge)
  50. : insert_behavior(insert_behavior_) {}
  51. /// \brief Returns a list of metrics and their samples.
  52. ///
  53. /// Every time the Registry is scraped it calls each of the metrics Collect
  54. /// function.
  55. ///
  56. /// \return Zero or more metrics and their samples.
  57. virtual MetricFamilies Collect() const {
  58. std::lock_guard<std::mutex> lock{ mutex };
  59. MetricFamilies results;
  60. for (const FamilyPtr& family_ptr : families) {
  61. MetricFamilies metrics = family_ptr->Collect();
  62. results.insert(results.end(), std::make_move_iterator(metrics.begin()), std::make_move_iterator(metrics.end()));
  63. }
  64. return results;
  65. }
  66. template <typename CustomFamily>
  67. CustomFamily& Add (const std::string& name, const std::string& help, const Family::Labels& labels) {
  68. std::lock_guard<std::mutex> lock{ mutex };
  69. bool found_one_but_not_merge = false;
  70. for (const FamilyPtr& family_ptr : families) {
  71. if (family_ptr->GetName() == name) {
  72. if (family_ptr->type != CustomFamily::static_type) // found family with this name and with different type
  73. throw std::invalid_argument("Family name already exists with different type");
  74. else { // found family with this name and the same type
  75. switch (insert_behavior) {
  76. case InsertBehavior::Throw:
  77. throw std::invalid_argument("Family name already exists");
  78. case InsertBehavior::Merge:
  79. if (family_ptr->GetConstantLabels() == labels)
  80. return dynamic_cast<CustomFamily&>(*family_ptr);
  81. else // this strange rule was in previos version prometheus cpp
  82. found_one_but_not_merge = true;
  83. case InsertBehavior::NonStandardAppend:
  84. continue;
  85. }
  86. }
  87. }
  88. }
  89. if (found_one_but_not_merge) // this strange rule was in previos version prometheus cpp
  90. throw std::invalid_argument("Family name already exists with different labels");
  91. std::unique_ptr<CustomFamily> new_family_ptr (new CustomFamily(name, help, labels));
  92. CustomFamily& new_family = *new_family_ptr;
  93. families.push_back(std::move(new_family_ptr));
  94. return new_family;
  95. }
  96. };
  97. } // namespace prometheus