日志、调试与可观测性
本教程共 54 篇 · 第 41 篇 · 更新于 2026-08-11 · 约 6 分钟阅读
本节目标:让每条 SQL 可见、可追踪、可度量,出问题时能快速定位。
应用上线后,数据库里发生了什么基本看不见。日志、追踪、健康检查就是你的眼睛。
日志级别与 $on 事件
PrismaClient 构造函数支持 log 选项,四种级别:query(SQL 语句与耗时)、info(生命周期)、warn(潜在问题)、error(失败):
const prisma = new PrismaClient({
adapter,
log: ["query", "info", "warn", "error"],
});
默认打印到 stdout。想自己处理,把级别改成事件(event)模式,用 $on 订阅:
const prisma = new PrismaClient({
adapter,
log: [
{ emit: "event", level: "query" },
{ emit: "stdout", level: "error" },
],
});
prisma.$on("query", (e) => {
console.log("Query:", e.query);
console.log("Params:", e.params);
console.log("Duration:", e.duration, "ms");
});
query 事件带三个字段:SQL 文本、参数数组、耗时(毫秒)。这是定位慢查询的第一手数据。可以在监听器里加阈值告警:duration 超过 100ms 就记一条 warn 日志。
日志默认打进 stdout,格式是文本。想让日志进采集系统,常见做法是把事件接进结构化日志库(pino、winston),一条查询一行 JSON,方便检索和聚合:
import pino from "pino";
const logger = pino();
prisma.$on("query", (e) => {
if (e.duration > 100) {
logger.warn({ sql: e.query, params: e.params, ms: e.duration }, "slow query");
}
});
Note生产环境不要开 query 日志。每条 SQL 都打印,日志量和性能开销都扛不住。生产只留 error 级别,需要排查时再临时开。
DEBUG 环境变量
log 管的是应用层行为,想深入客户端内部,用 DEBUG 环境变量:
# 全部 Prisma 调试信息
export DEBUG="prisma*"
# 只看客户端
export DEBUG="prisma:client"
# 只看引擎
export DEBUG="prisma:engine"
Windows 上把 export 换成 set。这是排查初始化失败、连接异常的利器。
慢查询的数据库侧定位
应用侧日志能看单条 SQL,但看不出整体规律。数据库侧两个工具补位:
- log_min_duration_statement:Postgres 配置,把超过阈值的语句写进数据库日志。
- pg_stat_statements:扩展,按语句聚合平均耗时、调用次数,适合找「慢但频繁」的查询。
慢 SQL 拿到手后,用 EXPLAIN ANALYZE 看执行计划:走没走索引、有没有全表扫描。Prisma 里可以用原始查询(Raw Query)直接跑:
await prisma.$queryRaw`EXPLAIN ANALYZE SELECT * FROM "Post" WHERE "authorId" = 1`;
SQL 注释:给查询挂上下文
v7.1 起支持 SQL 注释,采用 Google 的 sqlcommenter 格式。查询会带着注释一起发给数据库,监控工具据此把 SQL 关联回具体业务。官方两个插件:
- queryTags:在异步上下文里给查询打标签,比如路由、请求 ID。
- traceContext:把 W3C traceparent 写进 SQL 注释,关联分布式追踪。
import { PrismaPg } from "@prisma/adapter-pg";
import { queryTags, withQueryTags } from "@prisma/sqlcommenter-query-tags";
import { PrismaClient } from "../generated/prisma/client";
const prisma = new PrismaClient({
adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }),
comments: [queryTags()],
});
await withQueryTags({ route: "/api/users", requestId: "abc-123" }, () =>
prisma.user.findMany(),
);
发出的 SQL 长这样:SELECT ... FROM "User" /*requestId='abc-123',route='/api/users'*/。
嵌套作用域时,默认是替换:内层标签会盖掉外层。想要合并用 withMergedQueryTags,内层和外层的标签共存。标签会出现在数据库日志和监控工具里,注意别把用户密码之类的敏感值打进去。
OpenTelemetry 追踪
OpenTelemetry 追踪给每次操作生成一条 trace,里面是嵌套的 span:prisma:client:operation 是整个操作,下面有 serialize(序列化)、engine:query(查询引擎)、db_query(数据库查询)等子 span,各阶段耗时一目了然。接入三步:
- 装依赖:
@prisma/instrumentation和@opentelemetry系列包。 - 用 PrismaInstrumentation 注册插桩。
- 选导出器:SimpleSpanProcessor 逐条发(开发用),BatchSpanProcessor 批量发(生产推荐)。
import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
import { PrismaInstrumentation } from "@prisma/instrumentation";
const sdk = new NodeSDK({
serviceName: "my-service",
traceExporter: new OTLPTraceExporter(),
instrumentations: [new PrismaInstrumentation()],
});
sdk.start();
trace 可以发给 Jaeger、Honeycomb、Datadog 等任何兼容 OpenTelemetry 的后端。配合 sqlcommenter 的 traceContext,数据库里的慢 SQL 和应用 trace 能对上号。
交互式事务也有专属 span:prisma:client:transaction 包住整个事务,里面每个查询再展开。事务超时、锁等待这类问题,看 trace 比翻日志直观得多。
Tip注册追踪必须在 import 任何被插桩的依赖之前执行,否则这些模块不会被追踪。
高流量应用要控制 span 数量:生产用 BatchSpanProcessor 批量发送,或用采样器(如 TraceIdRatioBasedSampler(0.1))只采 10% 的请求,降低采集开销。
健康检查
健康检查是运维探活的基础。数据库探针一条查询就够了:
app.get("/health/db", async (_req, res) => {
try {
await prisma.$queryRaw`SELECT 1`;
res.json({ ok: true });
} catch {
res.status(503).json({ ok: false });
}
});
liveness 探针管进程是否活着,readiness 探针管依赖是否可用,数据库探针属于后者。Kubernetes 里就按这个语义配置:进程挂了重启容器,数据库不可用就不给流量。
v7 的 Metrics:已移除
v6 时代的 prisma.$metrics.prometheus() 等指标接口,在 6.14 弃用、7.0 正式删除。现在拿指标有两条路:
- 数据库侧:pg_stat_activity 看连接数,pg_stat_statements 看慢查询聚合。
- 应用侧:用
$on("query")事件自己统计(计数、耗时),或用客户端扩展(Client Extensions)在 query 钩子里统一打点,再暴露成 Prometheus 格式。
let queryCount = 0;
prisma.$on("query", () => {
queryCount++;
});
生产日志纪律
日志不是越多越好,三条纪律:
- 采样:慢查询全记,普通查询按比例采样,控制日志量。
- 脱敏:params 里可能带邮箱、手机号等个人信息,入库前剥离,只保留结构。
- 开关:用环境变量或配置中心控制日志级别,排查问题时临时开 query,事后关掉。
监控告警的参考阈值:错误率持续超过 1%、p95 延迟超过 SLO、连接池占用长期超过 80%,都该触发告警。
NoteMongoDB 的日志与监控体系由驱动管理,v7 不支持 MongoDB,相关场景留在 v6.19。
参考来源
- Prisma 官方文档:Logging / Debugging / SQL comments / OpenTelemetry tracing
- Mapagam:Debugging and Logging Queries / Monitoring and Observability