From b0b02673aa15388b76861277e57ada259ca0b94b Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 31 Jul 2026 20:52:35 +0800 Subject: [PATCH] fix: add DNS monitor support to global metrics pipeline (and update dashboard) (#2515) * fix: add DNS monitor support to global metrics pipeline DNS monitors were not displaying metrics (last checked, p50, p90, p95) on the /monitors page because they were excluded from the global metrics queries. Changes: - Created endpoint__dns_metrics_global_1d__v0.pipe for DNS global metrics - Added dnsGlobalMetricsDaily method to tinybird client - Updated getGlobalMetricsProcedure to handle DNS type - Updated monitors list client to query and display DNS metrics Fixes DNS monitors showing '-' and 'n/a' for all metric columns. * refactor: use useQueries for cleaner monitor metrics fetching Replaced three separate useQuery calls with a single useQueries call to reduce code duplication while maintaining the same functionality. * fix: add missing useQueries import * ci: apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../(dashboard)/monitors/(list)/client.tsx | 71 +++++++++++++------ packages/api/src/router/tinybird/index.ts | 5 +- .../endpoint__dns_metrics_global_1d__v0.pipe | 26 +++++++ packages/tinybird/src/client.ts | 22 ++++++ 4 files changed, 101 insertions(+), 23 deletions(-) create mode 100644 packages/tinybird/endpoints/endpoint__dns_metrics_global_1d__v0.pipe diff --git a/apps/dashboard/src/app/(dashboard)/monitors/(list)/client.tsx b/apps/dashboard/src/app/(dashboard)/monitors/(list)/client.tsx index 87086116..af68ed68 100644 --- a/apps/dashboard/src/app/(dashboard)/monitors/(list)/client.tsx +++ b/apps/dashboard/src/app/(dashboard)/monitors/(list)/client.tsx @@ -1,7 +1,7 @@ "use client"; import { ArrowDown, Success, ListFilter } from "@openstatus/icons"; -import { useQuery } from "@tanstack/react-query"; +import { useQueries, useQuery } from "@tanstack/react-query"; import type { ColumnFiltersState, SortingState } from "@tanstack/react-table"; import { useQueryStates } from "nuqs"; import { useEffect, useState } from "react"; @@ -59,24 +59,45 @@ export function Client() { monitors ?.filter((m) => m.jobType === "tcp") .map((m) => m.id.toString()) ?? [], + dns: + monitors + ?.filter((m) => m.jobType === "dns") + .map((m) => m.id.toString()) ?? [], }; - const { http: httpMonitors, tcp: tcpMonitors } = monitorsByType; + const { + http: httpMonitors, + tcp: tcpMonitors, + dns: dnsMonitors, + } = monitorsByType; - // HMM: why do we need two queries? - const { data: globalHttpMetrics, isLoading: isLoadingHttp } = useQuery({ - ...trpc.tinybird.globalMetrics.queryOptions({ - monitorIds: httpMonitors, - type: "http", - }), - enabled: httpMonitors.length > 0, - }); - - const { data: globalTcpMetrics, isLoading: isLoadingTcp } = useQuery({ - ...trpc.tinybird.globalMetrics.queryOptions({ - monitorIds: tcpMonitors, - type: "tcp", - }), - enabled: tcpMonitors.length > 0, + const [ + { data: globalHttpMetrics, isLoading: isLoadingHttp }, + { data: globalTcpMetrics, isLoading: isLoadingTcp }, + { data: globalDnsMetrics, isLoading: isLoadingDns }, + ] = useQueries({ + queries: [ + { + ...trpc.tinybird.globalMetrics.queryOptions({ + monitorIds: httpMonitors, + type: "http", + }), + enabled: httpMonitors.length > 0, + }, + { + ...trpc.tinybird.globalMetrics.queryOptions({ + monitorIds: tcpMonitors, + type: "tcp", + }), + enabled: tcpMonitors.length > 0, + }, + { + ...trpc.tinybird.globalMetrics.queryOptions({ + monitorIds: dnsMonitors, + type: "dns", + }), + enabled: dnsMonitors.length > 0, + }, + ], }); // TODO: ideally we read from the searchParamsCache and there is no layout shift @@ -95,6 +116,7 @@ export function Client() { const metrics = getMonitorListMetrics(monitors, [ ...(globalHttpMetrics?.data ?? []), ...(globalTcpMetrics?.data ?? []), + ...(globalDnsMetrics?.data ?? []), ]); return ( @@ -152,7 +174,8 @@ export function Client() { - {metric.key === "p95" && (isLoadingHttp || isLoadingTcp) ? ( + {metric.key === "p95" && + (isLoadingHttp || isLoadingTcp || isLoadingDns) ? ( ) : ( {metric.value} @@ -168,15 +191,19 @@ export function Client() { data={monitors.map((monitor) => ({ ...monitor, globalMetrics: - isLoadingHttp || isLoadingTcp + isLoadingHttp || isLoadingTcp || isLoadingDns ? undefined : monitor.jobType === "http" ? (globalHttpMetrics?.data?.find( (m) => m.monitorId === monitor.id.toString(), ) ?? false) - : (globalTcpMetrics?.data?.find( - (m) => m.monitorId === monitor.id.toString(), - ) ?? false), + : monitor.jobType === "tcp" + ? (globalTcpMetrics?.data?.find( + (m) => m.monitorId === monitor.id.toString(), + ) ?? false) + : (globalDnsMetrics?.data?.find( + (m) => m.monitorId === monitor.id.toString(), + ) ?? false), }))} actionBar={MonitorDataTableActionBar} toolbarComponent={(props) => ( diff --git a/packages/api/src/router/tinybird/index.ts b/packages/api/src/router/tinybird/index.ts index 39788c30..9f939c7f 100644 --- a/packages/api/src/router/tinybird/index.ts +++ b/packages/api/src/router/tinybird/index.ts @@ -164,7 +164,10 @@ export function getGetProcedure(period: "14d", type: Type) { } export function getGlobalMetricsProcedure(type: Type) { - return type === "http" ? tb.httpGlobalMetricsDaily : tb.tcpGlobalMetricsDaily; + if (type === "http") return tb.httpGlobalMetricsDaily; + if (type === "tcp") return tb.tcpGlobalMetricsDaily; + if (type === "dns") return tb.dnsGlobalMetricsDaily; + throw new TRPCError({ code: "NOT_FOUND", message: "Invalid type" }); } export function getUptimeProcedure(period: "7d" | "30d" | "90d", type: Type) { diff --git a/packages/tinybird/endpoints/endpoint__dns_metrics_global_1d__v0.pipe b/packages/tinybird/endpoints/endpoint__dns_metrics_global_1d__v0.pipe new file mode 100644 index 00000000..70ede409 --- /dev/null +++ b/packages/tinybird/endpoints/endpoint__dns_metrics_global_1d__v0.pipe @@ -0,0 +1,26 @@ +VERSION 0 + +TAGS "dns" + +NODE endpoint +SQL > + + % + SELECT + round(min(latency), 0) as minLatency, + round(max(latency), 0) as maxLatency, + round(quantile(0.5)(latency), 0) as p50Latency, + round(quantile(0.75)(latency), 0) as p75Latency, + round(quantile(0.9)(latency), 0) as p90Latency, + round(quantile(0.95)(latency), 0) as p95Latency, + round(quantile(0.99)(latency), 0) as p99Latency, + max(cronTimestamp) as lastTimestamp, + count() as count, + toString(monitorId) as monitorId + FROM dns_response__v0 + WHERE monitorId IN {{ Array(monitorIds, 'String', '1') }} + AND timestamp >= toUnixTimestamp64Milli(toDateTime64(now() - INTERVAL 1 DAY, 3)) + GROUP BY monitorId + + +TYPE ENDPOINT diff --git a/packages/tinybird/src/client.ts b/packages/tinybird/src/client.ts index fa5bc996..1bff26fb 100644 --- a/packages/tinybird/src/client.ts +++ b/packages/tinybird/src/client.ts @@ -1390,6 +1390,28 @@ export class OSTinybird { }); } + public get dnsGlobalMetricsDaily() { + return this.tb.buildPipe({ + pipe: "endpoint__dns_metrics_global_1d__v0", + parameters: z.object({ + monitorIds: z.string().array(), + }), + data: z.object({ + minLatency: z.int(), + maxLatency: z.int(), + p50Latency: z.int(), + p75Latency: z.int(), + p90Latency: z.int(), + p95Latency: z.int(), + p99Latency: z.int(), + lastTimestamp: z.int(), + count: z.int(), + monitorId: z.coerce.string(), + }), + opts: { next: { revalidate: REVALIDATE } }, + }); + } + public get httpTimingPhases14d() { return this.tb.buildPipe({ pipe: "endpoint__http_timing_phases_14d__v1", -- 2.51.2