Files
supabase/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.utils.ts
Jordi Enric 9685711519 chore(query-perf): better error handling and sentry tracking (#41278)
* add retry

* handle and capture errors

* adds tests

* improve Sentry integration

* remove SQL logging from query performance error capture

* fix error msg prop handling

* add max and baseline to alert

* undo change meant for other branch oops
2025-12-15 20:39:09 +01:00

85 lines
2.3 KiB
TypeScript

import * as Sentry from '@sentry/nextjs'
import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration'
import { getErrorMessage } from 'lib/get-error-message'
dayjs.extend(duration)
export const formatDuration = (milliseconds: number) => {
const duration = dayjs.duration(milliseconds, 'milliseconds')
const days = Math.floor(duration.asDays())
const hours = duration.hours()
const minutes = duration.minutes()
const seconds = duration.seconds()
const totalSeconds = duration.asSeconds()
if (totalSeconds < 60) {
return `${totalSeconds.toFixed(2)}s`
}
const parts = []
if (days > 0) parts.push(`${days}d`)
if (hours > 0) parts.push(`${hours}h`)
if (minutes > 0) parts.push(`${minutes}m`)
if (seconds > 0) parts.push(`${seconds}s`)
return parts.length > 0 ? parts.join(' ') : '0s'
}
export const transformLogsToJSON = (log: string) => {
try {
let jsonString = log.replace('[pg_stat_monitor] ', '')
jsonString = jsonString.replace(/""/g, '","')
const jsonObject = JSON.parse(jsonString)
return jsonObject
} catch (error) {
return null
}
}
export type QueryPerformanceErrorContext = {
projectRef?: string
databaseIdentifier?: string
queryPreset?: string
queryType?: 'hitRate' | 'metrics' | 'mainQuery' | 'monitor' | 'slowQueriesCount'
sql?: string
errorMessage?: string
postgresVersion?: string
databaseType?: 'primary' | 'read-replica'
}
export function captureQueryPerformanceError(
error: unknown,
context: QueryPerformanceErrorContext
) {
Sentry.withScope((scope) => {
scope.setTag('query-performance', 'true')
scope.setContext('query-performance', {
projectRef: context.projectRef,
databaseIdentifier: context.databaseIdentifier,
queryPreset: context.queryPreset,
queryType: context.queryType,
postgresVersion: context.postgresVersion,
databaseType: context.databaseType,
errorMessage: context.errorMessage,
})
if (error instanceof Error) {
Sentry.captureException(error)
return
}
const errorMessage = getErrorMessage(error)
const errorToCapture = new Error(errorMessage || 'Query performance error')
if (error !== null && error !== undefined) {
errorToCapture.cause = error
}
Sentry.captureException(errorToCapture)
})
}