mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: fix maching loki prom rules to rule rules, rename "Inactive" to "Normal" (#34111)
This commit is contained in:
parent
a71cebbcb1
commit
ddb2fc1ae6
@ -244,16 +244,16 @@ describe('RuleList', () => {
|
||||
let ruleRows = table.querySelectorAll<HTMLTableRowElement>(':scope > tbody > tr');
|
||||
expect(ruleRows).toHaveLength(4);
|
||||
|
||||
expect(ruleRows[0]).toHaveTextContent('n/a');
|
||||
expect(ruleRows[0]).toHaveTextContent('Recording rule');
|
||||
expect(ruleRows[0]).toHaveTextContent('recordingrule');
|
||||
|
||||
expect(ruleRows[1]).toHaveTextContent('firing');
|
||||
expect(ruleRows[1]).toHaveTextContent('Firing');
|
||||
expect(ruleRows[1]).toHaveTextContent('alertingrule');
|
||||
|
||||
expect(ruleRows[2]).toHaveTextContent('pending');
|
||||
expect(ruleRows[2]).toHaveTextContent('Pending');
|
||||
expect(ruleRows[2]).toHaveTextContent('p-rule');
|
||||
|
||||
expect(ruleRows[3]).toHaveTextContent('inactive');
|
||||
expect(ruleRows[3]).toHaveTextContent('Normal');
|
||||
expect(ruleRows[3]).toHaveTextContent('i-rule');
|
||||
|
||||
expect(byText('Labels').query()).not.toBeInTheDocument();
|
||||
@ -277,8 +277,8 @@ describe('RuleList', () => {
|
||||
let instanceRows = instancesTable?.querySelectorAll<HTMLTableRowElement>(':scope > tbody > tr');
|
||||
expect(instanceRows).toHaveLength(2);
|
||||
|
||||
expect(instanceRows![0]).toHaveTextContent('firingfoo=barseverity=warning2021-03-18 13:47:05');
|
||||
expect(instanceRows![1]).toHaveTextContent('firingfoo=bazseverity=error2021-03-18 13:47:05');
|
||||
expect(instanceRows![0]).toHaveTextContent('Firingfoo=barseverity=warning2021-03-18 13:47:05');
|
||||
expect(instanceRows![1]).toHaveTextContent('Firingfoo=bazseverity=error2021-03-18 13:47:05');
|
||||
|
||||
// expand details of an instance
|
||||
userEvent.click(ui.alertCollapseToggle.get(instanceRows![0]));
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { GrafanaAlertState, PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
||||
import React, { FC } from 'react';
|
||||
import { alertStateToReadable } from '../../utils/rules';
|
||||
import { State, StateTag } from '../StateTag';
|
||||
|
||||
const alertStateToState: Record<PromAlertingRuleState | GrafanaAlertState, State> = {
|
||||
@ -17,4 +18,6 @@ interface Props {
|
||||
state: PromAlertingRuleState | GrafanaAlertState;
|
||||
}
|
||||
|
||||
export const AlertStateTag: FC<Props> = ({ state }) => <StateTag state={alertStateToState[state]}>{state}</StateTag>;
|
||||
export const AlertStateTag: FC<Props> = ({ state }) => (
|
||||
<StateTag state={alertStateToState[state]}>{alertStateToReadable(state)}</StateTag>
|
||||
);
|
||||
|
@ -3,8 +3,8 @@ import { GrafanaTheme } from '@grafana/data';
|
||||
import { useStyles } from '@grafana/ui';
|
||||
import { CombinedRule } from 'app/types/unified-alerting';
|
||||
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
||||
import { capitalize } from 'lodash';
|
||||
import React, { FC, useState } from 'react';
|
||||
import { alertStateToReadable } from '../../utils/rules';
|
||||
import { CollapseToggle } from '../CollapseToggle';
|
||||
import { RulesTable } from './RulesTable';
|
||||
|
||||
@ -26,7 +26,7 @@ export const RuleListStateSection: FC<Props> = ({ rules, state, defaultCollapsed
|
||||
isCollapsed={collapsed}
|
||||
onToggle={() => setCollapsed(!collapsed)}
|
||||
/>
|
||||
{capitalize(state)} ({rules.length})
|
||||
{alertStateToReadable(state)} ({rules.length})
|
||||
</h4>
|
||||
{!collapsed && <RulesTable rules={rules} showGroupColumn={true} />}
|
||||
</>
|
@ -4,7 +4,7 @@ import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
||||
import React, { FC, useMemo } from 'react';
|
||||
import { getFiltersFromUrlParams } from '../../utils/misc';
|
||||
import { isAlertingRule } from '../../utils/rules';
|
||||
import { RuleListStateSection } from './RuleListSateSection';
|
||||
import { RuleListStateSection } from './RuleListStateSection';
|
||||
|
||||
interface Props {
|
||||
namespaces: CombinedRuleNamespace[];
|
||||
|
@ -8,6 +8,7 @@ import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||
import { getFiltersFromUrlParams } from '../../utils/misc';
|
||||
import { DataSourcePicker } from '@grafana/runtime';
|
||||
import { alertStateToReadable } from '../../utils/rules';
|
||||
|
||||
const RulesFilter = () => {
|
||||
const [queryParams, setQueryParams] = useQueryParams();
|
||||
@ -19,7 +20,10 @@ const RulesFilter = () => {
|
||||
const { dataSource, alertState, queryString } = getFiltersFromUrlParams(queryParams);
|
||||
|
||||
const styles = useStyles(getStyles);
|
||||
const stateOptions = Object.entries(PromAlertingRuleState).map(([key, value]) => ({ label: key, value }));
|
||||
const stateOptions = Object.entries(PromAlertingRuleState).map(([key, value]) => ({
|
||||
label: alertStateToReadable(value),
|
||||
value,
|
||||
}));
|
||||
|
||||
const handleDataSourceChange = (dataSourceValue: DataSourceInstanceSettings) => {
|
||||
setQueryParams({ dataSource: dataSourceValue.name });
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { ConfirmModal, useStyles2 } from '@grafana/ui';
|
||||
import React, { FC, Fragment, useState } from 'react';
|
||||
import { getRuleIdentifier, isAlertingRule, stringifyRuleIdentifier } from '../../utils/rules';
|
||||
import { getRuleIdentifier, isAlertingRule, isRecordingRule, stringifyRuleIdentifier } from '../../utils/rules';
|
||||
import { CollapseToggle } from '../CollapseToggle';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { RuleDetails } from './RuleDetails';
|
||||
@ -126,7 +126,15 @@ export const RulesTable: FC<Props> = ({
|
||||
data-testid="rule-collapse-toggle"
|
||||
/>
|
||||
</td>
|
||||
<td>{promRule && isAlertingRule(promRule) ? <AlertStateTag state={promRule.state} /> : 'n/a'}</td>
|
||||
<td>
|
||||
{promRule && isAlertingRule(promRule) ? (
|
||||
<AlertStateTag state={promRule.state} />
|
||||
) : promRule && isRecordingRule(promRule) ? (
|
||||
'Recording rule'
|
||||
) : (
|
||||
'n/a'
|
||||
)}
|
||||
</td>
|
||||
<td>{rule.name}</td>
|
||||
{showGroupColumn && (
|
||||
<td>{isCloudRulesSource(rulesSource) ? `${namespace.name} > ${group.name}` : namespace.name}</td>
|
||||
|
@ -164,23 +164,42 @@ function rulerRuleToCombinedRule(
|
||||
};
|
||||
}
|
||||
|
||||
// find existing rule in group that matches the given prom rule
|
||||
function getExistingRuleInGroup(
|
||||
rule: Rule,
|
||||
group: CombinedRuleGroup,
|
||||
rulesSource: RulesSource
|
||||
): CombinedRule | undefined {
|
||||
return isGrafanaRulesSource(rulesSource)
|
||||
? group!.rules.find((existingRule) => existingRule.name === rule.name) // assume grafana groups have only the one rule. check name anyway because paranoid
|
||||
: group!.rules.find((existingRule) => {
|
||||
return !existingRule.promRule && isCombinedRuleEqualToPromRule(existingRule, rule);
|
||||
});
|
||||
if (isGrafanaRulesSource(rulesSource)) {
|
||||
// assume grafana groups have only the one rule. check name anyway because paranoid
|
||||
return group!.rules.find((existingRule) => existingRule.name === rule.name);
|
||||
}
|
||||
return (
|
||||
// try finding a rule that matches name, labels, annotations and query
|
||||
group!.rules.find(
|
||||
(existingRule) => !existingRule.promRule && isCombinedRuleEqualToPromRule(existingRule, rule, true)
|
||||
) ??
|
||||
// if that fails, try finding a rule that only matches name, labels and annotations.
|
||||
// loki & prom can sometimes modify the query so it doesnt match, eg `2 > 1` becomes `1`
|
||||
group!.rules.find(
|
||||
(existingRule) => !existingRule.promRule && isCombinedRuleEqualToPromRule(existingRule, rule, false)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function isCombinedRuleEqualToPromRule(combinedRule: CombinedRule, rule: Rule): boolean {
|
||||
function isCombinedRuleEqualToPromRule(combinedRule: CombinedRule, rule: Rule, checkQuery = true): boolean {
|
||||
if (combinedRule.name === rule.name) {
|
||||
return (
|
||||
JSON.stringify([hashQuery(combinedRule.query), combinedRule.labels, combinedRule.annotations]) ===
|
||||
JSON.stringify([hashQuery(rule.query), rule.labels || {}, isAlertingRule(rule) ? rule.annotations || {} : {}])
|
||||
JSON.stringify([
|
||||
checkQuery ? hashQuery(combinedRule.query) : '',
|
||||
combinedRule.labels,
|
||||
combinedRule.annotations,
|
||||
]) ===
|
||||
JSON.stringify([
|
||||
checkQuery ? hashQuery(rule.query) : '',
|
||||
rule.labels || {},
|
||||
isAlertingRule(rule) ? rule.annotations || {} : {},
|
||||
])
|
||||
);
|
||||
}
|
||||
return false;
|
||||
@ -194,6 +213,6 @@ function hashQuery(query: string) {
|
||||
}
|
||||
// whitespace could be added or removed
|
||||
query = query.replace(/\s|\n/g, '');
|
||||
// labels matchers can be reordered, so sort the enitre string, esentially comparing just hte character counts
|
||||
// labels matchers can be reordered, so sort the enitre string, esentially comparing just the character counts
|
||||
return query.split('').sort().join('');
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import {
|
||||
Annotations,
|
||||
GrafanaAlertState,
|
||||
Labels,
|
||||
PromAlertingRuleState,
|
||||
PromRuleType,
|
||||
RulerAlertingRuleDTO,
|
||||
RulerGrafanaRuleDTO,
|
||||
@ -20,6 +22,7 @@ import {
|
||||
import { AsyncRequestState } from './redux';
|
||||
import { RULER_NOT_SUPPORTED_MSG } from './constants';
|
||||
import { hash } from './misc';
|
||||
import { capitalize } from 'lodash';
|
||||
|
||||
export function isAlertingRule(rule: Rule): rule is AlertingRule {
|
||||
return rule.type === PromRuleType.Alerting;
|
||||
@ -132,3 +135,10 @@ export function ruleWithLocationToRuleIdentifier(ruleWithLocation: RuleWithLocat
|
||||
ruleWithLocation.rule
|
||||
);
|
||||
}
|
||||
|
||||
export function alertStateToReadable(state: PromAlertingRuleState | GrafanaAlertState): string {
|
||||
if (state === PromAlertingRuleState.Inactive) {
|
||||
return 'Normal';
|
||||
}
|
||||
return capitalize(state);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user