Alerting: Add filters for AlertList panel (#43130)

* add state filters for prom alerts

* combine state filters

* add datasource filter for panel

* remove duplicate state check

* show only prom, loki, and grafana datasources
This commit is contained in:
Nathan Rodman 2021-12-16 10:17:24 -08:00 committed by GitHub
parent be498f312e
commit 187a8703c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 41 deletions

View File

@ -4,6 +4,7 @@ import { RulesSource } from 'app/types/unified-alerting';
import { getAllDataSources } from './config';
export const GRAFANA_RULES_SOURCE_NAME = 'grafana';
export const GRAFANA_DATASOURCE_NAME = '-- Grafana --';
export enum DataSourceType {
Alertmanager = 'alertmanager',

View File

@ -8,7 +8,6 @@ import { GrafanaAlertState, PromAlertingRuleState } from 'app/types/unified-aler
import { UnifiedAlertListOptions } from './types';
import { AlertInstancesTable } from 'app/features/alerting/unified/components/rules/AlertInstancesTable';
import { sortAlerts } from 'app/features/alerting/unified/utils/misc';
import { labelsMatchMatchers, parseMatchers } from 'app/features/alerting/unified/utils/alertmanager';
interface Props {
ruleWithLocation: PromRuleWithLocation;
@ -44,23 +43,22 @@ export const AlertInstances = ({ ruleWithLocation, options }: Props) => {
};
function filterAlerts(options: PanelProps<UnifiedAlertListOptions>['options'], alerts: Alert[]): Alert[] {
const hasAlertState = Object.values(options.stateFilter).some((value) => value);
let filteredAlerts = [...alerts];
if (options.alertInstanceLabelFilter) {
const matchers = parseMatchers(options.alertInstanceLabelFilter || '');
filteredAlerts = filteredAlerts.filter(({ labels }) => labelsMatchMatchers(labels, matchers));
}
if (Object.values(options.alertInstanceStateFilter).some((value) => value)) {
if (hasAlertState) {
filteredAlerts = filteredAlerts.filter((alert) => {
return (
(options.alertInstanceStateFilter.Alerting && alert.state === GrafanaAlertState.Alerting) ||
(options.alertInstanceStateFilter.Pending && alert.state === GrafanaAlertState.Pending) ||
(options.alertInstanceStateFilter.NoData && alert.state === GrafanaAlertState.NoData) ||
(options.alertInstanceStateFilter.Normal && alert.state === GrafanaAlertState.Normal) ||
(options.alertInstanceStateFilter.Error && alert.state === GrafanaAlertState.Error)
(options.stateFilter.firing &&
(alert.state === GrafanaAlertState.Alerting || alert.state === PromAlertingRuleState.Firing)) ||
(options.stateFilter.pending &&
(alert.state === GrafanaAlertState.Pending || alert.state === PromAlertingRuleState.Pending)) ||
(options.stateFilter.noData && alert.state === GrafanaAlertState.NoData) ||
(options.stateFilter.normal && alert.state === GrafanaAlertState.Normal) ||
(options.stateFilter.error && alert.state === GrafanaAlertState.Error) ||
(options.stateFilter.inactive && alert.state === PromAlertingRuleState.Inactive)
);
});
}
return filteredAlerts;
}

View File

@ -13,10 +13,15 @@ import { flattenRules, alertStateToState, getFirstActiveAt } from 'app/features/
import { PromRuleWithLocation } from 'app/types/unified-alerting';
import { fetchAllPromRulesAction } from 'app/features/alerting/unified/state/actions';
import { useUnifiedAlertingSelector } from 'app/features/alerting/unified/hooks/useUnifiedAlertingSelector';
import { getAllRulesSourceNames } from 'app/features/alerting/unified/utils/datasource';
import {
getAllRulesSourceNames,
GRAFANA_DATASOURCE_NAME,
GRAFANA_RULES_SOURCE_NAME,
} from 'app/features/alerting/unified/utils/datasource';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { Annotation, RULE_LIST_POLL_INTERVAL_MS } from 'app/features/alerting/unified/utils/constants';
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
import { labelsMatchMatchers, parseMatchers } from 'app/features/alerting/unified/utils/alertmanager';
export function UnifiedAlertList(props: PanelProps<UnifiedAlertListOptions>) {
const dispatch = useDispatch();
@ -151,11 +156,31 @@ function filterRules(options: PanelProps<UnifiedAlertListOptions>['options'], ru
);
});
}
if (options.alertInstanceLabelFilter) {
const matchers = parseMatchers(options.alertInstanceLabelFilter);
// Reduce rules and instances to only those that match
filteredRules = filteredRules.reduce((rules, rule) => {
const filteredAlerts = rule.rule.alerts.filter(({ labels }) => labelsMatchMatchers(labels, matchers));
if (filteredAlerts.length) {
rules.push({ ...rule, rule: { ...rule.rule, alerts: filteredAlerts } });
}
return rules;
}, [] as PromRuleWithLocation[]);
}
if (options.folder) {
filteredRules = filteredRules.filter((rule) => {
return rule.namespaceName === options.folder.title;
});
}
if (options.datasource) {
const isGrafanaDS = options.datasource === GRAFANA_DATASOURCE_NAME;
filteredRules = filteredRules.filter(
isGrafanaDS
? ({ dataSourceName }) => dataSourceName === GRAFANA_RULES_SOURCE_NAME
: ({ dataSourceName }) => dataSourceName === options.datasource
);
}
return filteredRules;
}

View File

@ -5,7 +5,7 @@ import { AlertList } from './AlertList';
import { UnifiedAlertList } from './UnifiedAlertList';
import { AlertListOptions, ShowOption, SortOrder, UnifiedAlertListOptions } from './types';
import { alertListPanelMigrationHandler } from './AlertListMigrationHandler';
import { config } from '@grafana/runtime';
import { config, DataSourcePicker } from '@grafana/runtime';
import { RuleFolderPicker } from 'app/features/alerting/unified/components/rule-editor/RuleFolderPicker';
import {
ALL_FOLDER,
@ -221,9 +221,29 @@ const unifiedAlertList = new PanelPlugin<UnifiedAlertListOptions>(UnifiedAlertLi
},
category: ['Filter'],
})
.addCustomEditor({
path: 'datasource',
name: 'Datasource',
description: 'Filter alerts from selected datasource',
id: 'datasource',
defaultValue: null,
editor: function RenderDatasourcePicker(props) {
return (
<DataSourcePicker
{...props}
type={['prometheus', 'loki', 'grafana']}
noDefault
current={props.value}
onChange={(ds) => props.onChange(ds.name)}
onClear={() => props.onChange('')}
/>
);
},
category: ['Filter'],
})
.addBooleanSwitch({
path: 'stateFilter.firing',
name: 'Alerting',
name: 'Alerting / Firing',
defaultValue: true,
category: ['Alert state filter'],
})
@ -240,34 +260,22 @@ const unifiedAlertList = new PanelPlugin<UnifiedAlertListOptions>(UnifiedAlertLi
category: ['Alert state filter'],
})
.addBooleanSwitch({
path: 'alertInstanceStateFilter.Alerting',
name: 'Alerting',
defaultValue: true,
category: ['Alert instance state filter'],
})
.addBooleanSwitch({
path: 'alertInstanceStateFilter.Pending',
name: 'Pending',
defaultValue: true,
category: ['Alert instance state filter'],
})
.addBooleanSwitch({
path: 'alertInstanceStateFilter.NoData',
path: 'stateFilter.noData',
name: 'No Data',
defaultValue: false,
category: ['Alert instance state filter'],
category: ['Alert state filter'],
})
.addBooleanSwitch({
path: 'alertInstanceStateFilter.Normal',
path: 'stateFilter.normal',
name: 'Normal',
defaultValue: false,
category: ['Alert instance state filter'],
category: ['Alert state filter'],
})
.addBooleanSwitch({
path: 'alertInstanceStateFilter.Error',
path: 'stateFilter.error',
name: 'Error',
defaultValue: true,
category: ['Alert instance state filter'],
category: ['Alert state filter'],
});
});

View File

@ -1,5 +1,3 @@
import { GrafanaAlertState, PromAlertingRuleState } from 'app/types/unified-alerting-dto';
export enum SortOrder {
AlphaAsc = 1,
AlphaDesc,
@ -32,6 +30,15 @@ export interface AlertListOptions {
folderId: number;
}
interface StateFilter {
firing: boolean;
pending: boolean;
inactive: boolean;
noData: boolean;
normal: boolean;
error: boolean;
}
export interface UnifiedAlertListOptions {
maxItems: number;
sortOrder: SortOrder;
@ -39,11 +46,7 @@ export interface UnifiedAlertListOptions {
alertName: string;
showInstances: boolean;
folder: { id: number; title: string };
stateFilter: {
[K in PromAlertingRuleState]: boolean;
};
stateFilter: StateFilter;
alertInstanceLabelFilter: string;
alertInstanceStateFilter: {
[K in GrafanaAlertState]: boolean;
};
datasource: string;
}