9
10
using namespace ml;
11
12
+static std::pair<std::string, std::string>
13
+getHostSpecificIdAndTitle(RRDHOST *RH, const std::string &IdPrefix,
14
+ const std::string &TitlePrefix) {
15
+ std::stringstream IdSS, TitleSS;
16
+
17
+ IdSS << IdPrefix << "_" << RH->machine_guid;
18
+ TitleSS << TitlePrefix << " " << RH->hostname;
19
+
20
+ return {IdSS.str(), TitleSS.str()};
21
+}
22
+
23
static void updateDimensionsChart(RRDHOST *RH,
24
collected_number NumTrainedDimensions,
25
collected_number NumNormalDimensions,
31
static thread_local RRDDIM *NumAnomalousDimensionsRD = nullptr;
32
33
if (!RS) {
23
- RS = rrdset_create(
24
- RH, // host
34
+ std::string IdPrefix = "dimensions";
35
+ std::string TitlePrefix = "Anomaly detection dimensions for host";
36
+ auto IdTitlePair = getHostSpecificIdAndTitle(RH, IdPrefix, TitlePrefix);
37
+
38
+ RS = rrdset_create_localhost(
39
"anomaly_detection", // type
26
- "dimensions", // id
40
+ IdTitlePair.first.c_str(), // id
41
NULL, // name
42
"dimensions", // family
29
- NULL, // ctx
30
- "Anomaly detection dimensions", // title
43
+ "anomaly_detection.dimensions", // ctx
44
+ IdTitlePair.second.c_str(), // title
45
"dimensions", // units
46
"netdata", // plugin
47
"ml", // module
74
static thread_local RRDDIM *AnomalyRateRD = nullptr;
75
76
if (!RS) {
63
- RS = rrdset_create(
64
- RH, // host
77
+ std::string IdPrefix = "anomaly_rate";
78
+ std::string TitlePrefix = "Percentage of anomalous dimensions for host";
79
+ auto IdTitlePair = getHostSpecificIdAndTitle(RH, IdPrefix, TitlePrefix);
80
+
81
+ RS = rrdset_create_localhost(
82
"anomaly_detection", // type
66
- "anomaly_rate", // id
83
+ IdTitlePair.first.c_str(), // id
84
NULL, // name
85
"anomaly_rate", // family
69
- NULL, // ctx
70
- "Percentage of anomalous dimensions", // title
86
+ "anomaly_detection.anomaly_rate", // ctx
87
+ IdTitlePair.second.c_str(), // title
88
"percentage", // units
89
"netdata", // plugin
90
"ml", // module
108
static thread_local RRDDIM *WindowLengthRD = nullptr;
109
110
if (!RS) {
94
- RS = rrdset_create(
95
- RH, // host
111
+ std::string IdPrefix = "detector_window";
112
+ std::string TitlePrefix = "Anomaly detector window length for host";
113
+ auto IdTitlePair = getHostSpecificIdAndTitle(RH, IdPrefix, TitlePrefix);
114
+
115
+ RS = rrdset_create_localhost(
116
"anomaly_detection", // type
97
- "detector_window", // id
117
+ IdTitlePair.first.c_str(), // id
118
NULL, // name
119
"detector_window", // family
100
- NULL, // ctx
101
- "Anomaly detector window length", // title
120
+ "anomaly_detection.detector_window", // ctx
121
+ IdTitlePair.second.c_str(), // title
122
"seconds", // units
123
"netdata", // plugin
124
"ml", // module
146
static thread_local RRDDIM *NewAnomalyEventRD = nullptr;
147
148
if (!RS) {
129
- RS = rrdset_create(
130
- RH, // host
149
+ std::string IdPrefix = "detector_events";
150
+ std::string TitlePrefix = "Anomaly events triggered for host";
151
+ auto IdTitlePair = getHostSpecificIdAndTitle(RH, IdPrefix, TitlePrefix);
152
+
153
+ RS = rrdset_create_localhost(
154
"anomaly_detection", // type
132
- "detector_events", // id
155
+ IdTitlePair.first.c_str(), // id
156
NULL, // name
157
"detector_events", // family
135
- NULL, // ctx
136
- "Anomaly events triggered", // title
158
+ "anomaly_detection.detector_events", // ctx
159
+ IdTitlePair.second.c_str(), // title
160
"boolean", // units
161
"netdata", // plugin
162
"ml", // module
189
static thread_local RRDDIM *PredictiobDurationRD = nullptr;
190
191
if (!RS) {
169
- RS = rrdset_create(
170
- RH, // host
192
+ std::string IdPrefix = "prediction_stats";
193
+ std::string TitlePrefix = "Time it took to run prediction for host";
194
+ auto IdTitlePair = getHostSpecificIdAndTitle(RH, IdPrefix, TitlePrefix);
195
+
196
+ RS = rrdset_create_localhost(
197
"anomaly_detection", // type
172
- "prediction_stats", // id
198
+ IdTitlePair.first.c_str(), // id
199
NULL, // name
200
"prediction_stats", // family
175
- NULL, // ctx
176
- "Time it took to run prediction", // title
201
+ "anomaly_detection.prediction_stats", // ctx
202
+ IdTitlePair.second.c_str(), // title
203
"milliseconds", // units
204
"netdata", // plugin
205
"ml", // module
227
static thread_local RRDDIM *MaxTrainingDurationRD = nullptr;
228
229
if (!RS) {
204
- RS = rrdset_create(
205
- RH, // host
230
+ std::string IdPrefix = "training_stats";
231
+ std::string TitlePrefix = "Training step statistics for host";
232
+ auto IdTitlePair = getHostSpecificIdAndTitle(RH, IdPrefix, TitlePrefix);
233
+
234
+ RS = rrdset_create_localhost(
235
"anomaly_detection", // type
207
- "training_stats", // id
236
+ IdTitlePair.first.c_str(), // id
237
NULL, // name
238
"training_stats", // family
210
- NULL, // ctx
211
- "Training step statistics", // title
239
+ "anomaly_detection.training_stats", // ctx
240
+ IdTitlePair.second.c_str(), // title
241
"milliseconds", // units
242
"netdata", // plugin
243
"ml", // module
260
}
261
262
void RrdHost::addDimension(Dimension *D) {
234
- std::lock_guard<std::mutex> Lock(Mutex);
263
+ RRDDIM *AnomalyRateRD = rrddim_add(AnomalyRateRS, D->getID().c_str(), NULL,
264
+ 1, 1000, RRD_ALGORITHM_ABSOLUTE);
265
+ D->setAnomalyRateRD(AnomalyRateRD);
266
+
267
+ {
268
+ std::lock_guard<std::mutex> Lock(Mutex);
269
236
- DimensionsMap[D->getRD()] = D;
270
+ DimensionsMap[D->getRD()] = D;
271
238
- // Default construct mutex for dimension
239
- LocksMap[D];
272
+ // Default construct mutex for dimension
273
+ LocksMap[D];
274
+ }
275
}
276
277
void RrdHost::removeDimension(Dimension *D) {
379
}
380
381
void DetectableHost::detectOnce() {
347
- auto P = BRW.insert(AnomalyRate >= Cfg.HostAnomalyRateThreshold);
382
+ auto P = BRW.insert(WindowAnomalyRate >= Cfg.HostAnomalyRateThreshold);
383
BitRateWindow::Edge Edge = P.first;
384
size_t WindowLength = P.second;
385
396
double TotalTrainingDuration = 0.0;
397
double MaxTrainingDuration = 0.0;
398
399
+ bool CollectAnomalyRates = (++AnomalyRateTimer == Cfg.DBEngineAnomalyRateEvery);
400
+ if (CollectAnomalyRates)
401
+ rrdset_next(AnomalyRateRS);
402
+
403
{
404
std::lock_guard<std::mutex> Lock(Mutex);
405
410
411
auto P = D->detect(WindowLength, ResetBitCounter);
412
bool IsAnomalous = P.first;
374
- double AnomalyRate = P.second;
413
+ double AnomalyScore = P.second;
414
415
NumTrainedDimensions += D->isTrained();
416
421
if (IsAnomalous)
422
NumAnomalousDimensions += 1;
423
385
- if (NewAnomalyEvent && (AnomalyRate >= Cfg.ADDimensionRateThreshold))
386
- DimsOverThreshold.push_back({ AnomalyRate, D->getID() });
424
+ if (NewAnomalyEvent && (AnomalyScore >= Cfg.ADDimensionRateThreshold))
425
+ DimsOverThreshold.push_back({ AnomalyScore, D->getID() });
426
+
427
+ D->updateAnomalyBitCounter(AnomalyRateRS, AnomalyRateTimer, IsAnomalous);
428
}
429
430
if (NumAnomalousDimensions)
390
- AnomalyRate = static_cast<double>(NumAnomalousDimensions) / DimensionsMap.size();
431
+ WindowAnomalyRate = static_cast<double>(NumAnomalousDimensions) / DimensionsMap.size();
432
else
392
- AnomalyRate = 0.0;
433
+ WindowAnomalyRate = 0.0;
434
435
NumNormalDimensions = DimensionsMap.size() - NumAnomalousDimensions;
436
}
437
438
+ if (CollectAnomalyRates) {
439
+ AnomalyRateTimer = 0;
440
+ rrdset_done(AnomalyRateRS);
441
+ }
442
+
443
this->NumAnomalousDimensions = NumAnomalousDimensions;
444
this->NumNormalDimensions = NumNormalDimensions;
445
this->NumTrainedDimensions = NumTrainedDimensions;
446
447
updateDimensionsChart(getRH(), NumTrainedDimensions, NumNormalDimensions, NumAnomalousDimensions);
402
- updateRateChart(getRH(), AnomalyRate * 10000.0);
448
+ updateRateChart(getRH(), WindowAnomalyRate * 10000.0);
449
updateWindowLengthChart(getRH(), WindowLength);
450
updateEventsChart(getRH(), P, ResetBitCounter, NewAnomalyEvent);
451
updateTrainingChart(getRH(), TotalTrainingDuration * 1000.0, MaxTrainingDuration * 1000.0);