]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts
import ceph quincy 17.2.4
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / shared / services / prometheus-alert.service.ts
CommitLineData
11fdf7f2
TL
1import { Injectable } from '@angular/core';
2
f67539c2 3import _ from 'lodash';
11fdf7f2
TL
4
5import { PrometheusService } from '../api/prometheus.service';
9f95a23c
TL
6import {
7 AlertmanagerAlert,
8 PrometheusCustomAlert,
9 PrometheusRule
10} from '../models/prometheus-alerts';
11fdf7f2 11import { PrometheusAlertFormatter } from './prometheus-alert-formatter';
11fdf7f2
TL
12
13@Injectable({
81eedcae 14 providedIn: 'root'
11fdf7f2
TL
15})
16export class PrometheusAlertService {
17 private canAlertsBeNotified = false;
494da23a 18 alerts: AlertmanagerAlert[] = [];
9f95a23c 19 rules: PrometheusRule[] = [];
cd265ab1 20 activeAlerts: number;
2a845540
TL
21 activeCriticalAlerts: number;
22 activeWarningAlerts: number;
11fdf7f2
TL
23
24 constructor(
25 private alertFormatter: PrometheusAlertFormatter,
26 private prometheusService: PrometheusService
27 ) {}
28
9f95a23c 29 getAlerts() {
494da23a
TL
30 this.prometheusService.ifAlertmanagerConfigured(() => {
31 this.prometheusService.getAlerts().subscribe(
32 (alerts) => this.handleAlerts(alerts),
33 (resp) => {
34 if ([404, 504].includes(resp.status)) {
35 this.prometheusService.disableAlertmanagerConfig();
11fdf7f2 36 }
494da23a
TL
37 }
38 );
11fdf7f2
TL
39 });
40 }
41
9f95a23c
TL
42 getRules() {
43 this.prometheusService.ifPrometheusConfigured(() => {
44 this.prometheusService.getRules('alerting').subscribe((groups) => {
45 this.rules = groups['groups'].reduce((acc, group) => {
46 return acc.concat(
47 group.rules.map((rule) => {
48 rule.group = group.name;
49 return rule;
50 })
51 );
52 }, []);
53 });
54 });
55 }
56
57 refresh() {
58 this.getAlerts();
59 this.getRules();
60 }
61
494da23a 62 private handleAlerts(alerts: AlertmanagerAlert[]) {
11fdf7f2
TL
63 if (this.canAlertsBeNotified) {
64 this.notifyOnAlertChanges(alerts, this.alerts);
65 }
cd265ab1
TL
66 this.activeAlerts = _.reduce<AlertmanagerAlert, number>(
67 this.alerts,
68 (result, alert) => (alert.status.state === 'active' ? ++result : result),
69 0
70 );
2a845540
TL
71 this.activeCriticalAlerts = _.reduce<AlertmanagerAlert, number>(
72 this.alerts,
73 (result, alert) =>
74 alert.status.state === 'active' && alert.labels.severity === 'critical' ? ++result : result,
75 0
76 );
77 this.activeWarningAlerts = _.reduce<AlertmanagerAlert, number>(
78 this.alerts,
79 (result, alert) =>
80 alert.status.state === 'active' && alert.labels.severity === 'warning' ? ++result : result,
81 0
82 );
11fdf7f2
TL
83 this.alerts = alerts;
84 this.canAlertsBeNotified = true;
85 }
86
494da23a 87 private notifyOnAlertChanges(alerts: AlertmanagerAlert[], oldAlerts: AlertmanagerAlert[]) {
11fdf7f2
TL
88 const changedAlerts = this.getChangedAlerts(
89 this.alertFormatter.convertToCustomAlerts(alerts),
90 this.alertFormatter.convertToCustomAlerts(oldAlerts)
91 );
522d829b
TL
92 const suppressedFiltered = _.filter(changedAlerts, (alert) => {
93 return alert.status !== 'suppressed';
94 });
95 const notifications = suppressedFiltered.map((alert) =>
11fdf7f2
TL
96 this.alertFormatter.convertAlertToNotification(alert)
97 );
98 this.alertFormatter.sendNotifications(notifications);
99 }
100
101 private getChangedAlerts(alerts: PrometheusCustomAlert[], oldAlerts: PrometheusCustomAlert[]) {
102 const updatedAndNew = _.differenceWith(alerts, oldAlerts, _.isEqual);
103 return updatedAndNew.concat(this.getVanishedAlerts(alerts, oldAlerts));
104 }
105
106 private getVanishedAlerts(alerts: PrometheusCustomAlert[], oldAlerts: PrometheusCustomAlert[]) {
107 return _.differenceWith(oldAlerts, alerts, (a, b) => a.fingerprint === b.fingerprint).map(
108 (alert) => {
109 alert.status = 'resolved';
110 return alert;
111 }
112 );
113 }
114}