mirror of
https://github.com/grafana/grafana.git
synced 2025-09-22 01:46:39 +08:00
90 lines
2.9 KiB
TypeScript
90 lines
2.9 KiB
TypeScript
import { uniqBy } from 'lodash';
|
|
|
|
import { Labels } from '@grafana/data';
|
|
import { Matcher, MatcherOperator } from 'app/plugins/datasource/alertmanager/types';
|
|
import { Alert } from 'app/types/unified-alerting';
|
|
|
|
import { MatcherFieldValue } from '../types/silence-form';
|
|
|
|
import { parseMatcher } from './alertmanager';
|
|
|
|
// Parses a list of entries like like "['foo=bar', 'baz=~bad*']" into SilenceMatcher[]
|
|
export function parseQueryParamMatchers(matcherPairs: string[]): Matcher[] {
|
|
const parsedMatchers = matcherPairs.filter((x) => !!x.trim()).map((x) => parseMatcher(x.trim()));
|
|
|
|
// Due to migration, old alert rules might have a duplicated alertname label
|
|
// To handle that case want to filter out duplicates and make sure there are only unique labels
|
|
return uniqBy(parsedMatchers, (matcher) => matcher.name);
|
|
}
|
|
|
|
export const getMatcherQueryParams = (labels: Labels) => {
|
|
const validMatcherLabels = Object.entries(labels).filter(
|
|
([labelKey]) => !(labelKey.startsWith('__') && labelKey.endsWith('__'))
|
|
);
|
|
|
|
const matcherUrlParams = new URLSearchParams();
|
|
validMatcherLabels.forEach(([labelKey, labelValue]) =>
|
|
matcherUrlParams.append('matcher', `${labelKey}=${labelValue}`)
|
|
);
|
|
|
|
return matcherUrlParams;
|
|
};
|
|
|
|
interface MatchedInstance {
|
|
id: string;
|
|
data: {
|
|
matchedInstance: Alert;
|
|
};
|
|
}
|
|
|
|
export const findAlertInstancesWithMatchers = (
|
|
instances: Alert[],
|
|
matchers: MatcherFieldValue[]
|
|
): MatchedInstance[] => {
|
|
const anchorRegex = (regexpString: string): RegExp => {
|
|
// Silence matchers are always fully anchored in the Alertmanager: https://github.com/prometheus/alertmanager/pull/748
|
|
if (!regexpString.startsWith('^')) {
|
|
regexpString = '^' + regexpString;
|
|
}
|
|
if (!regexpString.endsWith('$')) {
|
|
regexpString = regexpString + '$';
|
|
}
|
|
return new RegExp(regexpString);
|
|
};
|
|
|
|
const matchesInstance = (instance: Alert, matcher: MatcherFieldValue) => {
|
|
return Object.entries(instance.labels).some(([key, value]) => {
|
|
if (!matcher.name || !matcher.value) {
|
|
return false;
|
|
}
|
|
if (matcher.name !== key) {
|
|
return false;
|
|
}
|
|
switch (matcher.operator) {
|
|
case MatcherOperator.equal:
|
|
return matcher.value === value;
|
|
case MatcherOperator.notEqual:
|
|
return matcher.value !== value;
|
|
case MatcherOperator.regex:
|
|
const regex = anchorRegex(matcher.value);
|
|
return regex.test(value);
|
|
case MatcherOperator.notRegex:
|
|
const negregex = anchorRegex(matcher.value);
|
|
return !negregex.test(value);
|
|
default:
|
|
return false;
|
|
}
|
|
});
|
|
};
|
|
|
|
const filteredInstances = instances.filter((instance) => {
|
|
return matchers.every((matcher) => matchesInstance(instance, matcher));
|
|
});
|
|
const mappedInstances = filteredInstances.map((instance) => ({
|
|
id: `${instance.activeAt}-${instance.value}`,
|
|
data: { matchedInstance: instance },
|
|
}));
|
|
|
|
return mappedInstances;
|
|
};
|