mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
(working with @charislam @awaseem on this one) ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES Per [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md): - ✅ `pnpm --filter studio build` - ✅ `pnpm test:prettier` - ✅ `pnpm format` ## What kind of change does this PR introduce? Instruments `studio` app's table creation flow with Sentry. ## What is the current behavior? The table creation flow isn't instrumented in detail, which means we have less visibility into understanding performance problems or errors within this specific flow. ## What is the new behavior? The table creation flow is instrumented in detail. This instrumentation allows for Sentry dashboards like this one (created based on locally generated Supabase data), to help monitor anything going wrong with this critical flow: <img width="1915" height="1131" alt="image" src="https://github.com/user-attachments/assets/e2c5380e-7b00-41c1-9109-3ee4e47ff63b" /> --------- Co-authored-by: Ali Waseem <waseema393@gmail.com>
68 lines
2.1 KiB
TypeScript
68 lines
2.1 KiB
TypeScript
import * as Sentry from '@sentry/nextjs'
|
|
import { PG_META_URL } from 'lib/constants/index'
|
|
import { constructHeaders } from '../apiHelpers'
|
|
import { PgMetaDatabaseError, databaseErrorSchema, WrappedResult } from './types'
|
|
import { assertSelfHosted, encryptString, getConnectionString } from './util'
|
|
|
|
export type QueryOptions = {
|
|
query: string
|
|
parameters?: unknown[]
|
|
readOnly?: boolean
|
|
headers?: HeadersInit
|
|
}
|
|
|
|
/**
|
|
* Executes a SQL query against the self-hosted Postgres instance via pg-meta service.
|
|
*
|
|
* _Only call this from server-side self-hosted code._
|
|
*/
|
|
export async function executeQuery<T = unknown>({
|
|
query,
|
|
parameters,
|
|
readOnly = false,
|
|
headers,
|
|
}: QueryOptions): Promise<WrappedResult<T[]>> {
|
|
assertSelfHosted()
|
|
|
|
const connectionString = getConnectionString({ readOnly })
|
|
const connectionStringEncrypted = encryptString(connectionString)
|
|
|
|
const requestBody: { query: string; parameters?: unknown[] } = { query }
|
|
if (parameters !== undefined) {
|
|
requestBody.parameters = parameters
|
|
}
|
|
|
|
return await Sentry.startSpan({ name: 'pg-meta.query', op: 'db.query' }, async (span) => {
|
|
const response = await fetch(`${PG_META_URL}/query`, {
|
|
method: 'POST',
|
|
headers: constructHeaders({
|
|
...headers,
|
|
'Content-Type': 'application/json',
|
|
'x-connection-encrypted': connectionStringEncrypted,
|
|
}),
|
|
body: JSON.stringify(requestBody),
|
|
})
|
|
|
|
try {
|
|
const result = await response.json()
|
|
|
|
if (!response.ok) {
|
|
const { message, code, formattedError } = databaseErrorSchema.parse(result)
|
|
span.setAttribute('db.error', 1)
|
|
span.setAttribute('db.status_code', response.status)
|
|
const error = new PgMetaDatabaseError(message, code, response.status, formattedError)
|
|
return { data: undefined, error }
|
|
}
|
|
|
|
span.setAttribute('db.status_code', response.status)
|
|
return { data: result, error: undefined }
|
|
} catch (error) {
|
|
span.setAttribute('db.error', 1)
|
|
if (error instanceof Error) {
|
|
return { data: undefined, error }
|
|
}
|
|
throw error
|
|
}
|
|
})
|
|
}
|