131 {
132 std::cout << "=== Alert Triggers Example ===" << std::endl;
133 std::cout << std::endl;
134
135
136
137
138 std::cout << "1. Threshold Triggers" << std::endl;
139 std::cout << " -------------------" << std::endl;
140
141
146
147
148 auto equal_50 = std::make_shared<threshold_trigger>(
149 50.0, comparison_operator::equal, 0.5);
150 auto not_equal_100 = std::make_shared<threshold_trigger>(
151 100.0, comparison_operator::not_equal);
152
153 std::cout << " Testing threshold triggers with various values:" << std::endl;
154 std::cout << std::endl;
155
156 std::vector<double> test_values = {5.0, 10.0, 20.0, 50.0, 50.3, 80.0, 85.0, 90.0, 100.0};
157
158 for (double val : test_values) {
159 std::cout << " Value: " << val << std::endl;
160 print_eval_result(
"above(80)", val, above_80->evaluate(val), above_80->description());
166 std::cout << std::endl;
167 }
168
169
170
171
172 std::cout << "2. Range Triggers" << std::endl;
173 std::cout << " ---------------" << std::endl;
174
177
178 std::cout << " Range triggers test [40, 60]:" << std::endl;
179 std::cout << std::endl;
180
181 std::vector<double> range_values = {30.0, 40.0, 50.0, 60.0, 70.0};
182 for (double val : range_values) {
184 in_range_40_60->description());
186 out_of_range_40_60->description());
187 std::cout << std::endl;
188 }
189
190
191
192
193 std::cout << "3. Rate of Change Trigger" << std::endl;
194 std::cout << " -----------------------" << std::endl;
195
196
197 auto rate_increasing = std::make_shared<rate_of_change_trigger>(
198 10.0,
199 500ms,
200 rate_of_change_trigger::rate_direction::increasing,
201 3
202 );
203
204
205 auto rate_decreasing = std::make_shared<rate_of_change_trigger>(
206 5.0,
207 500ms,
208 rate_of_change_trigger::rate_direction::decreasing,
209 3
210 );
211
212
213 auto rate_either = std::make_shared<rate_of_change_trigger>(
214 8.0,
215 500ms,
216 rate_of_change_trigger::rate_direction::either,
217 3
218 );
219
220 std::cout << " Simulating rapidly increasing values:" << std::endl;
221
222
223 std::vector<double> increasing_values = {10.0, 15.0, 25.0, 40.0, 60.0, 85.0};
224 for (size_t i = 0; i < increasing_values.size(); ++i) {
225 double val = increasing_values[i];
226 bool triggered = rate_increasing->evaluate(val);
227 std::cout << " Sample " << (i + 1) << ": value=" << val
228 << " | Rate trigger: " << (triggered ? "YES" : "NO") << std::endl;
229 std::this_thread::sleep_for(100ms);
230 }
231 std::cout << std::endl;
232
233
234 rate_decreasing->reset();
235 std::cout << " Simulating rapidly decreasing values:" << std::endl;
236
237 std::vector<double> decreasing_values = {100.0, 95.0, 85.0, 70.0, 50.0, 25.0};
238 for (size_t i = 0; i < decreasing_values.size(); ++i) {
239 double val = decreasing_values[i];
240 bool triggered = rate_decreasing->evaluate(val);
241 std::cout << " Sample " << (i + 1) << ": value=" << val
242 << " | Rate trigger: " << (triggered ? "YES" : "NO") << std::endl;
243 std::this_thread::sleep_for(100ms);
244 }
245 std::cout << std::endl;
246
247
248
249
250 std::cout << "4. Anomaly Trigger (Statistical)" << std::endl;
251 std::cout << " ------------------------------" << std::endl;
252
253
254 auto anomaly_trigger_ptr = std::make_shared<anomaly_trigger>(
255 2.0,
256 20,
257 5
258 );
259
260 std::cout << " Building baseline with normal values (around 50):" << std::endl;
261
262
263 std::random_device rd;
264 std::mt19937 gen(rd());
265 std::normal_distribution<> normal_dist(50.0, 5.0);
266
267
268 for (int i = 0; i < 15; ++i) {
269 double val = normal_dist(gen);
270 bool triggered = anomaly_trigger_ptr->evaluate(val);
271 std::cout << " Sample " << (i + 1) << ": value=" << std::fixed
272 << std::setprecision(1) << val
273 << " | Anomaly: " << (triggered ? "YES" : "NO") << std::endl;
274 }
275
276 std::cout << std::endl;
277 std::cout << " Current baseline - Mean: " << std::fixed << std::setprecision(2)
278 << anomaly_trigger_ptr->current_mean()
279 << ", StdDev: " << anomaly_trigger_ptr->current_stddev() << std::endl;
280 std::cout << std::endl;
281
282
283 std::cout << " Introducing anomalous values:" << std::endl;
284 std::vector<double> anomalous_values = {80.0, 20.0, 100.0, 52.0};
285 for (double val : anomalous_values) {
286 bool triggered = anomaly_trigger_ptr->evaluate(val);
287 std::cout << " Value: " << val << " | Anomaly: " << (triggered ? "YES" : "NO")
288 << " (>" << (anomaly_trigger_ptr->current_stddev() * 2)
289 << " from mean " << anomaly_trigger_ptr->current_mean() << ")" << std::endl;
290 }
291 std::cout << std::endl;
292
293
294
295
296 std::cout << "5. Composite Triggers (AND/OR/NOT)" << std::endl;
297 std::cout << " --------------------------------" << std::endl;
298
299
303
304
306
307
309
310
312
313
314 auto xor_trigger = std::make_shared<composite_trigger>(
315 composite_operation::XOR,
316 std::vector<std::shared_ptr<alert_trigger>>{cpu_high, memory_high}
317 );
318
319 std::cout << " Composite trigger descriptions:" << std::endl;
320 std::cout << " - ALL (AND): " << all_high->description() << std::endl;
321 std::cout << " - ANY (OR): " << any_high->description() << std::endl;
322 std::cout << " - NOT: " << cpu_not_high->description() << std::endl;
323 std::cout << " - XOR: " << xor_trigger->description() << std::endl;
324 std::cout << std::endl;
325
326
327 struct TestCase {
330 double disk;
331 };
332
333 std::vector<TestCase> composite_tests = {
334 {50.0, 50.0, 50.0},
335 {85.0, 50.0, 50.0},
336 {85.0, 95.0, 50.0},
337 {85.0, 95.0, 90.0},
338 };
339
340 std::cout << " Testing composite triggers:" << std::endl;
341 for (const auto& tc : composite_tests) {
342 std::cout << " CPU=" << tc.cpu << ", Memory=" << tc.memory
343 << ", Disk=" << tc.disk << std::endl;
344
345
346 std::vector<double> values = {tc.cpu, tc.memory, tc.disk};
347
348
349 bool all_result = all_high->evaluate_multi(values);
350 bool any_result = any_high->evaluate_multi(values);
351 bool not_result = cpu_not_high->evaluate(tc.cpu);
352 bool xor_result = xor_trigger->evaluate_multi({tc.cpu, tc.memory});
353
354 std::cout << " ALL: " << (all_result ? "YES" : "NO")
355 << " | ANY: " << (any_result ? "YES" : "NO")
356 << " | NOT(cpu>80): " << (not_result ? "YES" : "NO")
357 << " | XOR(cpu,mem): " << (xor_result ? "YES" : "NO") << std::endl;
358 }
359 std::cout << std::endl;
360
361
362
363
364 std::cout << "6. Delta Trigger (Change Detection)" << std::endl;
365 std::cout << " ----------------------------------" << std::endl;
366
367
368 auto delta_absolute = std::make_shared<delta_trigger>(10.0, true);
369
370
371 auto delta_positive = std::make_shared<delta_trigger>(5.0, false);
372
373 std::cout << " Testing delta triggers with sequential values:" << std::endl;
374 std::vector<double> delta_values = {50.0, 52.0, 55.0, 70.0, 68.0, 55.0};
375
376 for (size_t i = 0; i < delta_values.size(); ++i) {
377 double val = delta_values[i];
378 bool abs_triggered = delta_absolute->evaluate(val);
379 bool pos_triggered = delta_positive->evaluate(val);
380
381 std::cout << " Value: " << val;
382 if (i > 0) {
383 std::cout << " (delta=" << (val - delta_values[i-1]) << ")";
384 }
385 std::cout << " | Absolute(>10): " << (abs_triggered ? "YES" : "NO")
386 << " | Positive(>5): " << (pos_triggered ? "YES" : "NO") << std::endl;
387 }
388 std::cout << std::endl;
389
390
391
392
393 std::cout << "7. Absent Trigger (Missing Data)" << std::endl;
394 std::cout << " ------------------------------" << std::endl;
395
396
397 auto absent_trigger_ptr = std::make_shared<absent_trigger>(200ms);
398
399 std::cout << " " << absent_trigger_ptr->description() << std::endl;
400 std::cout << " Simulating data with gaps:" << std::endl;
401
402
403 for (int i = 0; i < 3; ++i) {
404 bool triggered = absent_trigger_ptr->evaluate(100.0);
405 std::cout << " Evaluation " << (i + 1) << " (immediate): "
406 << (triggered ? "ABSENT" : "present") << std::endl;
407 std::this_thread::sleep_for(50ms);
408 }
409
410
411 std::cout << " ... waiting 300ms (simulating data gap) ..." << std::endl;
412 std::this_thread::sleep_for(300ms);
413
414 bool after_gap = absent_trigger_ptr->evaluate(100.0);
415 std::cout << " Evaluation after gap: " << (after_gap ? "ABSENT" : "present") << std::endl;
416 std::cout << std::endl;
417
418
419
420
421 std::cout << "8. Custom Trigger Implementations" << std::endl;
422 std::cout << " -------------------------------" << std::endl;
423
424
425 auto periodic = std::make_shared<periodic_trigger>(3);
426 std::cout << " Periodic trigger: " << periodic->description() << std::endl;
427
428 for (int i = 1; i <= 9; ++i) {
429 bool triggered = periodic->evaluate(0);
430 std::cout << " Evaluation " << i << ": " << (triggered ? "FIRE" : "-") << std::endl;
431 }
432 std::cout << std::endl;
433
434
435 auto ma_trigger = std::make_shared<moving_average_trigger>(5, 60.0);
436 std::cout << " Moving average trigger: " << ma_trigger->description() << std::endl;
437
438 std::vector<double> ma_values = {50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0};
439 for (size_t i = 0; i < ma_values.size(); ++i) {
440 double val = ma_values[i];
441 bool triggered = ma_trigger->evaluate(val);
442 std::cout << " Value: " << val << " | MA(5)=" << std::fixed << std::setprecision(1)
443 << ma_trigger->current_average()
444 << " | Triggered: " << (triggered ? "YES" : "NO") << std::endl;
445 }
446 std::cout << std::endl;
447
448
449
450
451 std::cout << "9. Using Triggers with Alert Rules" << std::endl;
452 std::cout << " ---------------------------------" << std::endl;
453
454
455 alert_rule complex_rule(
"complex_system_alert");
456 complex_rule.set_metric_name("system_health")
457 .set_severity(alert_severity::critical)
458 .set_summary("System health degraded")
459 .set_description("Multiple system metrics exceeded thresholds")
460 .add_label("team", "ops")
461 .add_label("priority", "p1");
462
463
467 });
468
470
472 cpu_mem_trigger,
473 disk_critical
474 });
475
476 complex_rule.set_trigger(complex_composite);
477
478
479 if (auto result = complex_rule.validate(); result.is_ok()) {
480 std::cout << " Rule '" << complex_rule.name() << "' validated successfully" << std::endl;
481 std::cout << " Trigger type: " << complex_rule.trigger()->type_name() << std::endl;
482 std::cout << " Description: " << complex_rule.trigger()->description() << std::endl;
483 }
484 std::cout << std::endl;
485
486
487
488
489 std::cout << "=== Alert Triggers Example Completed ===" << std::endl;
490 std::cout << std::endl;
491 std::cout << "Triggers demonstrated:" << std::endl;
492 std::cout << " - ThresholdTrigger (>, >=, <, <=, ==, !=)" << std::endl;
493 std::cout << " - RangeTrigger (in_range, out_of_range)" << std::endl;
494 std::cout << " - RateOfChangeTrigger (increasing, decreasing, either)" << std::endl;
495 std::cout << " - AnomalyTrigger (statistical deviation)" << std::endl;
496 std::cout << " - CompositeTrigger (AND, OR, XOR, NOT)" << std::endl;
497 std::cout << " - DeltaTrigger (change detection)" << std::endl;
498 std::cout << " - AbsentTrigger (missing data)" << std::endl;
499 std::cout << " - Custom triggers (periodic, moving average)" << std::endl;
500
501 return 0;
502}
void print_eval_result(const std::string &trigger_name, double value, bool triggered, const std::string &description="")
Defines conditions and behavior for alert triggering.
static std::shared_ptr< composite_trigger > all_of(std::vector< std::shared_ptr< alert_trigger > > triggers)
Create AND composite.
static std::shared_ptr< composite_trigger > any_of(std::vector< std::shared_ptr< alert_trigger > > triggers)
Create OR composite.
static std::shared_ptr< composite_trigger > invert(std::shared_ptr< alert_trigger > trigger)
Create NOT composite.
static std::shared_ptr< threshold_trigger > below_or_equal(double threshold)
Create trigger for value <= threshold.
static std::shared_ptr< threshold_trigger > below(double threshold)
Create trigger for value < threshold.
static std::shared_ptr< class range_trigger > in_range(double min_val, double max_val)
Create trigger for value within range (inclusive)
static std::shared_ptr< threshold_trigger > above_or_equal(double threshold)
Create trigger for value >= threshold.
static std::shared_ptr< class range_trigger > out_of_range(double min_val, double max_val)
Create trigger for value outside range (exclusive)
static std::shared_ptr< threshold_trigger > above(double threshold)
Create trigger for value > threshold.
@ memory
Memory/DRAM power domain (RAPL)
@ cpu
CPU power domain (RAPL)