mirror of
https://github.com/supabase/supabase.git
synced 2026-10-15 22:29:11 +03:00
single queries shown on click
This commit is contained in:
1 parent
f3aae471a5
commit
ed8a5ea11b
2 files changed
+106
-36
No files matched your search
@@ -15,6 +15,7 @@ import { useState } from 'react'
|
||||
import { useParams } from 'common'
|
||||
import { Button } from 'ui'
|
||||
import { MetricType } from '../QueryInsights'
|
||||
import { useSingleQueryLatency } from 'data/query-insights/single-query-latency-query'
|
||||
|
||||
interface MetricsChartProps {
|
||||
data: QueryInsightsMetric[]
|
||||
@@ -33,12 +34,22 @@ export function MetricsChart({
|
||||
endTime,
|
||||
selectedQuery,
|
||||
}: MetricsChartProps) {
|
||||
const { ref } = useParams()
|
||||
const [visibleMetrics, setVisibleMetrics] = useState({
|
||||
p50: true,
|
||||
p95: true,
|
||||
p99: true,
|
||||
p99_9: true,
|
||||
query_exec_time: true,
|
||||
query_latency: true,
|
||||
})
|
||||
|
||||
// Fetch single query latency data if a query is selected
|
||||
const {
|
||||
data: queryLatencyData,
|
||||
isLoading: isLoadingQueryLatency,
|
||||
error: queryLatencyError,
|
||||
} = useSingleQueryLatency(ref, selectedQuery?.query_id, startTime, endTime, {
|
||||
enabled: !!selectedQuery,
|
||||
})
|
||||
|
||||
if (isLoading) {
|
||||
@@ -67,8 +78,8 @@ export function MetricsChart({
|
||||
p95: point.p95,
|
||||
p99: point.p99,
|
||||
p99_9: point.p99_9,
|
||||
// Add a placeholder for the query execution time
|
||||
query_exec_time: null as unknown as number | undefined,
|
||||
// Initialize query latency as 0 instead of null
|
||||
query_latency: 0,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -77,26 +88,22 @@ export function MetricsChart({
|
||||
return dayjs(a.timestamp, 'HH:mm').diff(dayjs(b.timestamp, 'HH:mm'))
|
||||
})
|
||||
|
||||
// If we have a selected query, add its execution time as a consistent line
|
||||
if (selectedQuery) {
|
||||
// For visualizing the query, use its mean execution time as a flat line
|
||||
const queryExecTime = selectedQuery.mean_exec_time
|
||||
|
||||
// Log for debugging
|
||||
console.log(
|
||||
'Selected Query:',
|
||||
selectedQuery.query_id,
|
||||
selectedQuery.query.substring(0, 30) + '...'
|
||||
)
|
||||
console.log('Query Execution Time:', queryExecTime)
|
||||
|
||||
// Set the query execution time for all data points to create a flat line
|
||||
chartData.forEach((dataPoint) => {
|
||||
dataPoint.query_exec_time = queryExecTime
|
||||
// If we have query latency data, add it to the chart
|
||||
if (selectedQuery && queryLatencyData && queryLatencyData.length > 0) {
|
||||
// Create a map of timestamps to query latency values
|
||||
const queryLatencyMap = new Map<string, number>()
|
||||
queryLatencyData.forEach((point) => {
|
||||
const timestamp = dayjs(point.timestamp).format('HH:mm')
|
||||
queryLatencyMap.set(timestamp, point.value || 0)
|
||||
})
|
||||
|
||||
// Log the chart data for debugging
|
||||
console.log('Chart Data with Query:', chartData.slice(0, 2))
|
||||
// Add query latency data to each chart data point
|
||||
// Points without data will keep their 0 value
|
||||
chartData.forEach((point) => {
|
||||
if (queryLatencyMap.has(point.timestamp)) {
|
||||
point.query_latency = queryLatencyMap.get(point.timestamp)!
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const config = {
|
||||
@@ -116,9 +123,9 @@ export function MetricsChart({
|
||||
label: 'p99.9',
|
||||
color: 'hsl(var(--destructive-default))',
|
||||
},
|
||||
query_exec_time: {
|
||||
label: 'Query Execution Time',
|
||||
color: 'hsl(var(--red-500))',
|
||||
query_latency: {
|
||||
label: 'Query Latency',
|
||||
color: 'hsl(var(--foreground-default))',
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
@@ -138,14 +145,18 @@ export function MetricsChart({
|
||||
<span>
|
||||
Total Calls: <strong>{selectedQuery.calls.toLocaleString()}</strong>
|
||||
</span>
|
||||
{isLoadingQueryLatency && <span>Loading query latency data...</span>}
|
||||
{Boolean(queryLatencyError) && (
|
||||
<span className="text-red-500">Error loading query latency</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex gap-2 px-5">
|
||||
{Object.entries(config).map(([key, value]) => {
|
||||
// Only show query execution time button if we have a selected query
|
||||
if (key === 'query_exec_time' && !selectedQuery) {
|
||||
// Only show query latency button if we have a selected query
|
||||
if (key === 'query_latency' && !selectedQuery) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -216,8 +227,9 @@ export function MetricsChart({
|
||||
type="monotone"
|
||||
dataKey="p50"
|
||||
fill={config.p50.color}
|
||||
fillOpacity={selectedQuery ? 0.2 : 0.4}
|
||||
fillOpacity={selectedQuery ? 0.05 : 0.4}
|
||||
stroke={config.p50.color}
|
||||
strokeOpacity={selectedQuery ? 0.1 : 0.8}
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
animationDuration={100}
|
||||
@@ -228,8 +240,9 @@ export function MetricsChart({
|
||||
type="monotone"
|
||||
dataKey="p95"
|
||||
fill={config.p95.color}
|
||||
fillOpacity={selectedQuery ? 0.2 : 0.4}
|
||||
fillOpacity={selectedQuery ? 0.05 : 0.4}
|
||||
stroke={config.p95.color}
|
||||
strokeOpacity={selectedQuery ? 0.1 : 0.8}
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
animationDuration={100}
|
||||
@@ -240,8 +253,9 @@ export function MetricsChart({
|
||||
type="monotone"
|
||||
dataKey="p99"
|
||||
fill={config.p99.color}
|
||||
fillOpacity={selectedQuery ? 0.2 : 0.4}
|
||||
fillOpacity={selectedQuery ? 0.05 : 0.4}
|
||||
stroke={config.p99.color}
|
||||
strokeOpacity={selectedQuery ? 0.1 : 0.8}
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
animationDuration={100}
|
||||
@@ -252,21 +266,23 @@ export function MetricsChart({
|
||||
type="monotone"
|
||||
dataKey="p99_9"
|
||||
fill={config.p99_9.color}
|
||||
fillOpacity={selectedQuery ? 0.2 : 0.4}
|
||||
fillOpacity={selectedQuery ? 0.05 : 0.4}
|
||||
stroke={config.p99_9.color}
|
||||
strokeOpacity={selectedQuery ? 0.1 : 0.8}
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
animationDuration={100}
|
||||
/>
|
||||
)}
|
||||
{selectedQuery && visibleMetrics.query_exec_time && (
|
||||
{selectedQuery && visibleMetrics.query_latency && (
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="query_exec_time"
|
||||
fill={config.query_exec_time.color}
|
||||
fillOpacity={0.4}
|
||||
stroke={config.query_exec_time.color}
|
||||
strokeWidth={2}
|
||||
dataKey="query_latency"
|
||||
fill={config.query_latency.color}
|
||||
fillOpacity={0.6}
|
||||
stroke={config.query_latency.color}
|
||||
strokeOpacity={1}
|
||||
strokeWidth={2.5}
|
||||
dot={false}
|
||||
animationDuration={100}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { useQuery, UseQueryOptions } from '@tanstack/react-query'
|
||||
import { executeSql } from '../sql/execute-sql-query'
|
||||
import { QueryInsightsMetric } from './query-insights-query'
|
||||
|
||||
const singleQueryLatencyKeys = {
|
||||
base: ['single-query-latency'] as const,
|
||||
latency: (
|
||||
projectRef: string | undefined,
|
||||
queryId: string | undefined,
|
||||
startTime: string,
|
||||
endTime: string
|
||||
) => [...singleQueryLatencyKeys.base, projectRef, queryId, startTime, endTime] as const,
|
||||
}
|
||||
|
||||
const getSingleQueryLatencySql = (
|
||||
queryId: string,
|
||||
startTime: string,
|
||||
endTime: string
|
||||
) => /* SQL */ `
|
||||
SELECT
|
||||
bucket_start_time as timestamp,
|
||||
mean_exec_time as value,
|
||||
datname as database
|
||||
FROM pg_stat_monitor
|
||||
WHERE queryid = '${queryId}'
|
||||
AND bucket_start_time >= '${startTime}'
|
||||
AND bucket_start_time <= '${endTime}'
|
||||
ORDER BY bucket_start_time ASC
|
||||
`
|
||||
|
||||
export function useSingleQueryLatency(
|
||||
projectRef: string | undefined,
|
||||
queryId: string | undefined,
|
||||
startTime: string,
|
||||
endTime: string,
|
||||
options?: UseQueryOptions<QueryInsightsMetric[]>
|
||||
) {
|
||||
return useQuery({
|
||||
queryKey: singleQueryLatencyKeys.latency(projectRef, queryId, startTime, endTime),
|
||||
queryFn: async () => {
|
||||
if (!projectRef) throw new Error('Project ref is required')
|
||||
if (!queryId) return []
|
||||
|
||||
const { result } = await executeSql({
|
||||
projectRef,
|
||||
sql: getSingleQueryLatencySql(queryId, startTime, endTime),
|
||||
})
|
||||
|
||||
return result as QueryInsightsMetric[]
|
||||
},
|
||||
enabled: !!queryId && !!projectRef,
|
||||
...options,
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user