QueryPerformance.utils.ts73 lines · main
1import * as Sentry from '@sentry/nextjs'
2import dayjs from 'dayjs'
3import duration from 'dayjs/plugin/duration'
4
5import { getErrorMessage } from '@/lib/get-error-message'
6
7dayjs.extend(duration)
8
9export 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
31export 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
42export 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}