jmetrics.hpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2021 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #pragma once
  14. #include <string>
  15. #include <utility>
  16. #include <vector>
  17. #include <map>
  18. #include <atomic>
  19. #include <chrono>
  20. #include <mutex>
  21. #include <memory>
  22. #include <thread>
  23. #include <unordered_set>
  24. #include "jiface.hpp"
  25. #include "jptree.hpp"
  26. #include "platform.h"
  27. namespace hpccMetrics {
  28. class MetricsReporter;
  29. MetricsReporter jlib_decl &queryMetricsReporter();
  30. /*
  31. * Enumerates the metric type.
  32. */
  33. enum MetricType
  34. {
  35. METRICS_COUNTER,
  36. METRICS_GAUGE
  37. };
  38. /*
  39. * IMetric
  40. *
  41. * Interface defining a metric
  42. */
  43. interface IMetric
  44. {
  45. virtual ~IMetric() = default;
  46. /*
  47. * Returns the metric name
  48. */
  49. virtual const std::string &queryName() const = 0;
  50. /*
  51. * Returns metric description
  52. */
  53. virtual const std::string &queryDescription() const = 0;
  54. /*
  55. * Returns the metric type.
  56. */
  57. virtual MetricType queryMetricType() const = 0;
  58. /*
  59. * Get current measurement
  60. */
  61. virtual __uint64 queryValue() const = 0;
  62. };
  63. /*
  64. * Concrete base class implementation of the IMetric interface. All metrics inherit
  65. * from this class.
  66. */
  67. class jlib_decl MetricBase : public IMetric
  68. {
  69. public:
  70. virtual ~MetricBase() = default;
  71. virtual const std::string &queryName() const override { return name; }
  72. virtual const std::string &queryDescription() const override { return description; }
  73. virtual MetricType queryMetricType() const override { return metricType; }
  74. protected:
  75. // No one should be able to create one of these
  76. MetricBase(const char *_name, const char *_desc, MetricType _metricType) :
  77. name{_name},
  78. description{_desc},
  79. metricType{_metricType} { }
  80. protected:
  81. std::string name;
  82. std::string description;
  83. MetricType metricType;
  84. };
  85. class jlib_decl MetricVal : public MetricBase
  86. {
  87. public:
  88. virtual __uint64 queryValue() const override { return value; }
  89. protected:
  90. MetricVal(const char *name, const char *desc, MetricType metricType) :
  91. MetricBase(name, desc, metricType) {}
  92. std::atomic<__uint64> value{0};
  93. };
  94. /*
  95. * Metric used to count events. Count is a monotonically increasing value
  96. */
  97. class jlib_decl CounterMetric : public MetricVal
  98. {
  99. public:
  100. CounterMetric(const char *name, const char *description) :
  101. MetricVal{name, description, MetricType::METRICS_COUNTER} { }
  102. void inc(uint64_t val = 1)
  103. {
  104. value.fetch_add(val);
  105. }
  106. };
  107. /*
  108. * Metric used to track the current state of some internal measurement.
  109. */
  110. class jlib_decl GaugeMetric : public MetricVal
  111. {
  112. public:
  113. GaugeMetric(const char *name, const char *description) :
  114. MetricVal{name, description, MetricType::METRICS_GAUGE} { }
  115. /*
  116. * Update the value as indicated
  117. */
  118. void add(int64_t delta)
  119. {
  120. value += delta;
  121. }
  122. /*
  123. * Set the value
  124. */
  125. void set(int64_t val)
  126. {
  127. value = val;
  128. }
  129. };
  130. template<typename T>
  131. class CustomMetric : public MetricBase
  132. {
  133. public:
  134. CustomMetric(const char *name, const char *desc, MetricType metricType, T &_value) :
  135. MetricBase(name, desc, metricType),
  136. value{_value} { }
  137. virtual __uint64 queryValue() const override
  138. {
  139. return static_cast<__uint64>(value);
  140. }
  141. protected:
  142. T &value;
  143. };
  144. class jlib_decl MetricSink
  145. {
  146. public:
  147. virtual ~MetricSink() = default;
  148. virtual void startCollection(MetricsReporter *pReporter) = 0;
  149. virtual void stopCollection() = 0;
  150. const std::string &queryName() const { return name; }
  151. const std::string &queryType() const { return type; }
  152. protected:
  153. MetricSink(const char *_name, const char *_type) :
  154. name{_name},
  155. type{_type} { }
  156. protected:
  157. std::string name;
  158. std::string type;
  159. MetricsReporter *pReporter = nullptr;
  160. };
  161. class jlib_decl PeriodicMetricSink : public MetricSink
  162. {
  163. public:
  164. virtual ~PeriodicMetricSink() override;
  165. virtual void startCollection(MetricsReporter *pReporter) override;
  166. virtual void stopCollection() override;
  167. protected:
  168. explicit PeriodicMetricSink(const char *name, const char *type, const IPropertyTree *pSettingsTree);
  169. virtual void prepareToStartCollecting() = 0;
  170. virtual void collectingHasStopped() = 0;
  171. virtual void doCollection() = 0;
  172. void collectionThread();
  173. void doStopCollecting();
  174. protected:
  175. unsigned collectionPeriodSeconds;
  176. std::thread collectThread;
  177. std::atomic<bool> stopCollectionFlag{false};
  178. bool isCollecting = false;
  179. Semaphore waitSem;
  180. };
  181. extern "C" { typedef hpccMetrics::MetricSink* (*getSinkInstance)(const char *, const IPropertyTree *pSettingsTree); }
  182. struct SinkInfo
  183. {
  184. explicit SinkInfo(MetricSink *_pSink) : pSink{_pSink} {}
  185. MetricSink *pSink = nullptr; // ptr to the sink
  186. std::vector<std::string> reportMetrics; // vector of metrics to report (empty for none)
  187. };
  188. class jlib_decl MetricsReporter
  189. {
  190. public:
  191. MetricsReporter() = default;
  192. ~MetricsReporter();
  193. void init(IPropertyTree *pMetricsTree);
  194. void addSink(MetricSink *pSink, const char *name); // for use by unit tests
  195. void addMetric(const std::shared_ptr<IMetric> &pMetric);
  196. void startCollecting();
  197. void stopCollecting();
  198. std::vector<std::shared_ptr<IMetric>> queryMetricsForReport(const std::string &sinkName);
  199. protected:
  200. void initializeSinks(IPropertyTreeIterator *pSinkIt);
  201. static MetricSink *getSinkFromLib(const char *type, const char *sinkName, const IPropertyTree *pSettingsTree);
  202. protected:
  203. StringBuffer componentPrefix;
  204. StringBuffer globalPrefix;
  205. std::map<std::string, std::unique_ptr<SinkInfo>> sinks;
  206. std::map<std::string, std::weak_ptr<IMetric>> metrics;
  207. std::mutex metricVectorMutex;
  208. };
  209. //
  210. // Convenience function templates to create metrics and add to the reporter
  211. template <typename T>
  212. std::shared_ptr<T> createMetricAndAddToReporter(const char *name, const char* desc)
  213. {
  214. std::shared_ptr<T> pMetric = std::make_shared<T>(name, desc);
  215. queryMetricsReporter().addMetric(pMetric);
  216. return pMetric;
  217. }
  218. template <typename T>
  219. std::shared_ptr<CustomMetric<T>> createCustomMetricAndAddToReporter(const char *name, const char *desc, MetricType metricType, T &value)
  220. {
  221. std::shared_ptr<CustomMetric<T>> pMetric = std::make_shared<CustomMetric<T>>(name, desc, metricType, value);
  222. queryMetricsReporter().addMetric(pMetric);
  223. return pMetric;
  224. }
  225. }