mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Implement Alertmanagers discovery page
Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
parent
87a22500e1
commit
9e4ffd044c
|
@ -20,6 +20,7 @@ import {
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { useDisclosure } from "@mantine/hooks";
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
import {
|
import {
|
||||||
|
IconBell,
|
||||||
IconBellFilled,
|
IconBellFilled,
|
||||||
IconChevronDown,
|
IconChevronDown,
|
||||||
IconChevronRight,
|
IconChevronRight,
|
||||||
|
@ -62,6 +63,7 @@ import ReadinessWrapper from "./components/ReadinessWrapper";
|
||||||
import { QueryParamProvider } from "use-query-params";
|
import { QueryParamProvider } from "use-query-params";
|
||||||
import { ReactRouter6Adapter } from "use-query-params/adapters/react-router-6";
|
import { ReactRouter6Adapter } from "use-query-params/adapters/react-router-6";
|
||||||
import ServiceDiscoveryPage from "./pages/service-discovery/ServiceDiscoveryPage";
|
import ServiceDiscoveryPage from "./pages/service-discovery/ServiceDiscoveryPage";
|
||||||
|
import AlertmanagerDiscoveryPage from "./pages/AlertmanagerDiscoveryPage";
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
|
@ -106,6 +108,13 @@ const monitoringStatusPages = [
|
||||||
element: <ServiceDiscoveryPage />,
|
element: <ServiceDiscoveryPage />,
|
||||||
inAgentMode: true,
|
inAgentMode: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Alertmanager discovery",
|
||||||
|
path: "/discovered-alertmanagers",
|
||||||
|
icon: <IconBell style={navIconStyle} />,
|
||||||
|
element: <AlertmanagerDiscoveryPage />,
|
||||||
|
inAgentMode: false,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const serverStatusPages = [
|
const serverStatusPages = [
|
||||||
|
|
10
web/ui/mantine-ui/src/api/responseTypes/alertmanagers.ts
Normal file
10
web/ui/mantine-ui/src/api/responseTypes/alertmanagers.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
export type AlertmanagerTarget = {
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Result type for /api/v1/alertmanagers endpoint.
|
||||||
|
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#alertmanagers
|
||||||
|
export type AlertmanagersResult = {
|
||||||
|
activeAlertmanagers: AlertmanagerTarget[];
|
||||||
|
droppedAlertmanagers: AlertmanagerTarget[];
|
||||||
|
};
|
115
web/ui/mantine-ui/src/pages/AlertmanagerDiscoveryPage.tsx
Normal file
115
web/ui/mantine-ui/src/pages/AlertmanagerDiscoveryPage.tsx
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
import {
|
||||||
|
ActionIcon,
|
||||||
|
Alert,
|
||||||
|
Box,
|
||||||
|
Card,
|
||||||
|
Group,
|
||||||
|
Select,
|
||||||
|
Skeleton,
|
||||||
|
Stack,
|
||||||
|
Table,
|
||||||
|
Text,
|
||||||
|
} from "@mantine/core";
|
||||||
|
import {
|
||||||
|
IconBell,
|
||||||
|
IconBellOff,
|
||||||
|
IconInfoCircle,
|
||||||
|
IconLayoutNavbarCollapse,
|
||||||
|
IconLayoutNavbarExpand,
|
||||||
|
IconSearch,
|
||||||
|
} from "@tabler/icons-react";
|
||||||
|
import { Suspense } from "react";
|
||||||
|
import { useAppDispatch, useAppSelector } from "../state/hooks";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ArrayParam,
|
||||||
|
StringParam,
|
||||||
|
useQueryParam,
|
||||||
|
withDefault,
|
||||||
|
} from "use-query-params";
|
||||||
|
import ErrorBoundary from "../components/ErrorBoundary";
|
||||||
|
import ScrapePoolList from "./ServiceDiscoveryPoolsList";
|
||||||
|
import { useSuspenseAPIQuery } from "../api/api";
|
||||||
|
import { ScrapePoolsResult } from "../api/responseTypes/scrapePools";
|
||||||
|
import {
|
||||||
|
setCollapsedPools,
|
||||||
|
setShowLimitAlert,
|
||||||
|
} from "../state/serviceDiscoveryPageSlice";
|
||||||
|
import { StateMultiSelect } from "../components/StateMultiSelect";
|
||||||
|
import badgeClasses from "../Badge.module.css";
|
||||||
|
import { AlertmanagersResult } from "../api/responseTypes/alertmanagers";
|
||||||
|
import EndpointLink from "../components/EndpointLink";
|
||||||
|
|
||||||
|
export const targetPoolDisplayLimit = 20;
|
||||||
|
|
||||||
|
export default function AlertmanagerDiscoveryPage() {
|
||||||
|
// Load the list of all available scrape pools.
|
||||||
|
const {
|
||||||
|
data: {
|
||||||
|
data: { activeAlertmanagers, droppedAlertmanagers },
|
||||||
|
},
|
||||||
|
} = useSuspenseAPIQuery<AlertmanagersResult>({
|
||||||
|
path: `/alertmanagers`,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack gap="lg" maw={1000} mx="auto" mt="xs">
|
||||||
|
<Card shadow="xs" withBorder p="md">
|
||||||
|
<Group wrap="nowrap" align="center" ml="xs" mb="sm" gap="xs">
|
||||||
|
<IconBell size={22} />
|
||||||
|
<Text fz="xl" fw={600}>
|
||||||
|
Active Alertmanagers
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
{activeAlertmanagers.length === 0 ? (
|
||||||
|
<Alert title="No active alertmanagers" icon={<IconInfoCircle />}>
|
||||||
|
No active alertmanagers found.
|
||||||
|
</Alert>
|
||||||
|
) : (
|
||||||
|
<Table layout="fixed">
|
||||||
|
<Table.Tbody>
|
||||||
|
{activeAlertmanagers.map((alertmanager) => (
|
||||||
|
<Table.Tr key={alertmanager.url}>
|
||||||
|
<Table.Td>
|
||||||
|
<EndpointLink
|
||||||
|
endpoint={alertmanager.url}
|
||||||
|
globalUrl={alertmanager.url}
|
||||||
|
/>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
<Card shadow="xs" withBorder p="md">
|
||||||
|
<Group wrap="nowrap" align="center" ml="xs" mb="sm" gap="xs">
|
||||||
|
<IconBellOff size={22} />
|
||||||
|
<Text fz="xl" fw={600}>
|
||||||
|
Dropped Alertmanagers
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
{droppedAlertmanagers.length === 0 ? (
|
||||||
|
<Alert title="No dropped alertmanagers" icon={<IconInfoCircle />}>
|
||||||
|
No dropped alertmanagers found.
|
||||||
|
</Alert>
|
||||||
|
) : (
|
||||||
|
<Table layout="fixed">
|
||||||
|
<Table.Tbody>
|
||||||
|
{droppedAlertmanagers.map((alertmanager) => (
|
||||||
|
<Table.Tr key={alertmanager.url}>
|
||||||
|
<Table.Td>
|
||||||
|
<EndpointLink
|
||||||
|
endpoint={alertmanager.url}
|
||||||
|
globalUrl={alertmanager.url}
|
||||||
|
/>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
|
@ -25,7 +25,6 @@ import {
|
||||||
} from "../../state/serviceDiscoveryPageSlice";
|
} from "../../state/serviceDiscoveryPageSlice";
|
||||||
import CustomInfiniteScroll from "../../components/CustomInfiniteScroll";
|
import CustomInfiniteScroll from "../../components/CustomInfiniteScroll";
|
||||||
|
|
||||||
import TargetLabels from "./TargetLabels";
|
|
||||||
import { useDebouncedValue } from "@mantine/hooks";
|
import { useDebouncedValue } from "@mantine/hooks";
|
||||||
import { targetPoolDisplayLimit } from "./ServiceDiscoveryPage";
|
import { targetPoolDisplayLimit } from "./ServiceDiscoveryPage";
|
||||||
import { BooleanParam, useQueryParam, withDefault } from "use-query-params";
|
import { BooleanParam, useQueryParam, withDefault } from "use-query-params";
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
import { FC } from "react";
|
|
||||||
import { Labels } from "../../api/responseTypes/targets";
|
|
||||||
import { LabelBadges } from "../../components/LabelBadges";
|
|
||||||
import { ActionIcon, Collapse, Group, Stack, Text } from "@mantine/core";
|
|
||||||
import { useDisclosure } from "@mantine/hooks";
|
|
||||||
import { IconChevronDown, IconChevronUp } from "@tabler/icons-react";
|
|
||||||
|
|
||||||
type TargetLabelsProps = {
|
|
||||||
labels: Labels;
|
|
||||||
discoveredLabels: Labels;
|
|
||||||
};
|
|
||||||
|
|
||||||
const TargetLabels: FC<TargetLabelsProps> = ({ discoveredLabels, labels }) => {
|
|
||||||
const [showDiscovered, { toggle: toggleDiscovered }] = useDisclosure(false);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Stack my={showDiscovered ? "sm" : undefined}>
|
|
||||||
<Group wrap="nowrap" align="flex-start">
|
|
||||||
<LabelBadges labels={labels} />
|
|
||||||
|
|
||||||
<ActionIcon
|
|
||||||
size="xs"
|
|
||||||
color="gray"
|
|
||||||
variant="light"
|
|
||||||
onClick={toggleDiscovered}
|
|
||||||
title={`${showDiscovered ? "Hide" : "Show"} discovered (pre-relabeling) labels`}
|
|
||||||
>
|
|
||||||
{showDiscovered ? (
|
|
||||||
<IconChevronUp
|
|
||||||
style={{ width: "70%", height: "70%" }}
|
|
||||||
stroke={1.5}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<IconChevronDown style={{ width: "70%", height: "70%" }} />
|
|
||||||
)}
|
|
||||||
</ActionIcon>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
<Collapse in={showDiscovered}>
|
|
||||||
<Text fw={700} size="1em" my="lg" c="gray.7">
|
|
||||||
Discovered labels:
|
|
||||||
</Text>
|
|
||||||
<LabelBadges color="blue" labels={discoveredLabels} />
|
|
||||||
</Collapse>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TargetLabels;
|
|
Loading…
Reference in a new issue