diff --git a/apps/api/src/db/prisma.ts b/apps/api/src/db/prisma.ts index a8e61658d..bff6406eb 100644 --- a/apps/api/src/db/prisma.ts +++ b/apps/api/src/db/prisma.ts @@ -6,9 +6,9 @@ import { ProviderConfigSchema, type ProviderConfig } from "~api/modules/provider const DB_NULL = null; -const prisma = new PrismaClient({ - adapter: createPrismaAdapter("api"), -}); +/** Deferred to first request so OTel instrumentation is registered before the driver loads. */ +let _prisma: PrismaClient; +const getPrisma = () => (_prisma ??= new PrismaClient({ adapter: createPrismaAdapter("api") })); export const createPrismaClient = (organizationId: string, userId: string) => { if (!organizationId || !userId) { @@ -17,7 +17,7 @@ export const createPrismaClient = (organizationId: string, userId: string) => { const tenantFilters = { deleted_at: DB_NULL, organization_id: organizationId }; - return prisma.$extends({ + return getPrisma().$extends({ query: { $allModels: { $allOperations({ args, query, operation }) { @@ -94,7 +94,7 @@ export const createPrismaClient = (organizationId: string, userId: string) => { }, provider_configs: { getUnredacted(slug: string) { - return prisma.provider_configs.findFirst({ + return getPrisma().provider_configs.findFirst({ where: { provider_slug: slug, created_by: userId, diff --git a/packages/shared-api/db/postgres.ts b/packages/shared-api/db/postgres.ts index 23047fd24..346df66bd 100644 --- a/packages/shared-api/db/postgres.ts +++ b/packages/shared-api/db/postgres.ts @@ -1,4 +1,4 @@ -import { PrismaPg } from "@prisma/adapter-pg"; +import type { PrismaPg } from "@prisma/adapter-pg"; import { Resource } from "sst"; import { DEFAULT_DB_IDLE_TIMEOUT_MS, DEFAULT_DB_POOL_MAX } from "./config"; @@ -22,6 +22,7 @@ export const createPrismaAdapter = ( schema: string, max: number = DEFAULT_DB_POOL_MAX, ): PrismaPg => { + const { PrismaPg } = require("@prisma/adapter-pg") as typeof import("@prisma/adapter-pg"); return new PrismaPg( { connectionString: getConnectionString(schema), diff --git a/packages/shared-api/lib/otel.ts b/packages/shared-api/lib/otel.ts index f0b1c1b97..c4e5a1e2f 100644 --- a/packages/shared-api/lib/otel.ts +++ b/packages/shared-api/lib/otel.ts @@ -4,7 +4,6 @@ import type { SeverityNumber } from "@opentelemetry/api-logs"; import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-proto"; import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-proto"; import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto"; -import { registerInstrumentations } from "@opentelemetry/instrumentation"; import { PgInstrumentation } from "@opentelemetry/instrumentation-pg"; import { CompressionAlgorithm } from "@opentelemetry/otlp-exporter-base"; import { resourceFromAttributes } from "@opentelemetry/resources"; @@ -82,21 +81,6 @@ export const createOtelLogger = (serviceName: string, minimumSeverity: SeverityN return loggerProvider.getLogger(serviceName); }; -registerInstrumentations({ - instrumentations: [ - new PgInstrumentation({ - requireParentSpan: true, - enhancedDatabaseReporting: false, - }), - new BunSqlInstrumentation({ - requireParentSpan: true, - ignoreConnectionSpans: true, - // FUTURE: set to true to avoid leaking sensitive information - maskStatement: false, - }), - ], -}); - export const getOtelConfig = ( serviceName: string, additionalRequestHeaders?: readonly string[], @@ -104,6 +88,18 @@ export const getOtelConfig = ( ): ElysiaOpenTelemetryOptions => { return { serviceName, + instrumentations: [ + new PgInstrumentation({ + requireParentSpan: true, + enhancedDatabaseReporting: false, + }), + new BunSqlInstrumentation({ + requireParentSpan: true, + ignoreConnectionSpans: true, + // FUTURE: set to true to avoid leaking sensitive information + maskStatement: false, + }), + ], headersToSpanAttributes: { request: [...ALLOWED_REQUEST_HEADERS, ...(additionalRequestHeaders ?? [])], response: [...ALLOWED_RESPONSE_HEADERS, ...(additionalResponseHeaders ?? [])],