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",