如何在Prisma的$on('query')日志中关联每个请求的traceId?
如何将请求级traceId关联到Prisma的SQL查询日志
你遇到的核心问题是:Prisma查询引擎运行在独立进程中,$on('query')的回调由引擎触发,无法访问Node.js主进程AsyncLocalStorage中保存的请求上下文(traceId);而Prisma扩展仅能捕获操作耗时,无法直接获取SQL详情。以下是两种可行的解决方案:
方案一:通过SQL注释传递traceId(兼容所有Prisma版本)
思路是在每个Prisma查询中注入包含traceId的SQL注释,再在$on('query')回调中从SQL语句解析出traceId。
1. 扩展Prisma客户端,注入traceId注释
修改扩展代码,为每个查询添加带traceId的SQL注释:
const traceExtension = Prisma.defineExtension((client) => { return client.$extends({ query: { $allModels: { async $allOperations({ args, query }) { const traceId = asyncContext.getStore()?.traceId ?? 'no-trace-id'; // 为查询添加包含traceId的注释 const modifiedArgs = { ...args, comment: `traceId: ${traceId}` }; return query(modifiedArgs); }, }, }, }); }); // 使用扩展后的客户端 const prisma = new PrismaClient().$extends(traceExtension);
2. 在$on('query')中解析traceId
修改日志回调,从SQL语句中提取traceId:
prisma.$on('query', (e) => { // 从SQL注释中匹配traceId const traceIdMatch = e.query.match(/traceId: ([a-f0-9-]+)/); const traceId = traceIdMatch ? traceIdMatch[1] : 'no-trace-id'; console.info(`${traceId} SQL: ${e.query}`); console.info(`${traceId} Params: ${e.params}`); console.info(`${traceId} Duration: ${e.duration}ms`); });
方案二:使用Prisma自定义日志格式(Prisma 4.16.0+)
从Prisma 4.16.0开始,日志配置支持自定义format函数,该函数运行在主进程的异步上下文中,可直接获取AsyncLocalStorage中的traceId,无需依赖$on('query')。
初始化PrismaClient时配置自定义日志
const prisma = new PrismaClient({ log: [ { level: 'query', emit: 'stdout', format: (queryInfo) => { const traceId = asyncContext.getStore()?.traceId ?? 'no-trace-id'; return `[${traceId}] SQL: ${queryInfo.query}, Params: ${queryInfo.params}, Duration: ${queryInfo.duration}ms`; }, }, // 可选:添加其他日志级别 { level: 'info', emit: 'stdout' }, { level: 'warn', emit: 'stdout' }, ], });
这种方法无需修改查询逻辑或解析SQL,直接在日志格式化阶段关联traceId,实现更简洁。
注意事项
- 方案一需确保你的数据库支持SQL注释(PostgreSQL、MySQL、SQLite等主流数据库均支持)。
- 方案二需要升级到Prisma 4.16.0或更高版本。
内容的提问来源于stack exchange,提问作者Champer Wu
相关产品推荐
相关产品推荐

