summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts')
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts
new file mode 100644
index 000000000..6223808fb
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts
@@ -0,0 +1,100 @@
+import { Injectable } from '@angular/core';
+
+import _ from 'lodash';
+
+import { PrometheusService } from '../api/prometheus.service';
+import {
+ AlertmanagerAlert,
+ PrometheusCustomAlert,
+ PrometheusRule
+} from '../models/prometheus-alerts';
+import { PrometheusAlertFormatter } from './prometheus-alert-formatter';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class PrometheusAlertService {
+ private canAlertsBeNotified = false;
+ alerts: AlertmanagerAlert[] = [];
+ rules: PrometheusRule[] = [];
+ activeAlerts: number;
+
+ constructor(
+ private alertFormatter: PrometheusAlertFormatter,
+ private prometheusService: PrometheusService
+ ) {}
+
+ getAlerts() {
+ this.prometheusService.ifAlertmanagerConfigured(() => {
+ this.prometheusService.getAlerts().subscribe(
+ (alerts) => this.handleAlerts(alerts),
+ (resp) => {
+ if ([404, 504].includes(resp.status)) {
+ this.prometheusService.disableAlertmanagerConfig();
+ }
+ }
+ );
+ });
+ }
+
+ getRules() {
+ this.prometheusService.ifPrometheusConfigured(() => {
+ this.prometheusService.getRules('alerting').subscribe((groups) => {
+ this.rules = groups['groups'].reduce((acc, group) => {
+ return acc.concat(
+ group.rules.map((rule) => {
+ rule.group = group.name;
+ return rule;
+ })
+ );
+ }, []);
+ });
+ });
+ }
+
+ refresh() {
+ this.getAlerts();
+ this.getRules();
+ }
+
+ private handleAlerts(alerts: AlertmanagerAlert[]) {
+ if (this.canAlertsBeNotified) {
+ this.notifyOnAlertChanges(alerts, this.alerts);
+ }
+ this.activeAlerts = _.reduce<AlertmanagerAlert, number>(
+ this.alerts,
+ (result, alert) => (alert.status.state === 'active' ? ++result : result),
+ 0
+ );
+ this.alerts = alerts;
+ this.canAlertsBeNotified = true;
+ }
+
+ private notifyOnAlertChanges(alerts: AlertmanagerAlert[], oldAlerts: AlertmanagerAlert[]) {
+ const changedAlerts = this.getChangedAlerts(
+ this.alertFormatter.convertToCustomAlerts(alerts),
+ this.alertFormatter.convertToCustomAlerts(oldAlerts)
+ );
+ const suppressedFiltered = _.filter(changedAlerts, (alert) => {
+ return alert.status !== 'suppressed';
+ });
+ const notifications = suppressedFiltered.map((alert) =>
+ this.alertFormatter.convertAlertToNotification(alert)
+ );
+ this.alertFormatter.sendNotifications(notifications);
+ }
+
+ private getChangedAlerts(alerts: PrometheusCustomAlert[], oldAlerts: PrometheusCustomAlert[]) {
+ const updatedAndNew = _.differenceWith(alerts, oldAlerts, _.isEqual);
+ return updatedAndNew.concat(this.getVanishedAlerts(alerts, oldAlerts));
+ }
+
+ private getVanishedAlerts(alerts: PrometheusCustomAlert[], oldAlerts: PrometheusCustomAlert[]) {
+ return _.differenceWith(oldAlerts, alerts, (a, b) => a.fingerprint === b.fingerprint).map(
+ (alert) => {
+ alert.status = 'resolved';
+ return alert;
+ }
+ );
+ }
+}