QueryPerformance.utils.ts73 lines · main
| 1 | import * as Sentry from '@sentry/nextjs' |
| 2 | import dayjs from 'dayjs' |
| 3 | import duration from 'dayjs/plugin/duration' |
| 4 | |
| 5 | import { getErrorMessage } from '@/lib/get-error-message' |
| 6 | |
| 7 | dayjs.extend(duration) |
| 8 | |
| 9 | export const formatDuration = (milliseconds: number) => { |
| 10 | const duration = dayjs.duration(milliseconds, 'milliseconds') |
| 11 | |
| 12 | const days = Math.floor(duration.asDays()) |
| 13 | const hours = duration.hours() |
| 14 | const minutes = duration.minutes() |
| 15 | const seconds = duration.seconds() |
| 16 | const totalSeconds = duration.asSeconds() |
| 17 | |
| 18 | if (totalSeconds < 60) { |
| 19 | return `${totalSeconds.toFixed(2)}s` |
| 20 | } |
| 21 | |
| 22 | const parts = [] |
| 23 | if (days > 0) parts.push(`${days}d`) |
| 24 | if (hours > 0) parts.push(`${hours}h`) |
| 25 | if (minutes > 0) parts.push(`${minutes}m`) |
| 26 | if (seconds > 0) parts.push(`${seconds}s`) |
| 27 | |
| 28 | return parts.length > 0 ? parts.join(' ') : '0s' |
| 29 | } |
| 30 | |
| 31 | export type QueryPerformanceErrorContext = { |
| 32 | projectRef?: string |
| 33 | databaseIdentifier?: string |
| 34 | queryPreset?: string |
| 35 | queryType?: 'hitRate' | 'metrics' | 'mainQuery' | 'slowQueriesCount' | 'supamonitor' |
| 36 | sql?: string |
| 37 | errorMessage?: string |
| 38 | postgresVersion?: string |
| 39 | databaseType?: 'primary' | 'read-replica' |
| 40 | } |
| 41 | |
| 42 | export function captureQueryPerformanceError( |
| 43 | error: unknown, |
| 44 | context: QueryPerformanceErrorContext |
| 45 | ) { |
| 46 | Sentry.withScope((scope) => { |
| 47 | scope.setTag('query-performance', 'true') |
| 48 | |
| 49 | scope.setContext('query-performance', { |
| 50 | projectRef: context.projectRef, |
| 51 | databaseIdentifier: context.databaseIdentifier, |
| 52 | queryPreset: context.queryPreset, |
| 53 | queryType: context.queryType, |
| 54 | postgresVersion: context.postgresVersion, |
| 55 | databaseType: context.databaseType, |
| 56 | errorMessage: context.errorMessage, |
| 57 | }) |
| 58 | |
| 59 | if (error instanceof Error) { |
| 60 | Sentry.captureException(error) |
| 61 | return |
| 62 | } |
| 63 | |
| 64 | const errorMessage = getErrorMessage(error) |
| 65 | const errorToCapture = new Error(errorMessage || 'Query performance error') |
| 66 | |
| 67 | if (error !== null && error !== undefined) { |
| 68 | errorToCapture.cause = error |
| 69 | } |
| 70 | |
| 71 | Sentry.captureException(errorToCapture) |
| 72 | }) |
| 73 | } |