mirror of
https://github.com/prometheus/prometheus.git
synced 2025-08-06 14:17:12 +02:00
Fetch and display full query stats in hover tooltip in table query tab (#16723)
Fixes https://github.com/prometheus/prometheus/issues/5857 Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
parent
c9d638fd8f
commit
4eeeb6ee88
@ -23,9 +23,14 @@ export interface RangeSamples {
|
|||||||
export type SampleValue = [number, string];
|
export type SampleValue = [number, string];
|
||||||
export type SampleHistogram = [number, Histogram];
|
export type SampleHistogram = [number, Histogram];
|
||||||
|
|
||||||
|
export type QueryStats = {
|
||||||
|
timings: Record<string, number>;
|
||||||
|
samples: Record<string, number>;
|
||||||
|
};
|
||||||
|
|
||||||
// Result type for /api/v1/query endpoint.
|
// Result type for /api/v1/query endpoint.
|
||||||
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#instant-queries
|
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#instant-queries
|
||||||
export type InstantQueryResult =
|
export type InstantQueryResult = (
|
||||||
| {
|
| {
|
||||||
resultType: "vector";
|
resultType: "vector";
|
||||||
result: InstantSample[];
|
result: InstantSample[];
|
||||||
@ -41,11 +46,13 @@ export type InstantQueryResult =
|
|||||||
| {
|
| {
|
||||||
resultType: "string";
|
resultType: "string";
|
||||||
result: SampleValue;
|
result: SampleValue;
|
||||||
};
|
}
|
||||||
|
) & { stats?: QueryStats };
|
||||||
|
|
||||||
// Result type for /api/v1/query_range endpoint.
|
// Result type for /api/v1/query_range endpoint.
|
||||||
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries
|
// See: https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries
|
||||||
export type RangeQueryResult = {
|
export type RangeQueryResult = {
|
||||||
resultType: "matrix";
|
resultType: "matrix";
|
||||||
result: RangeSamples[];
|
result: RangeSamples[];
|
||||||
|
stats?: QueryStats;
|
||||||
};
|
};
|
||||||
|
49
web/ui/mantine-ui/src/pages/query/QueryStatsDisplay.tsx
Normal file
49
web/ui/mantine-ui/src/pages/query/QueryStatsDisplay.tsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { FC } from "react";
|
||||||
|
import { Box, Text, Tooltip, Table } from "@mantine/core";
|
||||||
|
import { QueryStats } from "../../api/responseTypes/query";
|
||||||
|
|
||||||
|
const statsTable = (stats: Record<string, number>) => {
|
||||||
|
return (
|
||||||
|
<Table withRowBorders={false}>
|
||||||
|
<Table.Tbody>
|
||||||
|
{Object.entries(stats).map(([k, v]) => (
|
||||||
|
<Table.Tr key={k}>
|
||||||
|
<Table.Td pl={0} py={3} c="dimmed">
|
||||||
|
{k}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td pr={0} py={3} ta="right">
|
||||||
|
{v}
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const QueryStatsDisplay: FC<{
|
||||||
|
numResults: number;
|
||||||
|
responseTime: number;
|
||||||
|
stats: QueryStats;
|
||||||
|
}> = ({ numResults, responseTime, stats }) => {
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
label={
|
||||||
|
<Box p="xs">
|
||||||
|
<Text mb="xs">Timing stats (s):</Text>
|
||||||
|
{statsTable(stats.timings)}
|
||||||
|
<Text mt="sm" mb="xs">
|
||||||
|
Sample stats:
|
||||||
|
</Text>
|
||||||
|
{statsTable(stats.samples)}
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Text size="xs" c="gray">
|
||||||
|
Load time: {responseTime}ms   Result series: {numResults}
|
||||||
|
</Text>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default QueryStatsDisplay;
|
@ -1,5 +1,5 @@
|
|||||||
import { FC, useEffect, useId, useLayoutEffect, useState } from "react";
|
import { FC, useEffect, useId, useLayoutEffect, useState } from "react";
|
||||||
import { Alert, Skeleton, Box, Group, Stack, Text } from "@mantine/core";
|
import { Alert, Skeleton, Box, Group, Stack } from "@mantine/core";
|
||||||
import { IconAlertTriangle, IconInfoCircle } from "@tabler/icons-react";
|
import { IconAlertTriangle, IconInfoCircle } from "@tabler/icons-react";
|
||||||
import { InstantQueryResult } from "../../api/responseTypes/query";
|
import { InstantQueryResult } from "../../api/responseTypes/query";
|
||||||
import { useAPIQuery } from "../../api/api";
|
import { useAPIQuery } from "../../api/api";
|
||||||
@ -9,6 +9,7 @@ import { useAppDispatch, useAppSelector } from "../../state/hooks";
|
|||||||
import { setVisualizer } from "../../state/queryPageSlice";
|
import { setVisualizer } from "../../state/queryPageSlice";
|
||||||
import TimeInput from "./TimeInput";
|
import TimeInput from "./TimeInput";
|
||||||
import DataTable from "./DataTable";
|
import DataTable from "./DataTable";
|
||||||
|
import QueryStatsDisplay from "./QueryStatsDisplay";
|
||||||
dayjs.extend(timezone);
|
dayjs.extend(timezone);
|
||||||
|
|
||||||
export interface TableTabProps {
|
export interface TableTabProps {
|
||||||
@ -34,6 +35,7 @@ const TableTab: FC<TableTabProps> = ({ panelIdx, retriggerIdx, expr }) => {
|
|||||||
params: {
|
params: {
|
||||||
query: expr,
|
query: expr,
|
||||||
time: `${(endTime !== null ? endTime : Date.now()) / 1000}`,
|
time: `${(endTime !== null ? endTime : Date.now()) / 1000}`,
|
||||||
|
stats: "true",
|
||||||
},
|
},
|
||||||
enabled: expr !== "",
|
enabled: expr !== "",
|
||||||
recordResponseTime: setResponseTime,
|
recordResponseTime: setResponseTime,
|
||||||
@ -66,10 +68,11 @@ const TableTab: FC<TableTabProps> = ({ panelIdx, retriggerIdx, expr }) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{!isFetching && data !== undefined && (
|
{!isFetching && data !== undefined && (
|
||||||
<Text size="xs" c="gray">
|
<QueryStatsDisplay
|
||||||
Load time: {responseTime}ms   Result series:{" "}
|
numResults={data.data.result.length}
|
||||||
{data.data.result.length}
|
responseTime={responseTime}
|
||||||
</Text>
|
stats={data.data.stats!}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
{isFetching ? (
|
{isFetching ? (
|
||||||
|
Loading…
Reference in New Issue
Block a user