mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-09 23:24:05 -08:00
Implement initial time check and fetching of metric names
Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
parent
33a753c2f8
commit
d2f913ac1e
|
@ -108,12 +108,14 @@ export class HistoryCompleteStrategy implements CompleteStrategy {
|
|||
|
||||
interface ExpressionInputProps {
|
||||
initialExpr: string;
|
||||
metricNames: string[];
|
||||
executeQuery: (expr: string) => void;
|
||||
removePanel: () => void;
|
||||
}
|
||||
|
||||
const ExpressionInput: FC<ExpressionInputProps> = ({
|
||||
initialExpr,
|
||||
metricNames,
|
||||
executeQuery,
|
||||
removePanel,
|
||||
}) => {
|
||||
|
@ -175,13 +177,13 @@ const ExpressionInput: FC<ExpressionInputProps> = ({
|
|||
newCompleteStrategy({
|
||||
remote: {
|
||||
url: pathPrefix,
|
||||
//cache: { initialMetricList: metricNames },
|
||||
cache: { initialMetricList: metricNames },
|
||||
},
|
||||
}),
|
||||
queryHistory
|
||||
),
|
||||
});
|
||||
}, []); // TODO: Make this depend on external settings changes, maybe use dynamic config compartment again.
|
||||
}, [metricNames, enableAutocomplete, enableLinter, queryHistory]); // TODO: Make this depend on external settings changes, maybe use dynamic config compartment again.
|
||||
|
||||
return (
|
||||
<Group align="flex-start" wrap="nowrap" gap="xs">
|
||||
|
|
|
@ -1,18 +1,101 @@
|
|||
import { Button, Stack } from "@mantine/core";
|
||||
import { IconPlus } from "@tabler/icons-react";
|
||||
import { Alert, Button, Notification, Stack, rem } from "@mantine/core";
|
||||
import {
|
||||
IconAlertCircle,
|
||||
IconAlertTriangle,
|
||||
IconPlus,
|
||||
IconX,
|
||||
} from "@tabler/icons-react";
|
||||
import { useAppDispatch, useAppSelector } from "../../state/hooks";
|
||||
import { addPanel } from "../../state/queryPageSlice";
|
||||
import Panel from "./QueryPanel";
|
||||
import { LabelValuesResult } from "../../api/responseTypes/labelValues";
|
||||
import { useAPIQuery } from "../../api/api";
|
||||
import { useEffect, useState } from "react";
|
||||
import { InstantQueryResult } from "../../api/responseTypes/query";
|
||||
import { humanizeDuration } from "../../lib/formatTime";
|
||||
|
||||
export default function QueryPage() {
|
||||
const panels = useAppSelector((state) => state.queryPage.panels);
|
||||
const dispatch = useAppDispatch();
|
||||
const [timeDelta, setTimeDelta] = useState(0);
|
||||
|
||||
const { data: metricNamesResult, error: metricNamesError } =
|
||||
useAPIQuery<LabelValuesResult>({
|
||||
path: "/label/__name__/values",
|
||||
});
|
||||
|
||||
const { data: timeResult, error: timeError } =
|
||||
useAPIQuery<InstantQueryResult>({
|
||||
path: "/query",
|
||||
params: {
|
||||
query: "time()",
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (timeResult) {
|
||||
if (timeResult.data.resultType !== "scalar") {
|
||||
throw new Error("Unexpected result type from time query");
|
||||
}
|
||||
|
||||
const browserTime = new Date().getTime() / 1000;
|
||||
const serverTime = timeResult.data.result[0];
|
||||
console.log(browserTime, serverTime, Math.abs(browserTime - serverTime));
|
||||
setTimeDelta(Math.abs(browserTime - serverTime));
|
||||
}
|
||||
}, [timeResult]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack gap="sm">
|
||||
{metricNamesError && (
|
||||
<Alert
|
||||
icon={
|
||||
<IconAlertTriangle style={{ width: rem(14), height: rem(14) }} />
|
||||
}
|
||||
color="red"
|
||||
title="Error fetching metrics list"
|
||||
withCloseButton
|
||||
>
|
||||
Unable to fetch list of metric names: {metricNamesError.message}
|
||||
</Alert>
|
||||
)}
|
||||
{timeError && (
|
||||
<Alert
|
||||
icon={
|
||||
<IconAlertTriangle style={{ width: rem(14), height: rem(14) }} />
|
||||
}
|
||||
color="red"
|
||||
title="Error fetching server time"
|
||||
withCloseButton
|
||||
>
|
||||
{timeError.message}
|
||||
</Alert>
|
||||
)}
|
||||
{timeDelta > 30 && (
|
||||
<Alert
|
||||
title="Server time is out of sync"
|
||||
color="red"
|
||||
icon={
|
||||
<IconAlertCircle style={{ width: rem(14), height: rem(14) }} />
|
||||
}
|
||||
onClose={() => setTimeDelta(0)}
|
||||
>
|
||||
Detected a time difference of{" "}
|
||||
<strong>{humanizeDuration(timeDelta * 1000)}</strong> between your
|
||||
browser and the server. You may see unexpected time-shifted query
|
||||
results due to the time drift.
|
||||
</Alert>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
<Stack gap="xl">
|
||||
{panels.map((p, idx) => (
|
||||
<Panel key={p.id} idx={idx} />
|
||||
<Panel
|
||||
key={p.id}
|
||||
idx={idx}
|
||||
metricNames={metricNamesResult?.data || []}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
|
||||
|
|
|
@ -30,12 +30,13 @@ import ExpressionInput from "./ExpressionInput";
|
|||
|
||||
export interface PanelProps {
|
||||
idx: number;
|
||||
metricNames: string[];
|
||||
}
|
||||
|
||||
// TODO: This is duplicated everywhere, unify it.
|
||||
const iconStyle = { width: "0.9rem", height: "0.9rem" };
|
||||
|
||||
const QueryPanel: FC<PanelProps> = ({ idx }) => {
|
||||
const QueryPanel: FC<PanelProps> = ({ idx, metricNames }) => {
|
||||
// Used to indicate to the selected display component that it should retrigger
|
||||
// the query, even if the expression has not changed (e.g. when the user presses
|
||||
// the "Execute" button or hits <Enter> again).
|
||||
|
@ -48,6 +49,7 @@ const QueryPanel: FC<PanelProps> = ({ idx }) => {
|
|||
<Stack gap="lg" mt="sm">
|
||||
<ExpressionInput
|
||||
initialExpr={panel.expr}
|
||||
metricNames={metricNames}
|
||||
executeQuery={(expr: string) => {
|
||||
setRetriggerIdx((idx) => idx + 1);
|
||||
dispatch(setExpr({ idx, expr }));
|
||||
|
|
Loading…
Reference in a new issue