Created
May 20, 2024 04:45
-
-
Save Jackman3005/c11c751c6d5fac4f002d4d369f20932b to your computer and use it in GitHub Desktop.
Prisma Query Debugging code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function buildPrismaWithQueryDebugging( | |
sqlQueryReportingThresholdMs: number, | |
prismaActionReportingThresholdMs: number | |
) { | |
const prisma = new PrismaClient({ | |
log: [ | |
{ | |
emit: "event", | |
level: "query", | |
}, | |
], | |
}); | |
prisma.$on("query", (e) => { | |
try { | |
if (!/^(UPDATE|SELECT|INSERT|DELETE).*/g.test(e.query)) { | |
// skip BEGIN/COMMIT/etc queries | |
return; | |
} | |
if (e.duration < sqlQueryReportingThresholdMs) { | |
// threshold for what to record, increase if too many queries printed, decrease if not enough | |
return; | |
} | |
// replace raw date characters with the postgres timestamp syntax wrapped in a string | |
const queryParamsArray = e.params.replaceAll( | |
/(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{0,3} UTC)/g, | |
(match) => { | |
return `TIMESTAMP WITH TIME ZONE '${match}'`; | |
} | |
); | |
const paramObjs = JSON.parse(queryParamsArray); | |
const rebuiltQuery = (e.query || "").replaceAll( | |
/\$(\d+)/g, | |
(_matchedString, paramIndex) => { | |
let param = paramObjs[parseInt(paramIndex) - 1]; | |
if (typeof param === "string") { | |
if (!param.startsWith("TIMESTAMP")) { | |
param = `'${param.replace("'", "\\'")}'`; | |
} | |
} | |
return param; | |
} | |
); | |
LOG.debug( | |
`\n\nLONG QUERY DETECTED - ${e.duration}ms - Query below:\n${rebuiltQuery}\n`, | |
{ durationMs: e.duration } | |
); | |
} catch (err) { | |
LOG.error("Unknown error in long query reporter: ", err); | |
} | |
}); | |
return prisma.$extends({ | |
query: { | |
async $allOperations({ operation, model, args, query }) { | |
const timeStart = Date.now(); | |
const result = await query(args); | |
const timeEnd = Date.now(); | |
try { | |
const duration = timeEnd - timeStart; | |
if (duration > prismaActionReportingThresholdMs) { | |
let resultStats; | |
if (Array.isArray(result)) { | |
resultStats = `NumItems: ${result.length}, RawCharacterSize: ${ | |
JSON.stringify(result).length | |
}`; | |
} else { | |
resultStats = `RawCharacterSize: ${ | |
JSON.stringify(result).length | |
}`; | |
} | |
LOG.warn( | |
`LONG PRISMA ACTION DETECTED - ${duration}ms - ${model}.${operation} - Result Stats -> ${resultStats}`, | |
{ | |
error: new Error("LONG PRISMA ACTION DETECTED"), | |
durationMs: duration, | |
model, | |
operation, | |
args, | |
} | |
); | |
} | |
} catch (error) { | |
LOG.error("Unknown error in long action reporter: ", { error }); | |
} | |
return result; | |
}, | |
}, | |
}); | |
} | |
const _prisma = ENV.DEBUG_PRISMA_QUERIES | |
? buildPrismaWithQueryDebugging(10, 30) | |
: new PrismaClient(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment