diff --git a/metrics_handler.go b/metrics_handler.go index 18b2484..337f49c 100644 --- a/metrics_handler.go +++ b/metrics_handler.go @@ -23,7 +23,7 @@ func newGetMetricsHandlerFunc(client *http.Client) http.HandlerFunc { const ( baseAddr = "http://localhost:9090" apiPath = "/api/v1/query_range" - promQL = "asynq_tasks_enqueued_total" + promQL = "asynq_queue_size" ) var b strings.Builder v := url.Values{} diff --git a/ui/src/actions/metricsActions.ts b/ui/src/actions/metricsActions.ts index 7265f43..269cd66 100644 --- a/ui/src/actions/metricsActions.ts +++ b/ui/src/actions/metricsActions.ts @@ -32,7 +32,6 @@ export function getMetricsAsync() { dispatch({ type: GET_METRICS_BEGIN }); try { const response = await getMetrics(); - console.log("DEBUG: got metrics: ", response); dispatch({ type: GET_METRICS_SUCCESS, payload: response }); } catch (error) { console.error(`getMetricsAsync: ${toErrorStringWithHttpStatus(error)}`); diff --git a/ui/src/api.ts b/ui/src/api.ts index d3d9158..1a3cedc 100644 --- a/ui/src/api.ts +++ b/ui/src/api.ts @@ -86,7 +86,7 @@ export interface MetricsResult { export interface Metrics { metric: MetricsInfo; - values: [number, string]; // [unixtime, value] + values: [number, string][]; // [unixtime, value] } export interface MetricsInfo { diff --git a/ui/src/components/QueueSizeMetricsChart.tsx b/ui/src/components/QueueSizeMetricsChart.tsx new file mode 100644 index 0000000..248c6d4 --- /dev/null +++ b/ui/src/components/QueueSizeMetricsChart.tsx @@ -0,0 +1,84 @@ +import React from "react"; +import { + LineChart, + Line, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + Legend, + ResponsiveContainer, +} from "recharts"; +import { Metrics } from "../api"; + +interface Props { + data: Metrics[]; +} + +// interface that rechart understands. +interface ChartData { + timestamp: number; + [qname: string]: number; +} + +function toChartData(metrics: Metrics[]): ChartData[] { + if (metrics.length === 0) { + return []; + } + let byTimestamp: { [key: number]: ChartData } = {}; + for (let x of metrics) { + for (let [ts, val] of x.values) { + if (!byTimestamp[ts]) { + byTimestamp[ts] = { timestamp: ts }; + } + byTimestamp[ts][x.metric.queue] = parseFloat(val); + } + } + return Object.values(byTimestamp); +} + +const lineColors = [ + "#2085ec", + "#72b4eb", + "#0a417a", + "#8464a0", + "#cea9bc", + "#323232", +]; + +function QueueSizeMetricsChart(props: Props) { + console.log("DEBUG: QueueSizeMetricsChart props:", props); + console.log("DEBUG: chartData", toChartData(props.data)); + const data = toChartData(props.data); + const keys = props.data.map((x) => x.metric.queue); + return ( + + + + + new Date(timestamp * 1000).toLocaleTimeString() + } + /> + + { + return new Date(timestamp * 1000).toLocaleTimeString(); + }} + /> + + {keys.map((key, idx) => ( + + ))} + + + ); +} + +export default QueueSizeMetricsChart; diff --git a/ui/src/views/MetricsView.tsx b/ui/src/views/MetricsView.tsx index 4d8dca0..b9a1b7d 100644 --- a/ui/src/views/MetricsView.tsx +++ b/ui/src/views/MetricsView.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React from "react"; import { connect, ConnectedProps } from "react-redux"; import { makeStyles } from "@material-ui/core/styles"; import Container from "@material-ui/core/Container"; @@ -6,6 +6,8 @@ import Grid from "@material-ui/core/Grid"; import { getMetricsAsync } from "../actions/metricsActions"; import { AppState } from "../store"; import { usePolling } from "../hooks"; +import Typography from "@material-ui/core/Typography"; +import QueueSizeMetricsChart from "../components/QueueSizeMetricsChart"; const useStyles = makeStyles((theme) => ({ container: { @@ -28,7 +30,7 @@ type Props = ConnectedProps; function MetricsView(props: Props) { const classes = useStyles(); - const { pollInterval, getMetricsAsync } = props; + const { pollInterval, getMetricsAsync, data } = props; usePolling(getMetricsAsync, pollInterval); @@ -36,9 +38,14 @@ function MetricsView(props: Props) { - Hello Metrics + Queue Size + + + Queue Latency + TODO: Queue latency chart here + ); }