ml.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "Config.h"
  3. #include "Dimension.h"
  4. #include "Host.h"
  5. #include <random>
  6. using namespace ml;
  7. bool ml_capable() {
  8. return true;
  9. }
  10. bool ml_enabled(RRDHOST *RH) {
  11. if (!Cfg.EnableAnomalyDetection)
  12. return false;
  13. if (simple_pattern_matches(Cfg.SP_HostsToSkip, RH->hostname))
  14. return false;
  15. return true;
  16. }
  17. /*
  18. * Assumptions:
  19. * 1) hosts outlive their sets, and sets outlive their dimensions,
  20. * 2) dimensions always have a set that has a host.
  21. */
  22. void ml_init(void) {
  23. // Read config values
  24. Cfg.readMLConfig();
  25. if (!Cfg.EnableAnomalyDetection)
  26. return;
  27. // Generate random numbers to efficiently sample the features we need
  28. // for KMeans clustering.
  29. std::random_device RD;
  30. std::mt19937 Gen(RD());
  31. Cfg.RandomNums.reserve(Cfg.MaxTrainSamples);
  32. for (size_t Idx = 0; Idx != Cfg.MaxTrainSamples; Idx++)
  33. Cfg.RandomNums.push_back(Gen());
  34. }
  35. void ml_new_host(RRDHOST *RH) {
  36. if (!ml_enabled(RH))
  37. return;
  38. Host *H = new Host(RH);
  39. RH->ml_host = static_cast<ml_host_t>(H);
  40. H->startAnomalyDetectionThreads();
  41. }
  42. void ml_delete_host(RRDHOST *RH) {
  43. Host *H = static_cast<Host *>(RH->ml_host);
  44. if (!H)
  45. return;
  46. H->stopAnomalyDetectionThreads();
  47. delete H;
  48. RH->ml_host = nullptr;
  49. }
  50. void ml_new_dimension(RRDDIM *RD) {
  51. RRDSET *RS = RD->rrdset;
  52. Host *H = static_cast<Host *>(RD->rrdset->rrdhost->ml_host);
  53. if (!H)
  54. return;
  55. if (static_cast<unsigned>(RD->update_every) != H->updateEvery())
  56. return;
  57. if (simple_pattern_matches(Cfg.SP_ChartsToSkip, RS->name))
  58. return;
  59. Dimension *D = new Dimension(RD);
  60. RD->state->ml_dimension = static_cast<ml_dimension_t>(D);
  61. H->addDimension(D);
  62. }
  63. void ml_delete_dimension(RRDDIM *RD) {
  64. Dimension *D = static_cast<Dimension *>(RD->state->ml_dimension);
  65. if (!D)
  66. return;
  67. Host *H = static_cast<Host *>(RD->rrdset->rrdhost->ml_host);
  68. if (!H)
  69. delete D;
  70. else
  71. H->removeDimension(D);
  72. RD->state->ml_dimension = nullptr;
  73. }
  74. char *ml_get_host_info(RRDHOST *RH) {
  75. nlohmann::json ConfigJson;
  76. if (RH && RH->ml_host) {
  77. Host *H = static_cast<Host *>(RH->ml_host);
  78. H->getConfigAsJson(ConfigJson);
  79. } else {
  80. ConfigJson["enabled"] = false;
  81. }
  82. return strdup(ConfigJson.dump(2, '\t').c_str());
  83. }
  84. char *ml_get_host_runtime_info(RRDHOST *RH) {
  85. nlohmann::json ConfigJson;
  86. if (RH && RH->ml_host) {
  87. Host *H = static_cast<Host *>(RH->ml_host);
  88. H->getDetectionInfoAsJson(ConfigJson);
  89. } else {
  90. return nullptr;
  91. }
  92. return strdup(ConfigJson.dump(1, '\t').c_str());
  93. }
  94. bool ml_is_anomalous(RRDDIM *RD, double Value, bool Exists) {
  95. Dimension *D = static_cast<Dimension *>(RD->state->ml_dimension);
  96. if (!D)
  97. return false;
  98. D->addValue(Value, Exists);
  99. bool Result = D->predict().second;
  100. return Result;
  101. }
  102. char *ml_get_anomaly_events(RRDHOST *RH, const char *AnomalyDetectorName,
  103. int AnomalyDetectorVersion, time_t After, time_t Before) {
  104. if (!RH || !RH->ml_host) {
  105. error("No host");
  106. return nullptr;
  107. }
  108. Host *H = static_cast<Host *>(RH->ml_host);
  109. std::vector<std::pair<time_t, time_t>> TimeRanges;
  110. bool Res = H->getAnomaliesInRange(TimeRanges, AnomalyDetectorName,
  111. AnomalyDetectorVersion,
  112. H->getUUID(),
  113. After, Before);
  114. if (!Res) {
  115. error("DB result is empty");
  116. return nullptr;
  117. }
  118. nlohmann::json Json = TimeRanges;
  119. return strdup(Json.dump(4).c_str());
  120. }
  121. char *ml_get_anomaly_event_info(RRDHOST *RH, const char *AnomalyDetectorName,
  122. int AnomalyDetectorVersion, time_t After, time_t Before) {
  123. if (!RH || !RH->ml_host) {
  124. error("No host");
  125. return nullptr;
  126. }
  127. Host *H = static_cast<Host *>(RH->ml_host);
  128. nlohmann::json Json;
  129. bool Res = H->getAnomalyInfo(Json, AnomalyDetectorName,
  130. AnomalyDetectorVersion,
  131. H->getUUID(),
  132. After, Before);
  133. if (!Res) {
  134. error("DB result is empty");
  135. return nullptr;
  136. }
  137. return strdup(Json.dump(4, '\t').c_str());
  138. }
  139. void ml_process_rrdr(RRDR *R, int MaxAnomalyRates) {
  140. if (R->rows != 1)
  141. return;
  142. if (MaxAnomalyRates < 1 || MaxAnomalyRates >= R->d)
  143. return;
  144. calculated_number *CNs = R->v;
  145. RRDR_DIMENSION_FLAGS *DimFlags = R->od;
  146. std::vector<std::pair<calculated_number, int>> V;
  147. V.reserve(R->d);
  148. for (int Idx = 0; Idx != R->d; Idx++)
  149. V.emplace_back(CNs[Idx], Idx);
  150. std::sort(V.rbegin(), V.rend());
  151. for (int Idx = MaxAnomalyRates; Idx != R->d; Idx++) {
  152. int UnsortedIdx = V[Idx].second;
  153. int OldFlags = static_cast<int>(DimFlags[UnsortedIdx]);
  154. int NewFlags = OldFlags | RRDR_DIMENSION_HIDDEN;
  155. DimFlags[UnsortedIdx] = static_cast<rrdr_dimension_flag>(NewFlags);
  156. }
  157. }
  158. void ml_dimension_update_name(RRDSET *RS, RRDDIM *RD, const char *Name) {
  159. (void) RS;
  160. Dimension *D = static_cast<Dimension *>(RD->state->ml_dimension);
  161. if (!D)
  162. return;
  163. D->setAnomalyRateRDName(Name);
  164. }
  165. bool ml_streaming_enabled() {
  166. return Cfg.StreamADCharts;
  167. }
  168. #if defined(ENABLE_ML_TESTS)
  169. #include "gtest/gtest.h"
  170. int test_ml(int argc, char *argv[]) {
  171. (void) argc;
  172. (void) argv;
  173. ::testing::InitGoogleTest(&argc, argv);
  174. return RUN_ALL_TESTS();
  175. }
  176. #endif // ENABLE_ML_TESTS
  177. #include "ml-private.h"