jmetrics.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  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. #include "jstatcodes.h"
  28. #include "jatomic.hpp"
  29. namespace hpccMetrics {
  30. class MetricsManager;
  31. MetricsManager jlib_decl &queryMetricsManager();
  32. /*
  33. * Enumerates the metric type.
  34. */
  35. enum MetricType
  36. {
  37. METRICS_COUNTER,
  38. METRICS_GAUGE
  39. };
  40. struct MetricMetaDataItem
  41. {
  42. MetricMetaDataItem(const char *_key, const char *_value)
  43. : key{_key}, value{_value} {}
  44. std::string key;
  45. std::string value;
  46. };
  47. typedef std::vector<MetricMetaDataItem> MetricMetaData;
  48. /*
  49. * IMetric
  50. *
  51. * Interface defining a metric
  52. */
  53. interface IMetric
  54. {
  55. virtual ~IMetric() = default;
  56. /*
  57. * Returns the metric name
  58. */
  59. virtual const std::string &queryName() const = 0;
  60. /*
  61. * Returns metric description
  62. */
  63. virtual const std::string &queryDescription() const = 0;
  64. /*
  65. * Returns the metric type.
  66. */
  67. virtual MetricType queryMetricType() const = 0;
  68. /*
  69. * Get current measurement
  70. */
  71. virtual __uint64 queryValue() const = 0;
  72. /*
  73. * Query the meta data for the metric
  74. */
  75. virtual const MetricMetaData &queryMetaData() const = 0;
  76. /*
  77. * Get the units for the metric
  78. */
  79. virtual StatisticMeasure queryUnits() const = 0;
  80. };
  81. /*
  82. * Concrete base class implementation of the IMetric interface. All metrics inherit
  83. * from this class.
  84. */
  85. class jlib_decl MetricBase : public IMetric
  86. {
  87. public:
  88. virtual ~MetricBase() = default;
  89. virtual const std::string &queryName() const override { return name; }
  90. virtual const std::string &queryDescription() const override { return description; }
  91. virtual MetricType queryMetricType() const override { return metricType; }
  92. const MetricMetaData &queryMetaData() const { return metaData; }
  93. StatisticMeasure queryUnits() const override { return units; }
  94. protected:
  95. // No one should be able to create one of these
  96. MetricBase(const char *_name, const char *_desc, MetricType _metricType, StatisticMeasure _units, const MetricMetaData &_metaData) :
  97. name{_name},
  98. description{_desc},
  99. metricType{_metricType},
  100. units{_units},
  101. metaData{_metaData} { }
  102. protected:
  103. std::string name;
  104. std::string description;
  105. MetricType metricType;
  106. StatisticMeasure units;
  107. MetricMetaData metaData;
  108. };
  109. class jlib_decl MetricVal : public MetricBase
  110. {
  111. public:
  112. virtual __uint64 queryValue() const override { return value; }
  113. protected:
  114. MetricVal(const char *name, const char *desc, MetricType metricType, StatisticMeasure _units, const MetricMetaData &_metaData) :
  115. MetricBase(name, desc, metricType, _units, _metaData) {}
  116. RelaxedAtomic<__uint64> value{0};
  117. };
  118. /*
  119. * Metric used to count events. Count is a monotonically increasing value
  120. */
  121. class jlib_decl CounterMetric : public MetricVal
  122. {
  123. public:
  124. CounterMetric(const char *name, const char *description, StatisticMeasure _units, const MetricMetaData &_metaData = MetricMetaData()) :
  125. MetricVal{name, description, MetricType::METRICS_COUNTER, _units, _metaData} { }
  126. void inc(uint64_t val)
  127. {
  128. value.fetch_add(val);
  129. }
  130. void fastInc(uint16_t val)
  131. {
  132. value.fastAdd(val);
  133. }
  134. };
  135. /*
  136. * Metric used to track the current state of some internal measurement.
  137. */
  138. class jlib_decl GaugeMetric : public MetricVal
  139. {
  140. public:
  141. GaugeMetric(const char *name, const char *description, StatisticMeasure _units, const MetricMetaData &_metaData = MetricMetaData()) :
  142. MetricVal{name, description, MetricType::METRICS_GAUGE, _units, _metaData} { }
  143. void adjust(int64_t delta)
  144. {
  145. value += delta;
  146. }
  147. void fastAdjust(int64_t delta)
  148. {
  149. value.fastAdd(delta);
  150. }
  151. /*
  152. * Set the value
  153. */
  154. void set(int64_t val)
  155. {
  156. value = val;
  157. }
  158. };
  159. class jlib_decl GaugeMetricFromCounters : public MetricVal
  160. {
  161. public:
  162. GaugeMetricFromCounters(const char *name, const char *description, StatisticMeasure _units,
  163. const std::shared_ptr<CounterMetric> &_pBeginCounter, const std::shared_ptr<CounterMetric> &_pEndCounter,
  164. const MetricMetaData &_metaData = MetricMetaData()) :
  165. MetricVal{name, description, MetricType::METRICS_GAUGE, _units, _metaData},
  166. pBeginCounter{_pBeginCounter},
  167. pEndCounter{_pEndCounter}
  168. {
  169. assert(pBeginCounter->queryUnits() == pEndCounter->queryUnits());
  170. }
  171. virtual __uint64 queryValue() const override
  172. {
  173. auto endValue = pEndCounter->queryValue();
  174. return pBeginCounter->queryValue() - endValue;
  175. }
  176. protected:
  177. std::shared_ptr<CounterMetric> pBeginCounter;
  178. std::shared_ptr<CounterMetric> pEndCounter;
  179. };
  180. template<typename T>
  181. class CustomMetric : public MetricBase
  182. {
  183. public:
  184. CustomMetric(const char *name, const char *desc, MetricType metricType, T &_value, StatisticMeasure _units, const MetricMetaData &_metaData = MetricMetaData()) :
  185. MetricBase(name, desc, metricType, _units, _metaData),
  186. value{_value} { }
  187. virtual __uint64 queryValue() const override
  188. {
  189. return static_cast<__uint64>(value);
  190. }
  191. protected:
  192. T &value;
  193. };
  194. class jlib_decl MetricSink
  195. {
  196. public:
  197. virtual ~MetricSink() = default;
  198. virtual void startCollection(MetricsManager *pManager) = 0;
  199. virtual void stopCollection() = 0;
  200. const std::string &queryName() const { return name; }
  201. const std::string &queryType() const { return type; }
  202. protected:
  203. MetricSink(const char *_name, const char *_type) :
  204. name{_name},
  205. type{_type} { }
  206. protected:
  207. std::string name;
  208. std::string type;
  209. MetricsManager *pManager = nullptr;
  210. };
  211. class jlib_decl PeriodicMetricSink : public MetricSink
  212. {
  213. public:
  214. virtual ~PeriodicMetricSink() override;
  215. virtual void startCollection(MetricsManager *pManager) override;
  216. virtual void stopCollection() override;
  217. protected:
  218. explicit PeriodicMetricSink(const char *name, const char *type, const IPropertyTree *pSettingsTree);
  219. virtual void prepareToStartCollecting() = 0;
  220. virtual void collectingHasStopped() = 0;
  221. virtual void doCollection() = 0;
  222. void collectionThread();
  223. void doStopCollecting();
  224. protected:
  225. unsigned collectionPeriodSeconds;
  226. std::thread collectThread;
  227. std::atomic<bool> stopCollectionFlag{false};
  228. bool isCollecting = false;
  229. Semaphore waitSem;
  230. };
  231. extern "C" { typedef hpccMetrics::MetricSink* (*getSinkInstance)(const char *, const IPropertyTree *pSettingsTree); }
  232. struct SinkInfo
  233. {
  234. explicit SinkInfo(MetricSink *_pSink) : pSink{_pSink} {}
  235. MetricSink *pSink = nullptr; // ptr to the sink
  236. std::vector<std::string> reportMetrics; // vector of metrics to report (empty for none)
  237. };
  238. class jlib_decl MetricsManager
  239. {
  240. public:
  241. MetricsManager() {}
  242. ~MetricsManager();
  243. void init(IPropertyTree *pMetricsTree);
  244. void addSink(MetricSink *pSink, const char *name); // for use by unit tests
  245. bool addMetric(const std::shared_ptr<IMetric> &pMetric);
  246. void startCollecting();
  247. void stopCollecting();
  248. std::vector<std::shared_ptr<IMetric>> queryMetricsForReport(const std::string &sinkName);
  249. const char * queryUnitsString(StatisticMeasure units) const;
  250. protected:
  251. void initializeSinks(IPropertyTreeIterator *pSinkIt);
  252. static MetricSink *getSinkFromLib(const char *type, const char *sinkName, const IPropertyTree *pSettingsTree);
  253. protected:
  254. StringBuffer componentPrefix;
  255. StringBuffer globalPrefix;
  256. std::map<std::string, std::unique_ptr<SinkInfo>> sinks;
  257. std::map<std::string, std::weak_ptr<IMetric>> metrics;
  258. std::mutex metricVectorMutex;
  259. };
  260. //
  261. // Convenience function templates to create metrics and add to the manager
  262. template <typename T>
  263. std::shared_ptr<T> createMetricAndAddToManager(const char *name, const char* desc, StatisticMeasure units, const MetricMetaData &metaData = MetricMetaData())
  264. {
  265. std::shared_ptr<T> pMetric = std::make_shared<T>(name, desc, units, metaData);
  266. queryMetricsManager().addMetric(pMetric);
  267. return pMetric;
  268. }
  269. inline std::shared_ptr<CounterMetric> registerCounterMetric(const char *name, const char* desc, StatisticMeasure units, const MetricMetaData &metaData = MetricMetaData())
  270. {
  271. return createMetricAndAddToManager<CounterMetric>(name, desc, units, metaData);
  272. }
  273. inline std::shared_ptr<GaugeMetric> registerGaugeMetric(const char *name, const char* desc, StatisticMeasure units, const MetricMetaData &metaData = MetricMetaData())
  274. {
  275. return createMetricAndAddToManager<GaugeMetric>(name, desc, units, metaData);
  276. }
  277. inline std::shared_ptr<GaugeMetricFromCounters> registerGaugeFromCountersMetric(const char *name, const char* desc, StatisticMeasure units,
  278. const std::shared_ptr<CounterMetric> &pBeginCounter, const std::shared_ptr<CounterMetric> &pEndCounter,
  279. const MetricMetaData &metaData = MetricMetaData())
  280. {
  281. std::shared_ptr<GaugeMetricFromCounters> pMetric = std::make_shared<GaugeMetricFromCounters>(name, desc, units, pBeginCounter, pEndCounter, metaData);
  282. queryMetricsManager().addMetric(pMetric);
  283. return pMetric;
  284. }
  285. template <typename T>
  286. std::shared_ptr<CustomMetric<T>> registerCustomMetric(const char *name, const char *desc, MetricType metricType, T &value, StatisticMeasure units, const MetricMetaData &metaData = MetricMetaData())
  287. {
  288. std::shared_ptr<CustomMetric<T>> pMetric = std::make_shared<CustomMetric<T>>(name, desc, metricType, value, units, metaData);
  289. queryMetricsManager().addMetric(pMetric);
  290. return pMetric;
  291. }
  292. class jlib_decl ScopedGaugeUpdater
  293. {
  294. public:
  295. explicit ScopedGaugeUpdater(GaugeMetric &_pGauge, int64_t _amount=1)
  296. : gauge{_pGauge}, amount{_amount}
  297. {
  298. gauge.adjust(amount);
  299. }
  300. ScopedGaugeUpdater(const ScopedGaugeUpdater&) = delete;
  301. ScopedGaugeUpdater(ScopedGaugeUpdater&) = delete;
  302. ScopedGaugeUpdater& operator=(const ScopedGaugeUpdater&) = delete;
  303. ScopedGaugeUpdater& operator=(ScopedGaugeUpdater&) = delete;
  304. ~ScopedGaugeUpdater()
  305. {
  306. gauge.adjust(-amount);
  307. }
  308. protected:
  309. GaugeMetric &gauge;
  310. int64_t amount;
  311. };
  312. class jlib_decl ScopedGaugeDecrementer
  313. {
  314. public:
  315. explicit ScopedGaugeDecrementer(GaugeMetric &_pGauge, int64_t _amount=1)
  316. : gauge{_pGauge}, amount{_amount}
  317. { }
  318. ScopedGaugeDecrementer(const ScopedGaugeDecrementer&) = delete;
  319. ScopedGaugeDecrementer(ScopedGaugeDecrementer&&) = delete;
  320. ScopedGaugeDecrementer& operator=(const ScopedGaugeDecrementer&) = delete;
  321. ScopedGaugeDecrementer& operator=(ScopedGaugeDecrementer&&) = delete;
  322. ~ScopedGaugeDecrementer()
  323. {
  324. gauge.adjust(-amount);
  325. }
  326. protected:
  327. GaugeMetric &gauge;
  328. int64_t amount;
  329. };
  330. }