首页 / Prisma ORM 入门教程 / 日志、调试与可观测性

Prisma ORM 入门教程

日志、调试与可观测性

本教程共 54 篇 · 第 41 篇 · 更新于 2026-08-11 · 约 6 分钟阅读

日志DEBUGOpenTelemetrySQL 注释健康检查Metrics可观测性

本节目标:让每条 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,各阶段耗时一目了然。接入三步:

  1. 装依赖:@prisma/instrumentation@opentelemetry 系列包。
  2. 用 PrismaInstrumentation 注册插桩。
  3. 选导出器: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 正式删除。现在拿指标有两条路:

  1. 数据库侧:pg_stat_activity 看连接数,pg_stat_statements 看慢查询聚合。
  2. 应用侧:用 $on("query") 事件自己统计(计数、耗时),或用客户端扩展(Client Extensions)在 query 钩子里统一打点,再暴露成 Prometheus 格式。
let queryCount = 0;
prisma.$on("query", () => {
  queryCount++;
});

生产日志纪律

日志不是越多越好,三条纪律:

  1. 采样:慢查询全记,普通查询按比例采样,控制日志量。
  2. 脱敏:params 里可能带邮箱、手机号等个人信息,入库前剥离,只保留结构。
  3. 开关:用环境变量或配置中心控制日志级别,排查问题时临时开 query,事后关掉。

监控告警的参考阈值:错误率持续超过 1%、p95 延迟超过 SLO、连接池占用长期超过 80%,都该触发告警。

Note

MongoDB 的日志与监控体系由驱动管理,v7 不支持 MongoDB,相关场景留在 v6.19。

参考来源

  • Prisma 官方文档:Logging / Debugging / SQL comments / OpenTelemetry tracing
  • Mapagam:Debugging and Logging Queries / Monitoring and Observability