mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
Add list of labels in the policy route path that produces the policy matchers to match potential instances
This commit is contained in:
parent
8c539da81b
commit
ee73ae9cf9
@ -12,7 +12,7 @@ import { HoverCard } from '../HoverCard';
|
||||
type MatchersProps = { matchers: ObjectMatcher[] };
|
||||
|
||||
// renders the first N number of matchers
|
||||
const Matchers: FC<MatchersProps> = ({ matchers }) => {
|
||||
const Matchers: FC<MatchersProps> = React.forwardRef<HTMLInputElement, MatchersProps>(({ matchers }, ref) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
const NUM_MATCHERS = 5;
|
||||
@ -22,7 +22,7 @@ const Matchers: FC<MatchersProps> = ({ matchers }) => {
|
||||
const hasMoreMatchers = rest.length > 0;
|
||||
|
||||
return (
|
||||
<span data-testid="label-matchers">
|
||||
<span data-testid="label-matchers" ref={ref}>
|
||||
<Stack direction="row" gap={1} alignItems="center">
|
||||
{firstFew.map((matcher) => (
|
||||
<MatcherBadge key={uniqueId()} matcher={matcher} />
|
||||
@ -48,7 +48,9 @@ const Matchers: FC<MatchersProps> = ({ matchers }) => {
|
||||
</Stack>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
Matchers.displayName = 'Matchers';
|
||||
|
||||
interface MatcherBadgeProps {
|
||||
matcher: ObjectMatcher;
|
||||
|
@ -22,10 +22,8 @@ function NotificationPreviewByAlertManager({
|
||||
}) {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
const { routesByIdMap, receiversByName, matchingMap, loading, error } = useAlertmanagerNotificationRoutingPreview(
|
||||
alertManagerSource.name,
|
||||
potentialInstances
|
||||
);
|
||||
const { routesByIdMap, receiversByName, matchingMap, matchingMapPath, loading, error } =
|
||||
useAlertmanagerNotificationRoutingPreview(alertManagerSource.name, potentialInstances);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
@ -74,6 +72,8 @@ function NotificationPreviewByAlertManager({
|
||||
key={routeId}
|
||||
routesByIdMap={routesByIdMap}
|
||||
alertManagerSourceName={alertManagerSource.name}
|
||||
matchingMap={matchingMap}
|
||||
matchingMapPath={matchingMapPath}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@ -25,6 +25,8 @@ function NotificationRouteHeader({
|
||||
alertManagerSourceName,
|
||||
expandRoute,
|
||||
onExpandRouteClick,
|
||||
matchingMap,
|
||||
matchingMapPath,
|
||||
}: {
|
||||
route: RouteWithPath;
|
||||
receiver: Receiver;
|
||||
@ -33,6 +35,8 @@ function NotificationRouteHeader({
|
||||
alertManagerSourceName: string;
|
||||
expandRoute: boolean;
|
||||
onExpandRouteClick: (expand: boolean) => void;
|
||||
matchingMap: Map<string, AlertInstanceMatch[]>;
|
||||
matchingMapPath: Map<string, AlertInstanceMatch[]>;
|
||||
}) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const [showDetails, setShowDetails] = useState(false);
|
||||
@ -82,6 +86,8 @@ function NotificationRouteHeader({
|
||||
receiver={receiver}
|
||||
routesByIdMap={routesByIdMap}
|
||||
alertManagerSourceName={alertManagerSourceName}
|
||||
matchingMap={matchingMap}
|
||||
matchingMapPath={matchingMapPath}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@ -94,6 +100,8 @@ interface NotificationRouteProps {
|
||||
instanceMatches: AlertInstanceMatch[];
|
||||
routesByIdMap: Map<string, RouteWithPath>;
|
||||
alertManagerSourceName: string;
|
||||
matchingMap: Map<string, AlertInstanceMatch[]>;
|
||||
matchingMapPath: Map<string, AlertInstanceMatch[]>;
|
||||
}
|
||||
|
||||
export function NotificationRoute({
|
||||
@ -102,26 +110,35 @@ export function NotificationRoute({
|
||||
receiver,
|
||||
routesByIdMap,
|
||||
alertManagerSourceName,
|
||||
matchingMap,
|
||||
matchingMapPath,
|
||||
}: NotificationRouteProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const [expandRoute, setExpandRoute] = useToggle(false);
|
||||
const GREY_COLOR_INDEX = 9;
|
||||
|
||||
const instanceMatchesUnique = [
|
||||
...new Map(
|
||||
instanceMatches.map((matchInstance) => [JSON.stringify(matchInstance.instance), matchInstance])
|
||||
).values(),
|
||||
];
|
||||
return (
|
||||
<div data-testid="matching-policy-route">
|
||||
<NotificationRouteHeader
|
||||
route={route}
|
||||
receiver={receiver}
|
||||
routesByIdMap={routesByIdMap}
|
||||
instancesCount={instanceMatches.length}
|
||||
instancesCount={instanceMatchesUnique.length}
|
||||
alertManagerSourceName={alertManagerSourceName}
|
||||
expandRoute={expandRoute}
|
||||
onExpandRouteClick={setExpandRoute}
|
||||
matchingMap={matchingMap}
|
||||
matchingMapPath={matchingMapPath}
|
||||
/>
|
||||
{expandRoute && (
|
||||
<Stack gap={1} direction="column">
|
||||
<div className={styles.routeInstances} data-testid="route-matching-instance">
|
||||
{instanceMatches.map((instanceMatch) => {
|
||||
{instanceMatchesUnique.map((instanceMatch) => {
|
||||
const matchArray = Array.from(instanceMatch.labelsMatch.entries());
|
||||
let matchResult = matchArray.map(([label, matchResult]) => ({
|
||||
label: `${label[0]}=${label[1]}`,
|
||||
|
@ -3,19 +3,56 @@ import { compact } from 'lodash';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Button, Icon, Modal, useStyles2 } from '@grafana/ui';
|
||||
import { Button, Icon, Modal, TagList, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { Receiver } from '../../../../../../plugins/datasource/alertmanager/types';
|
||||
import { Stack } from '../../../../../../plugins/datasource/parca/QueryEditor/Stack';
|
||||
import { getNotificationsPermissions } from '../../../utils/access-control';
|
||||
import { Label } from '../../../utils/matchers';
|
||||
import { makeAMLink } from '../../../utils/misc';
|
||||
import { AlertInstanceMatch, LabelMatchResult } from '../../../utils/notification-policies';
|
||||
import { Authorize } from '../../Authorize';
|
||||
import { Matchers } from '../../notification-policies/Matchers';
|
||||
|
||||
import { NotificationPolicyMatchers } from './NotificationPolicyMatchers';
|
||||
import { hasEmptyMatchers, isDefaultPolicy, RouteWithPath } from './route';
|
||||
|
||||
function PolicyPath({ route, routesByIdMap }: { routesByIdMap: Map<string, RouteWithPath>; route: RouteWithPath }) {
|
||||
export const LabelsMatching = ({
|
||||
routeId,
|
||||
matchingMapPath,
|
||||
}: {
|
||||
routeId: string;
|
||||
matchingMap: Map<string, AlertInstanceMatch[]>;
|
||||
matchingMapPath: Map<string, AlertInstanceMatch[]>;
|
||||
}) => {
|
||||
const matching = matchingMapPath.get(routeId);
|
||||
if (!matching) {
|
||||
return null;
|
||||
}
|
||||
const matchingInstances: AlertInstanceMatch[] | undefined = matchingMapPath.get(routeId);
|
||||
// get array of labelsMatch from mapchingInstances
|
||||
const valuesIterator = matchingInstances?.map((instance) => instance.labelsMatch)?.values() ?? [];
|
||||
const labelMaps: Array<Map<Label, LabelMatchResult>> = Array.from(valuesIterator);
|
||||
const labels = labelMaps
|
||||
.map((m) => Array.from(m.entries() ?? []).filter(([label, result]) => result.match))
|
||||
.flat()
|
||||
.map(([label, _]) => label);
|
||||
// get array of strings from labels, remove duplicated
|
||||
const labelsStringArray = Array.from(new Set(labels.map((label: Label) => label[0] + '=' + label[1])));
|
||||
return <TagList tags={labelsStringArray} />;
|
||||
};
|
||||
|
||||
function PolicyPath({
|
||||
route,
|
||||
routesByIdMap,
|
||||
matchingMap,
|
||||
matchingMapPath,
|
||||
}: {
|
||||
routesByIdMap: Map<string, RouteWithPath>;
|
||||
route: RouteWithPath;
|
||||
matchingMapPath: Map<string, AlertInstanceMatch[]>;
|
||||
matchingMap: Map<string, AlertInstanceMatch[]>;
|
||||
}) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const routePathIds = route.path?.slice(1) ?? [];
|
||||
const routePathObjects = [...compact(routePathIds.map((id) => routesByIdMap.get(id))), route];
|
||||
@ -30,7 +67,18 @@ function PolicyPath({ route, routesByIdMap }: { routesByIdMap: Map<string, Route
|
||||
{hasEmptyMatchers(pathRoute) ? (
|
||||
<div className={styles.textMuted}>No matchers</div>
|
||||
) : (
|
||||
<Matchers matchers={pathRoute.object_matchers ?? []} />
|
||||
<Tooltip
|
||||
placement="bottom"
|
||||
content={
|
||||
<LabelsMatching
|
||||
routeId={pathRoute.id}
|
||||
matchingMap={matchingMap}
|
||||
matchingMapPath={matchingMapPath}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Matchers matchers={pathRoute.object_matchers ?? []} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@ -46,6 +94,8 @@ interface NotificationRouteDetailsModalProps {
|
||||
receiver: Receiver;
|
||||
routesByIdMap: Map<string, RouteWithPath>;
|
||||
alertManagerSourceName: string;
|
||||
matchingMap: Map<string, AlertInstanceMatch[]>;
|
||||
matchingMapPath: Map<string, AlertInstanceMatch[]>;
|
||||
}
|
||||
|
||||
export function NotificationRouteDetailsModal({
|
||||
@ -54,6 +104,8 @@ export function NotificationRouteDetailsModal({
|
||||
receiver,
|
||||
routesByIdMap,
|
||||
alertManagerSourceName,
|
||||
matchingMap,
|
||||
matchingMapPath,
|
||||
}: NotificationRouteDetailsModalProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const isDefault = isDefaultPolicy(route);
|
||||
@ -84,7 +136,12 @@ export function NotificationRouteDetailsModal({
|
||||
{!isDefault && (
|
||||
<>
|
||||
<div className={cx(styles.textMuted, styles.marginBottom(1))}>Notification policy path</div>
|
||||
<PolicyPath route={route} routesByIdMap={routesByIdMap} />
|
||||
<PolicyPath
|
||||
route={route}
|
||||
routesByIdMap={routesByIdMap}
|
||||
matchingMap={matchingMap}
|
||||
matchingMapPath={matchingMapPath}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div className={styles.separator(4)} />
|
||||
|
@ -49,7 +49,10 @@ export const useAlertmanagerNotificationRoutingPreview = (
|
||||
|
||||
// match labels in the tree => map of notification policies and the alert instances (list of labels) in each one
|
||||
const {
|
||||
value: matchingMap = new Map<string, AlertInstanceMatch[]>(),
|
||||
value: matchingMap = {
|
||||
result: new Map<string, AlertInstanceMatch[]>(),
|
||||
resultPath: new Map<string, AlertInstanceMatch[]>(),
|
||||
},
|
||||
loading: matchingLoading,
|
||||
error: matchingError,
|
||||
} = useAsync(async () => {
|
||||
@ -62,7 +65,8 @@ export const useAlertmanagerNotificationRoutingPreview = (
|
||||
return {
|
||||
routesByIdMap,
|
||||
receiversByName,
|
||||
matchingMap: matchingMap,
|
||||
matchingMap: matchingMap.result,
|
||||
matchingMapPath: matchingMap.resultPath,
|
||||
loading: configLoading || matchingLoading,
|
||||
error: configError ?? matchingError,
|
||||
};
|
||||
|
@ -25,15 +25,23 @@ export const routeGroupsMatcher = {
|
||||
return routeGroupsMap;
|
||||
},
|
||||
|
||||
matchInstancesToRoute(routeTree: RouteWithID, instancesToMatch: Labels[]): Map<string, AlertInstanceMatch[]> {
|
||||
matchInstancesToRoute(
|
||||
routeTree: RouteWithID,
|
||||
instancesToMatch: Labels[]
|
||||
): { result: Map<string, AlertInstanceMatch[]>; resultPath: Map<string, AlertInstanceMatch[]> } {
|
||||
const result = new Map<string, AlertInstanceMatch[]>();
|
||||
const resultPath = new Map<string, AlertInstanceMatch[]>();
|
||||
|
||||
const normalizedRootRoute = normalizeRoute(routeTree);
|
||||
|
||||
// find matching routes for each instance and add them to the results map and the path map
|
||||
instancesToMatch.forEach((instance) => {
|
||||
const matchingRoutes = findMatchingRoutes(normalizedRootRoute, Object.entries(instance));
|
||||
const { matchesResult: matchingRoutes, matchesPath } = findMatchingRoutes(
|
||||
normalizedRootRoute,
|
||||
Object.entries(instance)
|
||||
);
|
||||
// Only to convert Label[] to Labels[] - needs better approach
|
||||
matchingRoutes.forEach(({ route, details, labelsMatch }) => {
|
||||
// Only to convert Label[] to Labels[] - needs better approach
|
||||
const matchDetails = new Map(
|
||||
Array.from(details.entries()).map(([matcher, labels]) => [matcher, Object.fromEntries(labels)])
|
||||
);
|
||||
@ -45,9 +53,21 @@ export const routeGroupsMatcher = {
|
||||
result.set(route.id, [{ instance, matchDetails, labelsMatch }]);
|
||||
}
|
||||
});
|
||||
matchesPath.forEach(({ route: routeInPath, details, labelsMatch }) => {
|
||||
const matchDetailsPath = new Map(
|
||||
Array.from(details.entries()).map(([matcher, labels]) => [matcher, Object.fromEntries(labels)])
|
||||
);
|
||||
|
||||
const currentRouteInpath = resultPath.get(routeInPath.id);
|
||||
if (currentRouteInpath) {
|
||||
currentRouteInpath.push({ instance, matchDetails: matchDetailsPath, labelsMatch });
|
||||
} else {
|
||||
resultPath.set(routeInPath.id, [{ instance, matchDetails: matchDetailsPath, labelsMatch }]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
return { result: result, resultPath: resultPath };
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -98,7 +98,7 @@ export function useRouteGroupsMatcher() {
|
||||
|
||||
const startTime = performance.now();
|
||||
|
||||
const result = await routeMatcher.matchInstancesToRoute(rootRoute, instancesToMatch);
|
||||
const { result, resultPath } = await routeMatcher.matchInstancesToRoute(rootRoute, instancesToMatch);
|
||||
|
||||
const timeSpent = performance.now() - startTime;
|
||||
|
||||
@ -108,8 +108,7 @@ export function useRouteGroupsMatcher() {
|
||||
// Counting all nested routes might be too time-consuming, so we only count the first level
|
||||
topLevelRoutesCount: rootRoute.routes?.length.toString() ?? '0',
|
||||
});
|
||||
|
||||
return result;
|
||||
return { result, resultPath };
|
||||
},
|
||||
[workerPreviewEnabled]
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { MatcherOperator, Route, RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
||||
|
||||
import { findMatchingRoutes, normalizeRoute, getInheritedProperties } from './notification-policies';
|
||||
import { findMatchingRoutes, getInheritedProperties, normalizeRoute } from './notification-policies';
|
||||
|
||||
import 'core-js/stable/structured-clone';
|
||||
|
||||
@ -39,19 +39,19 @@ describe('findMatchingRoutes', () => {
|
||||
};
|
||||
|
||||
it('should match root route with no matching labels', () => {
|
||||
const matches = findMatchingRoutes(policies, []);
|
||||
const { matchesResult: matches } = findMatchingRoutes(policies, []);
|
||||
expect(matches).toHaveLength(1);
|
||||
expect(matches[0].route).toHaveProperty('receiver', 'ROOT');
|
||||
});
|
||||
|
||||
it('should match parent route with no matching children', () => {
|
||||
const matches = findMatchingRoutes(policies, [['team', 'operations']]);
|
||||
const { matchesResult: matches } = findMatchingRoutes(policies, [['team', 'operations']]);
|
||||
expect(matches).toHaveLength(1);
|
||||
expect(matches[0].route).toHaveProperty('receiver', 'A');
|
||||
});
|
||||
|
||||
it('should match child route of matching parent', () => {
|
||||
const matches = findMatchingRoutes(policies, [
|
||||
const { matchesResult: matches } = findMatchingRoutes(policies, [
|
||||
['team', 'operations'],
|
||||
['region', 'europe'],
|
||||
]);
|
||||
@ -60,7 +60,7 @@ describe('findMatchingRoutes', () => {
|
||||
});
|
||||
|
||||
it('should match simple policy', () => {
|
||||
const matches = findMatchingRoutes(policies, [['foo', 'bar']]);
|
||||
const { matchesResult: matches } = findMatchingRoutes(policies, [['foo', 'bar']]);
|
||||
expect(matches).toHaveLength(1);
|
||||
expect(matches[0].route).toHaveProperty('receiver', 'C');
|
||||
});
|
||||
@ -71,7 +71,7 @@ describe('findMatchingRoutes', () => {
|
||||
routes: [CATCH_ALL_ROUTE, ...(policies.routes ?? [])],
|
||||
};
|
||||
|
||||
const matches = findMatchingRoutes(policiesWithAll, []);
|
||||
const { matchesResult: matches } = findMatchingRoutes(policiesWithAll, []);
|
||||
expect(matches).toHaveLength(1);
|
||||
expect(matches[0].route).toHaveProperty('receiver', 'ALL');
|
||||
});
|
||||
@ -88,7 +88,7 @@ describe('findMatchingRoutes', () => {
|
||||
],
|
||||
};
|
||||
|
||||
const matches = findMatchingRoutes(policiesWithAll, [['foo', 'bar']]);
|
||||
const { matchesResult: matches } = findMatchingRoutes(policiesWithAll, [['foo', 'bar']]);
|
||||
expect(matches).toHaveLength(2);
|
||||
expect(matches[0].route).toHaveProperty('receiver', 'ALL');
|
||||
expect(matches[1].route).toHaveProperty('receiver', 'C');
|
||||
@ -115,7 +115,7 @@ describe('findMatchingRoutes', () => {
|
||||
group_interval: '1m',
|
||||
};
|
||||
|
||||
const matches = findMatchingRoutes(policies, [['foo', 'bar']]);
|
||||
const { matchesResult: matches } = findMatchingRoutes(policies, [['foo', 'bar']]);
|
||||
expect(matches).toHaveLength(1);
|
||||
expect(matches[0].route).toHaveProperty('receiver', 'PARENT');
|
||||
});
|
||||
|
@ -37,7 +37,7 @@ function isLabelMatch(matcher: ObjectMatcher, label: Label) {
|
||||
return matchFunction(labelValue, matcherValue);
|
||||
}
|
||||
|
||||
interface LabelMatchResult {
|
||||
export interface LabelMatchResult {
|
||||
match: boolean;
|
||||
matchers: ObjectMatcher[];
|
||||
}
|
||||
@ -99,36 +99,60 @@ export interface RouteMatchResult<T extends Route> {
|
||||
// If the current node is not a match, return nothing
|
||||
// const normalizedMatchers = normalizeMatchers(root);
|
||||
// Normalization should have happened earlier in the code
|
||||
function findMatchingRoutes<T extends Route>(root: T, labels: Label[]): Array<RouteMatchResult<T>> {
|
||||
let matches: Array<RouteMatchResult<T>> = [];
|
||||
function findMatchingRoutes<T extends Route>(
|
||||
mainRoot: T,
|
||||
labels: Label[]
|
||||
): { matchesResult: Array<RouteMatchResult<T>>; matchesPath: Array<RouteMatchResult<T>> } {
|
||||
// ----------- recursive function to find matching routes
|
||||
function findMatchingRoutesRecursive<T extends Route>(
|
||||
root: T | undefined,
|
||||
labels: Label[],
|
||||
matchesPathAcum: Array<RouteMatchResult<T>>
|
||||
): { matchesResult: Array<RouteMatchResult<T>>; matchesPath: Array<RouteMatchResult<T>> } {
|
||||
let matches: Array<RouteMatchResult<T>> = [];
|
||||
if (!root) {
|
||||
return { matchesResult: [], matchesPath: matchesPathAcum };
|
||||
}
|
||||
// If the current node is not a match, return nothing
|
||||
const matchResult: MatchingResult = matchLabels(root.object_matchers ?? [], labels);
|
||||
if (!matchResult.matches) {
|
||||
return { matchesResult: [], matchesPath: matchesPathAcum };
|
||||
}
|
||||
// If the current node matches, add current match to the path results and continue with the children
|
||||
matchesPathAcum.push({ route: root, details: matchResult.details, labelsMatch: matchResult.labelsMatch });
|
||||
if (root.routes) {
|
||||
for (let index = 0; index < root.routes.length; index++) {
|
||||
let child = root.routes?.[index];
|
||||
let { matchesResult: matchingChildren, matchesPath: matchesPathInChild } = findMatchingRoutesRecursive(
|
||||
child,
|
||||
labels,
|
||||
matchesPathAcum
|
||||
);
|
||||
// TODO how do I solve this typescript thingy? It looks correct to me /shrug
|
||||
// @ts-ignore
|
||||
matches = matches.concat(matchingChildren);
|
||||
// @ts-ignore
|
||||
matchingChildren.length && matchesPathAcum.concat(matchesPathInChild);
|
||||
|
||||
// If the current node is not a match, return nothing
|
||||
const matchResult = matchLabels(root.object_matchers ?? [], labels);
|
||||
if (!matchResult.matches) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// If the current node matches, recurse through child nodes
|
||||
if (root.routes) {
|
||||
for (let index = 0; index < root.routes.length; index++) {
|
||||
let child = root.routes[index];
|
||||
let matchingChildren = findMatchingRoutes(child, labels);
|
||||
// TODO how do I solve this typescript thingy? It looks correct to me /shrug
|
||||
// @ts-ignore
|
||||
matches = matches.concat(matchingChildren);
|
||||
// we have matching children and we don't want to continue, so break here
|
||||
if (matchingChildren.length && !child.continue) {
|
||||
break;
|
||||
// we have matching children and we don't want to continue, so break here
|
||||
if (matchingChildren.length && !child?.continue) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no child nodes were matches, the current node itself is a match.
|
||||
if (matches.length === 0) {
|
||||
matches.push({ route: root, details: matchResult.details, labelsMatch: matchResult.labelsMatch });
|
||||
}
|
||||
// If no child nodes were matches, the current node itself is a match.
|
||||
if (matches.length === 0) {
|
||||
matches.push({ route: root, details: matchResult.details, labelsMatch: matchResult.labelsMatch });
|
||||
}
|
||||
|
||||
return matches;
|
||||
const matchesResultUnique = [
|
||||
...new Map(matches.map((matchInstance) => [JSON.stringify(matchInstance), matchInstance])).values(),
|
||||
];
|
||||
return { matchesResult: matchesResultUnique, matchesPath: matchesPathAcum };
|
||||
}
|
||||
// ------------ call to the recursive function
|
||||
return findMatchingRoutesRecursive(mainRoot, labels, []);
|
||||
}
|
||||
|
||||
// This is a performance improvement to normalize matchers only once and use the normalized version later on
|
||||
@ -162,7 +186,8 @@ function findMatchingAlertGroups(
|
||||
// find matching alerts in the current group
|
||||
const matchingAlerts = group.alerts.filter((alert) => {
|
||||
const labels = Object.entries(alert.labels);
|
||||
return findMatchingRoutes(routeTree, labels).some((matchingRoute) => matchingRoute.route === route);
|
||||
const { matchesResult } = findMatchingRoutes(routeTree, labels);
|
||||
return matchesResult.some((matchingRoute) => matchingRoute.route === route);
|
||||
});
|
||||
|
||||
// if the groups has any alerts left after matching, add it to the results
|
||||
|
Loading…
Reference in New Issue
Block a user