ml.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. H->removeDimension(D);
  69. RD->state->ml_dimension = nullptr;
  70. }
  71. char *ml_get_host_info(RRDHOST *RH) {
  72. nlohmann::json ConfigJson;
  73. if (RH && RH->ml_host) {
  74. Host *H = static_cast<Host *>(RH->ml_host);
  75. H->getConfigAsJson(ConfigJson);
  76. } else {
  77. ConfigJson["enabled"] = false;
  78. }
  79. return strdup(ConfigJson.dump(2, '\t').c_str());
  80. }
  81. char *ml_get_host_runtime_info(RRDHOST *RH) {
  82. nlohmann::json ConfigJson;
  83. if (RH && RH->ml_host) {
  84. Host *H = static_cast<Host *>(RH->ml_host);
  85. H->getDetectionInfoAsJson(ConfigJson);
  86. } else {
  87. return nullptr;
  88. }
  89. return strdup(ConfigJson.dump(1, '\t').c_str());
  90. }
  91. bool ml_is_anomalous(RRDDIM *RD, double Value, bool Exists) {
  92. Dimension *D = static_cast<Dimension *>(RD->state->ml_dimension);
  93. if (!D)
  94. return false;
  95. D->addValue(Value, Exists);
  96. bool Result = D->predict().second;
  97. return Result;
  98. }
  99. char *ml_get_anomaly_events(RRDHOST *RH, const char *AnomalyDetectorName,
  100. int AnomalyDetectorVersion, time_t After, time_t Before) {
  101. if (!RH || !RH->ml_host) {
  102. error("No host");
  103. return nullptr;
  104. }
  105. Host *H = static_cast<Host *>(RH->ml_host);
  106. std::vector<std::pair<time_t, time_t>> TimeRanges;
  107. bool Res = H->getAnomaliesInRange(TimeRanges, AnomalyDetectorName,
  108. AnomalyDetectorVersion,
  109. H->getUUID(),
  110. After, Before);
  111. if (!Res) {
  112. error("DB result is empty");
  113. return nullptr;
  114. }
  115. nlohmann::json Json = TimeRanges;
  116. return strdup(Json.dump(4).c_str());
  117. }
  118. char *ml_get_anomaly_event_info(RRDHOST *RH, const char *AnomalyDetectorName,
  119. int AnomalyDetectorVersion, time_t After, time_t Before) {
  120. if (!RH || !RH->ml_host) {
  121. error("No host");
  122. return nullptr;
  123. }
  124. Host *H = static_cast<Host *>(RH->ml_host);
  125. nlohmann::json Json;
  126. bool Res = H->getAnomalyInfo(Json, AnomalyDetectorName,
  127. AnomalyDetectorVersion,
  128. H->getUUID(),
  129. After, Before);
  130. if (!Res) {
  131. error("DB result is empty");
  132. return nullptr;
  133. }
  134. return strdup(Json.dump(4, '\t').c_str());
  135. }
  136. void ml_process_rrdr(RRDR *R, int MaxAnomalyRates) {
  137. if (R->rows != 1)
  138. return;
  139. if (MaxAnomalyRates < 1 || MaxAnomalyRates >= R->d)
  140. return;
  141. calculated_number *CNs = R->v;
  142. RRDR_DIMENSION_FLAGS *DimFlags = R->od;
  143. std::vector<std::pair<calculated_number, int>> V;
  144. V.reserve(R->d);
  145. for (int Idx = 0; Idx != R->d; Idx++)
  146. V.emplace_back(CNs[Idx], Idx);
  147. std::sort(V.rbegin(), V.rend());
  148. for (int Idx = MaxAnomalyRates; Idx != R->d; Idx++) {
  149. int UnsortedIdx = V[Idx].second;
  150. int OldFlags = static_cast<int>(DimFlags[UnsortedIdx]);
  151. int NewFlags = OldFlags | RRDR_DIMENSION_HIDDEN;
  152. DimFlags[UnsortedIdx] = static_cast<rrdr_dimension_flag>(NewFlags);
  153. }
  154. }
  155. void ml_dimension_update_name(RRDSET *RS, RRDDIM *RD, const char *Name) {
  156. (void) RS;
  157. Dimension *D = static_cast<Dimension *>(RD->state->ml_dimension);
  158. if (!D)
  159. return;
  160. D->setAnomalyRateRDName(Name);
  161. }
  162. #if defined(ENABLE_ML_TESTS)
  163. #include "gtest/gtest.h"
  164. int test_ml(int argc, char *argv[]) {
  165. (void) argc;
  166. (void) argv;
  167. ::testing::InitGoogleTest(&argc, argv);
  168. return RUN_ALL_TESTS();
  169. }
  170. #endif // ENABLE_ML_TESTS
  171. #include "ml-private.h"