QueryPerformance.utils.ts 2.0 KB

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