171 {
172 std::cout << "=== Alert Notifiers Example ===" << std::endl;
173 std::cout << std::endl;
174
175
176 const std::string temp_dir = "/tmp/alert_notifiers_example";
177 std::filesystem::create_directories(temp_dir);
178
179
180
181
182 std::cout << "1. Alert Formatters" << std::endl;
183 std::cout << " -----------------" << std::endl;
184
185
187 "high_cpu_usage",
188 alert_severity::critical,
189 alert_state::firing,
190 95.5
191 );
192
193
195 std::cout << " JSON format:" << std::endl;
196 std::cout <<
" " << json_fmt.
format(sample) << std::endl;
197 std::cout << std::endl;
198
199
201 std::cout << " Text format:" << std::endl;
202 std::cout <<
" " << text_fmt.
format(sample) << std::endl;
203 std::cout << std::endl;
204
205
206
207
208 std::cout << "2. Log Notifier" << std::endl;
209 std::cout << " -------------" << std::endl;
210
211 auto log_notifier_ptr = std::make_shared<log_notifier>("system_logger");
212
213 std::cout << " Notifier name: " << log_notifier_ptr->name() << std::endl;
214 std::cout << " Ready: " << (log_notifier_ptr->is_ready() ? "yes" : "no") << std::endl;
215
216
217 std::cout << " Sending alert to log notifier..." << std::endl;
218 if (auto result = log_notifier_ptr->notify(sample); result.is_ok()) {
219 std::cout << " Alert logged successfully" << std::endl;
220 } else {
221 std::cout << " Failed to log alert: " << result.error().message << std::endl;
222 }
223 std::cout << std::endl;
224
225
226
227
228 std::cout << "3. File Notifier" << std::endl;
229 std::cout << " --------------" << std::endl;
230
231 std::string alert_log_path = temp_dir + "/alerts.log";
232 auto file_notifier_ptr = std::make_shared<file_notifier>(
233 alert_log_path,
234 std::make_shared<text_alert_formatter>()
235 );
236
237 std::cout << " Notifier name: " << file_notifier_ptr->name() << std::endl;
238 std::cout << " Output file: " << alert_log_path << std::endl;
239
240
241 std::vector<alert> alerts_to_log = {
245 };
246
247 for (const auto& a : alerts_to_log) {
248 if (auto result = file_notifier_ptr->notify(a); !result.is_ok()) {
249 std::cout << " Failed to write alert: " << result.error().message << std::endl;
250 }
251 }
252
253 std::cout << " Wrote " << alerts_to_log.size() << " alerts to file" << std::endl;
254
255
256 std::cout << " File contents:" << std::endl;
257 std::ifstream file(alert_log_path);
258 std::string line;
259 while (std::getline(file, line)) {
260 std::cout << " " << line << std::endl;
261 }
262 std::cout << std::endl;
263
264
265
266
267 std::cout << "4. Webhook Notifier Configuration" << std::endl;
268 std::cout << " -------------------------------" << std::endl;
269
271 webhook_cfg.
url =
"https://hooks.example.com/alerts";
272 webhook_cfg.
method =
"POST";
278 webhook_cfg.
add_header(
"Authorization",
"Bearer token-xxx")
279 .
add_header(
"X-Alert-Source",
"monitoring-system");
280
281 std::cout <<
" URL: " << webhook_cfg.
url << std::endl;
282 std::cout <<
" Method: " << webhook_cfg.
method << std::endl;
283 std::cout <<
" Timeout: " << webhook_cfg.
timeout.count() <<
"ms" << std::endl;
284 std::cout <<
" Max retries: " << webhook_cfg.
max_retries << std::endl;
285 std::cout << " Headers:" << std::endl;
286 for (
const auto& [key, value] : webhook_cfg.
headers) {
287 std::cout << " " << key << ": " << value << std::endl;
288 }
289 std::cout << std::endl;
290
291
292 auto webhook_notifier_ptr = std::make_shared<webhook_notifier>(
293 webhook_cfg,
294 std::make_shared<json_alert_formatter>()
295 );
296
297 std::cout << " Notifier name: " << webhook_notifier_ptr->name() << std::endl;
298 std::cout << " Ready: " << (webhook_notifier_ptr->is_ready() ? "yes" : "no")
299 << " (no HTTP sender configured)" << std::endl;
300
301
302 int http_call_count = 0;
303 webhook_notifier_ptr->set_http_sender(
304 [&http_call_count](const std::string& url,
305 const std::string& method,
306 const std::unordered_map<std::string, std::string>& headers,
307 const std::string& body) -> kcenon::common::VoidResult {
308 http_call_count++;
309 std::cout << " [MOCK HTTP] " << method << " " << url << std::endl;
310 std::cout << " [MOCK HTTP] Headers: " << headers.size() << std::endl;
311 std::cout << " [MOCK HTTP] Body length: " << body.length() << " chars" << std::endl;
312 return kcenon::common::ok();
313 }
314 );
315
316 std::cout << " Ready after setting HTTP sender: "
317 << (webhook_notifier_ptr->is_ready() ? "yes" : "no") << std::endl;
318
319
320 std::cout << " Testing webhook notification:" << std::endl;
321 if (auto result = webhook_notifier_ptr->notify(sample); result.is_ok()) {
322 std::cout << " Webhook notification sent (HTTP calls: " << http_call_count << ")" << std::endl;
323 }
324 std::cout << std::endl;
325
326
327
328
329 std::cout << "5. Callback Notifier" << std::endl;
330 std::cout << " ------------------" << std::endl;
331
332 size_t callback_count = 0;
333 auto callback_notifier_ptr = std::make_shared<callback_notifier>(
334 "custom_callback",
335 [&callback_count](
const alert& a) {
336 callback_count++;
337 std::cout <<
" [CALLBACK] Received: " << a.
name
339 << std::endl;
340 },
342 callback_count += group.size();
343 std::cout << " [CALLBACK GROUP] Received group: " << group.group_key
344 << " (" << group.size() << " alerts)" << std::endl;
345 }
346 );
347
348 std::cout << " Testing callback notifier:" << std::endl;
349 callback_notifier_ptr->notify(sample);
350 std::cout << " Callbacks executed: " << callback_count << std::endl;
351 std::cout << std::endl;
352
353
354
355
356 std::cout << "6. Multi Notifier (Multiple Targets)" << std::endl;
357 std::cout << " -----------------------------------" << std::endl;
358
359 auto multi = std::make_shared<multi_notifier>("multi_channel");
360
361
362 auto log_child = std::make_shared<log_notifier>("log_child");
363 auto stats_child = std::make_shared<statistics_notifier>("stats_child");
364 auto console_child = std::make_shared<console_color_notifier>("console_child");
365
366 multi->add_notifier(log_child);
367 multi->add_notifier(stats_child);
368 multi->add_notifier(console_child);
369
370 std::cout << " Added 3 child notifiers to multi_channel" << std::endl;
371 std::cout << " Sending alert to all channels:" << std::endl;
372
373 if (auto result = multi->notify(sample); result.is_ok()) {
374 std::cout << " All notifiers succeeded" << std::endl;
375 } else {
376 std::cout << " Some notifiers failed: " << result.error().message << std::endl;
377 }
378 std::cout << std::endl;
379
380
381
382
383 std::cout << "7. Buffered Notifier (Batching)" << std::endl;
384 std::cout << " -----------------------------" << std::endl;
385
386 auto inner_notifier = std::make_shared<statistics_notifier>("buffered_inner");
387 auto buffered = std::make_shared<buffered_notifier>(
388 inner_notifier,
389 5,
390 10000ms
391 );
392
393 std::cout << " Buffer size: 5, flush interval: 10s" << std::endl;
394 std::cout << " Sending alerts (will buffer until size reached):" << std::endl;
395
396 for (int i = 1; i <= 7; ++i) {
398 "buffered_alert_" + std::to_string(i),
399 alert_severity::warning,
400 alert_state::firing,
401 static_cast<double>(i * 10)
402 );
403 buffered->notify(a);
404 std::cout << " Sent alert " << i << ", pending: " << buffered->pending_count() << std::endl;
405 }
406
407
408 std::cout << " Forcing flush of remaining alerts..." << std::endl;
409 buffered->flush();
410 std::cout << " Pending after flush: " << buffered->pending_count() << std::endl;
411
412 inner_notifier->print_statistics();
413 std::cout << std::endl;
414
415
416
417
418 std::cout << "8. Routing Notifier (Conditional Routing)" << std::endl;
419 std::cout << " ---------------------------------------" << std::endl;
420
421 auto router = std::make_shared<routing_notifier>("alert_router");
422
423
424 auto critical_notifier = std::make_shared<console_color_notifier>("critical_channel");
425 auto warning_notifier = std::make_shared<console_color_notifier>("warning_channel");
426 auto default_notifier = std::make_shared<console_color_notifier>("default_channel");
427
428
429 router->route_by_severity(alert_severity::critical, critical_notifier);
430 router->route_by_severity(alert_severity::emergency, critical_notifier);
431 router->route_by_severity(alert_severity::warning, warning_notifier);
432 router->set_default_route(default_notifier);
433
434 std::cout << " Routing rules configured:" << std::endl;
435 std::cout << " - critical/emergency -> critical_channel" << std::endl;
436 std::cout << " - warning -> warning_channel" << std::endl;
437 std::cout << " - default -> default_channel" << std::endl;
438 std::cout << std::endl;
439
440 std::cout << " Testing routing with different severities:" << std::endl;
441
442 std::vector<alert> routing_tests = {
443 create_sample_alert(
"critical_alert", alert_severity::critical, alert_state::firing, 99.0),
446 };
447
448 for (const auto& a : routing_tests) {
449 std::cout <<
" Routing '" << a.
name <<
"' (severity: "
451 router->notify(a);
452 }
453 std::cout << std::endl;
454
455
456 std::cout << " Adding label-based routing:" << std::endl;
457 auto ops_notifier = std::make_shared<console_color_notifier>("ops_team_channel");
458 router->route_by_label("team", "ops", ops_notifier);
459
460 auto ops_alert =
create_sample_alert(
"ops_alert", alert_severity::info, alert_state::firing, 60.0,
"ops");
461 std::cout << " Routing alert with team=ops:" << std::endl;
462 router->notify(ops_alert);
463 std::cout << std::endl;
464
465
466
467
468 std::cout << "9. Custom Notifier Implementation" << std::endl;
469 std::cout << " -------------------------------" << std::endl;
470
471
472 auto stats = std::make_shared<statistics_notifier>("alert_statistics");
473
474
475 std::vector<alert> stat_alerts = {
481 };
482
483 for (const auto& a : stat_alerts) {
484 stats->notify(a);
485 }
486
487 stats->print_statistics();
488 std::cout << std::endl;
489
490
491
492
493 std::cout << "10. Alert Group Notification" << std::endl;
494 std::cout << " -------------------------" << std::endl;
495
496
498 group.common_labels.set("environment", "production");
499 group.common_labels.set("datacenter", "us-west-2");
500
501 group.add_alert(
create_sample_alert(
"cpu_server1", alert_severity::critical, alert_state::firing, 95.0));
502 group.add_alert(
create_sample_alert(
"cpu_server2", alert_severity::warning, alert_state::firing, 82.0));
503 group.add_alert(
create_sample_alert(
"cpu_server3", alert_severity::critical, alert_state::firing, 91.0));
504
505 std::cout << " Group: " << group.group_key << std::endl;
506 std::cout << " Alerts: " << group.size() << std::endl;
508 std::cout << std::endl;
509
510
511 std::cout << " JSON formatted group:" << std::endl;
512 std::cout <<
" " << json_fmt.
format_group(group) << std::endl;
513 std::cout << std::endl;
514
515
516 auto group_stats = std::make_shared<statistics_notifier>("group_stats");
517 group_stats->notify_group(group);
518 group_stats->print_statistics();
519 std::cout << std::endl;
520
521
522
523
524 std::cout << "11. Error Handling" << std::endl;
525 std::cout << " ---------------" << std::endl;
526
527
529 fail_cfg.
url =
"https://failing.example.com/alerts";
532
533 auto failing_webhook = std::make_shared<webhook_notifier>(fail_cfg);
534 int retry_count = 0;
535
536 failing_webhook->set_http_sender(
537 [&retry_count](const std::string& ,
538 const std::string& ,
539 const std::unordered_map<std::string, std::string>& ,
540 const std::string& ) -> kcenon::common::VoidResult {
541 retry_count++;
542 std::cout << " HTTP attempt " << retry_count << " - simulating failure" << std::endl;
543 return kcenon::common::VoidResult::err(500, "Simulated server error");
544 }
545 );
546
547 std::cout << " Testing webhook with simulated failures:" << std::endl;
548 auto fail_result = failing_webhook->notify(sample);
549 if (!fail_result.is_ok()) {
550 std::cout << " Expected failure after " << retry_count << " attempts: "
551 << fail_result.error().message << std::endl;
552 }
553 std::cout << std::endl;
554
555
556
557
558 std::cout << "12. Cleanup" << std::endl;
559 std::cout << " -------" << std::endl;
560
561
562 std::filesystem::remove_all(temp_dir);
563 std::cout << " Removed temporary directory: " << temp_dir << std::endl;
564 std::cout << std::endl;
565
566 std::cout << "=== Alert Notifiers Example Completed ===" << std::endl;
567 std::cout << std::endl;
568 std::cout << "Notifiers demonstrated:" << std::endl;
569 std::cout << " - LogNotifier (built-in logging)" << std::endl;
570 std::cout << " - FileNotifier (file-based alerts)" << std::endl;
571 std::cout << " - WebhookNotifier (HTTP webhooks)" << std::endl;
572 std::cout << " - CallbackNotifier (custom callbacks)" << std::endl;
573 std::cout << " - MultiNotifier (multiple targets)" << std::endl;
574 std::cout << " - BufferedNotifier (batching)" << std::endl;
575 std::cout << " - RoutingNotifier (conditional routing)" << std::endl;
576 std::cout << " - Custom implementations (color console, statistics)" << std::endl;
577 std::cout << " - Alert formatters (JSON, text)" << std::endl;
578
579 return 0;
580}
Formats alerts as human-readable text.
std::string format(const alert &a) const override
Format a single alert.
alert create_sample_alert(const std::string &name, alert_severity severity, alert_state state, double value, const std::string &team="ops")
constexpr const char * alert_severity_to_string(alert_severity severity) noexcept
Convert alert severity to string.
Group of related alerts for batch notification.
Core alert data structure.
alert_severity severity
Alert severity level.
std::string name
Alert name/identifier.
Configuration for webhook notifier.
std::chrono::milliseconds retry_delay
Delay between retries.
std::chrono::milliseconds timeout
Request timeout.
bool send_resolved
Send resolved notifications.
size_t max_retries
Maximum retry attempts.
std::string content_type
Content type header.
webhook_config & add_header(const std::string &key, const std::string &value)
Add a custom header.
std::unordered_map< std::string, std::string > headers
Custom headers.
std::string url
Webhook URL.
std::string method
HTTP method.