如何使用 Prisma ORM 设置 Datadog 追踪
介绍
¥Introduction
在本指南中,你将学习如何为新的 Prisma 项目设置 Datadog 追踪。通过将 @prisma/instrumentation
包与 Prisma 客户端扩展相结合,你可以捕获每个数据库查询的详细跨度。这些 span 包含丰富的查询元数据,并发送到 Datadog 使用 dd-trace
(Datadog 官方的 Node.js APM 库),使你能够监控、分析和深入了解应用的数据库活动。
¥In this guide, you'll learn how to set up Datadog tracing for a new Prisma project. By combining the @prisma/instrumentation
package with Prisma Client extensions, you can capture detailed spans for every database query. These spans are enriched with query metadata and sent to Datadog using dd-trace
, Datadog's official APM library for Node.js, enabling you to monitor, analyze, and gain visibility into your application's database activity.
什么是 Span 和 tracing?
¥What are spans and tracing?
-
跨度是分布式系统或复杂应用中的单个操作或工作单元。每个数据库查询、服务调用或外部请求都由一个 span 表示。
¥Spans are the individual operations or units of work within a distributed system or complex application. Each database query, service call, or external request is represented by a span.
-
跟踪将这些跨度联系在一起,形成一个完整的、端到端的请求生命周期图景。通过跟踪,你可以可视化瓶颈、识别有问题的查询并查明查询中发生错误的位置。
¥Tracing ties these spans together to form a complete, end-to-end picture of a request’s lifecycle. With tracing, you can visualize bottlenecks, identify problematic queries, and pinpoint where errors occur from your queries.
为什么将 Datadog 与 Prisma ORM 一起使用?
¥Why use Datadog with Prisma ORM?
数据狗 提供应用性能监控 (APM)、指标、日志和仪表板,帮助你观察和调试生产系统。
¥Datadog provides application performance monitoring (APM), metrics, logs, and dashboards to help you observe and debug production systems.
虽然 Prisma ORM 抽象了 SQL 并提高了开发者的工作效率,但如果没有适当的检测,它可能会降低查询性能。通过使用 @prisma/instrumentation
和 dd-trace
将 Datadog 与 Prisma 集成,你可以自动捕获每个数据库查询的跨度。
¥While Prisma ORM abstracts away SQL and boosts developer productivity, it can obscure query performance without proper instrumentation. By integrating Datadog with Prisma using @prisma/instrumentation
and dd-trace
, you can automatically capture spans for every database query.
这使你能够:
¥This enables you to:
-
测量每个查询的延迟。
¥Measure latency per query.
-
检查查询参数和原始 SQL。
¥Inspect query arguments and raw SQL.
-
在应用级请求的上下文中跟踪 Prisma 操作。
¥Trace Prisma operations in the context of application-level requests.
-
识别与数据库访问相关的瓶颈。
¥Identify bottlenecks related to database access.
此集成以最小的努力提供了对 Prisma 查询的运行时可见性,帮助你实时捕获慢速查询和错误。
¥This integration provides runtime visibility into Prisma queries with minimal effort, helping you catch slow queries and errors in real time.
先决条件
¥Prerequisites
开始之前,请确保你已具备以下条件:
¥Before you begin, ensure you have the following:
-
已安装 Node.js(建议使用 v18 及以上版本)。
¥Node.js installed (v18+ recommended).
-
一个本地或托管的 PostgreSQL 数据库。
¥A local or hosted PostgreSQL database.
-
一个 Datadog 账户。如果你没有数据库 URL,请使用 在此注册。
¥A Datadog account. If you do not have one, sign up here.
-
Datadog 代理已安装并运行在运行此应用的机器或服务器上。你可以按照 Datadog Agent 安装文档 进行设置。
¥The Datadog Agent installed and running on your machine or server where this application will run. You can follow the Datadog Agent installation docs to set it up.
1. 创建一个新项目
¥ Create a new project
我们将首先创建一个新的 Node.js 项目,以演示如何使用 Datadog 和 Prisma ORM 进行跟踪。这将是一个最小的独立设置,专注于运行和跟踪 Prisma 查询,以便单独了解检测流程。
¥We will start by creating a new Node.js project to demonstrate tracing with Datadog and Prisma ORM. This will be a minimal, standalone setup focused on running and tracing Prisma queries, to understand the instrumentation flow in isolation.
如果你要将跟踪集成到现有的 Prisma 项目中,则可以跳过此步骤,直接从 设置跟踪部分 开始操作。请确保将更改应用到项目的等效文件夹结构中。
¥If you're integrating tracing into an existing Prisma project, you can skip this step and directly follow from the setup tracing section. Just make sure you apply the changes in your project's equivalent folder structure.
mkdir prisma-datadog-tracing
cd prisma-datadog-tracing
npm init -y
在此设置中,你将:
¥In this setup, you'll:
-
使用基本模型定义 Prisma 模式。
¥Define a Prisma schema with basic models.
-
连接到 Postgres 数据库(Prisma Postgres 或你自己的数据库)。
¥Connect to a Postgres database (Prisma Postgres or your own).
-
使用
@prisma/instrumentation
和dd-trace
为所有查询配置 Datadog 跟踪。¥Configure Datadog tracing for all queries using
@prisma/instrumentation
anddd-trace
. -
运行执行 Prisma 操作并将 span 发送到 Datadog 的示例脚本。
¥Run a sample script that executes Prisma operations and sends spans to Datadog.
2. 设置 Prisma ORM
¥ Set up Prisma ORM
在本部分中,你将安装 Prisma、创建模式并生成 Prisma 客户端。这将使你的应用准备好运行数据库查询 - 你将使用 Datadog 跟踪的查询。
¥In this section, you will install Prisma, create your schema, and generate the Prisma Client. This prepares your application to run database queries—queries that you will trace with Datadog.
2.1.安装并初始化 Prisma ORM
¥2.1. Install and initialize Prisma ORM
运行以下命令安装 Prisma 和精简的 TypeScript 运行器:
¥Run the following commands to install Prisma and a minimal TypeScript runner:
npm install -D prisma tsx
然后初始化 Prisma:
¥Then initialize Prisma:
在项目中初始化 Prisma 时,你可以使用 --db
标志创建 新的 Prisma Postgres 实例。
¥You can use the --db
flag to create a new Prisma Postgres instance when initializing Prisma in your project.
- Prisma Postgres (recommended)
- Your own database
npx prisma init --db --output ../src/generated/prisma
You will be prompted to name your database and select the closest region. For clarity, choose a memorable name (e.g., My Datadog Project
).
npx prisma init --output ../src/generated/prisma
此命令执行以下操作:
¥This command does the following:
-
创建包含
schema.prisma
文件的prisma
目录。¥Creates a
prisma
directory with aschema.prisma
file. -
在
/src/generated/prisma
目录(如--output
标志中指定)中生成 Prisma 客户端。¥Generates the Prisma Client in the
/src/generated/prisma
directory (as specified in the--output
flag). -
在项目根目录创建一个包含数据库连接字符串 (
DATABASE_URL
) 的.env
文件。¥Creates a
.env
file at the project root with your database connection string (DATABASE_URL
).
如果你未使用 --db
标志,请替换 .env
文件中的占位符数据库 URL:
¥If you did not use the --db
flag, replace the placeholder database URL in the .env
file:
- Prisma Postgres
- Your own database
DATABASE_URL="prisma+postgres://accelerate.prisma-data.net/?api_key=..."
# Placeholder url you have to replace
DATABASE_URL="postgresql://janedoe:mypassword@localhost:5432/mydb?schema=sample"
如果你使用 Prisma Postgres,还需要安装:
¥If you're using Prisma Postgres, also install:
npm i @prisma/extension-accelerate
此扩展使你能够使用 缓存你的 Prisma 查询。
¥This extension enables you to cache your Prisma queries.
2.2.定义模型
¥2.2. Define models
现在,打开 prisma/schema.prisma
并更新生成器块和模型。将 generator
块替换为以下内容,并添加 User
和 Post
模型:
¥Now, open prisma/schema.prisma
and update your generator block and models. Replace the generator
block with the following, and add a User
and a Post
model:
generator client {
provider = "prisma-client-js"
output = "../src/generated/prisma"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
authorId Int
author User @relation(fields: [authorId], references: [id])
}
2.3.生成 Prisma 客户端并运行迁移
¥2.3. Generate the Prisma Client and run migrations
生成 Prisma 客户端并将你的模式应用于数据库:
¥Generate the Prisma Client and apply your schema to your database:
npx prisma generate
npx prisma migrate dev --name "init"
这将根据你的架构在 Postgres 数据库中创建表,并生成一个客户端供你与数据库交互。
¥This creates the tables according to your schema in the Postgres database and generates a client for you to interact with the database.
3. 安装追踪所需的依赖
¥ Install required dependencies for tracing
除了 Prisma,你还需要以下软件包来进行 Datadog 追踪:
¥In addition to Prisma, you will need the following packages for Datadog tracing:
npm install @prisma/instrumentation \
dd-trace
同时,请确保你已安装 TypeScript 的开发依赖:
¥Also ensure you have development dependencies for TypeScript:
npm install -D typescript
以下是简要概述:
¥Here's a quick overview:
-
@prisma/instrumentation
:对 Prisma 查询进行检测,使其在跟踪器中显示为跨度。¥
@prisma/instrumentation
: Instruments Prisma queries so they appear as spans in your tracer. -
dd-trace
:Datadog 的官方 Node.js 跟踪库。¥
dd-trace
: Official Node.js tracing library from Datadog.
4. 设置 Datadog 追踪
¥ Set up Datadog tracing
在 src
文件夹中创建一个 tracer.ts
文件来实例化你的跟踪逻辑:
¥Create a tracer.ts
file in the src
folder to instantiate your tracing logic:
touch src/tracer.ts
4.1.配置跟踪器
¥4.1. Configure the tracer
打开 src/tracer.ts
并添加以下代码:
¥Open src/tracer.ts
and add the following code:
import Tracer from "dd-trace";
import {
PrismaInstrumentation,
registerInstrumentations,
} from "@prisma/instrumentation";
const tracer = Tracer.init({
apmTracingEnabled: true,
service: "prisma-datadog-tracing",
version: "1.0.0",
profiling: true
});
const provider = new tracer.TracerProvider();
// Register the provider globally
provider.register();
registerInstrumentations({
instrumentations: [
new PrismaInstrumentation({
enabled: true,
}),
],
tracerProvider: provider,
});
export { tracer };
如果你在 traceProvider: provider
行遇到由于类型不兼容而导致的 linting 错误,则很可能是由 @opentelemetry/api
包中的版本不匹配引起的。
¥If you encounter a linting error on the line traceProvider: provider
due to incompatible types, it's likely caused by a version mismatch in the @opentelemetry/api
package.
要解决此问题,请在你的 package.json 中添加以下覆盖:
¥To resolve this, add the following override to your package.json:
"overrides": {
"@opentelemetry/api": "1.8.0"
}
这是必要的,因为 dd-trace
尚不支持 1.9.0
或更高版本的 @opentelemetry/api
。
¥This is necessary because dd-trace
does not yet support version 1.9.0
or above of @opentelemetry/api
.
更新 package.json
后,重新安装依赖:
¥After updating the package.json
, reinstall your dependencies:
npm i
这应该可以解决 linting 错误。
¥This should resolve the linting error.
说明
¥Explanation
-
Tracer.init
配置dd-trace
的名称为service
。此名称显示在 Datadog 中的APM
>Services
列表下。¥
Tracer.init
configuresdd-trace
with aservice
name. This name appears in Datadog under yourAPM
>Services
list. -
@prisma/instrumentation
自动将每个 Prisma 查询记录为 Datadog span。¥
@prisma/instrumentation
automatically logs each Prisma query as a Datadog span. -
middleware: true
选项可确保每个查询都被拦截以进行检测。¥The
middleware: true
option ensures that each query is intercepted for instrumentation.
5. 实例化 Prisma 并运行查询
¥ Instantiate Prisma and run queries
5.1.创建 Prisma 客户端实例
¥5.1. Create the Prisma Client instance
创建一个 src/client.ts
文件来保存你的 Prisma 客户端实例:
¥Create a src/client.ts
to hold your Prisma Client instantiation:
- Prisma Postgres (recommended)
- Your own database
import { tracer } from "./tracer";
import { withAccelerate } from "@prisma/extension-accelerate";
import { PrismaClient } from "./generated/prisma";
const prisma = new PrismaClient({
log: [{ emit: "event", level: "query" }],
})
.$on("query", (e) => {
const span = tracer.startSpan(`prisma_raw_query`, {
childOf: tracer.scope().active() || undefined,
tags: {
"prisma.rawquery": e.query,
},
});
span.finish();
})
.$extends({
query: {
async $allOperations({ operation, model, args, query }) {
const span = tracer.startSpan(
`prisma_query_${model?.toLowerCase()}_${operation}`,
{
tags: {
"prisma.operation": operation,
"prisma.model": model,
"prisma.args": JSON.stringify(args),
"prisma.rawQuery": query,
},
childOf: tracer.scope().active() || undefined,
}
);
try {
const result = await query(args);
span.finish();
return result;
} catch (error) {
span.setTag("error", error);
span.finish();
throw error;
}
},
},
})
.$extends(withAccelerate());
export { prisma };
import { tracer } from "./tracer";
import { withAccelerate } from "@prisma/extension-accelerate";
import { PrismaClient } from "./generated/prisma";
const prisma = new PrismaClient({
log: [{ emit: "event", level: "query" }],
})
.$on("query", (e) => {
const span = tracer.startSpan(`prisma_raw_query`, {
childOf: tracer.scope().active() || undefined,
tags: {
"prisma.rawquery": e.query,
},
});
span.finish();
})
.$extends({
query: {
async $allOperations({ operation, model, args, query }) {
const span = tracer.startSpan(
`prisma_query_${model?.toLowerCase()}_${operation}`,
{
tags: {
"prisma.operation": operation,
"prisma.model": model,
"prisma.args": JSON.stringify(args),
"prisma.rawQuery": query,
},
childOf: tracer.scope().active() || undefined,
}
);
try {
const result = await query(args);
span.finish();
return result;
} catch (error) {
span.setTag("error", error);
span.finish();
throw error;
}
},
},
});
export { prisma };
上述设置使你可以更好地控制查询的跟踪方式:
¥The setup above gives you more control over how queries are traced:
-
通过在创建 Prisma 客户端之前导入
tracer
,可以尽早初始化跟踪。¥Tracing is initialized as early as possible by importing the
tracer
before creating the Prisma Client. -
$on("query")
钩子捕获原始 SQL 查询并将其作为独立 span 发送。¥The
$on("query")
hook captures raw SQL queries and sends them as standalone spans. -
$allOperations
扩展将所有 Prisma 操作封装在自定义 span 中,允许你使用模型、操作类型和参数等元数据对其进行标记。¥The
$allOperations
extension wraps all Prisma operations in custom spans, allowing you to tag them with metadata like the model, operation type, and arguments.
与提供开箱即用自动跟踪功能的 @prisma/instrumentation
软件包不同,此手动设置让你可以完全控制每个跨度的结构和标记方式。当你需要自定义跨度名称、附加元数据、更简单的设置,或者解决 OpenTelemetry 生态系统中的限制或兼容性问题时,它会很有帮助。它还允许你根据查询上下文调整跟踪行为,这在复杂的应用中尤其有用。
¥Unlike the @prisma/instrumentation
package, which offers automatic tracing out of the box, this manual setup gives you full control over how each span is structured and tagged. It's helpful when you need custom span names, additional metadata, a simpler setup, or when working around limitations or compatibility issues in the OpenTelemetry ecosystem. It also allows you to adapt tracing behavior based on query context, which can be especially useful in complex applications.
5.2.添加执行查询的脚本
¥5.2. Add a script that performs queries
创建一个 src/index.ts
文件并添加代码以执行数据库查询并将跟踪发送到 Datadog:
¥Create a src/index.ts
file and add code to perform queries to your database and send traces to Datadog:
import { prisma } from "./client";
async function main() {
const user1Email = `alice${Date.now()}@prisma.io`;
const user2Email = `bob${Date.now()}@prisma.io`;
let alice, bob;
// 1. Create users concurrently
try {
[alice, bob] = await Promise.all([
prisma.user.create({
data: {
email: user1Email,
name: "Alice",
posts: {
create: {
title: "Join the Prisma community on Discord",
content: "https://pris.ly/discord",
published: true,
},
},
},
include: { posts: true },
}),
prisma.user.create({
data: {
email: user2Email,
name: "Bob",
posts: {
create: [
{
title: "Check out Prisma on YouTube",
content: "https://pris.ly/youtube",
published: true,
},
{
title: "Follow Prisma on Twitter",
content: "https://twitter.com/prisma/",
published: false,
},
],
},
},
include: { posts: true },
}),
]);
console.log(
`✅ Created users: ${alice.name} (${alice.posts.length} post) and ${bob.name} (${bob.posts.length} posts)`
);
} catch (err) {
console.error("❌ Error creating users:", err);
return;
}
// 2. Fetch all published posts
try {
const publishedPosts = await prisma.post.findMany({
where: { published: true },
});
console.log(`✅ Retrieved ${publishedPosts.length} published post(s).`);
} catch (err) {
console.error("❌ Error fetching published posts:", err);
}
// 3. Create & publish a post for Alice
let post;
try {
post = await prisma.post.create({
data: {
title: "Join the Prisma Discord community",
content: "https://pris.ly/discord",
published: false,
author: { connect: { email: user1Email } },
},
});
console.log(`✅ Created draft post for Alice (ID: ${post.id})`);
} catch (err) {
console.error("❌ Error creating draft post for Alice:", err);
return;
}
try {
post = await prisma.post.update({
where: { id: post.id },
data: { published: true },
});
console.log("✅ Published Alice’s post:", post);
} catch (err) {
console.error("❌ Error publishing Alice's post:", err);
}
// 4. Fetch all posts by Alice
try {
const alicePosts = await prisma.post.findMany({
where: { author: { email: user1Email } },
});
console.log(
`✅ Retrieved ${alicePosts.length} post(s) by Alice.`,
alicePosts
);
} catch (err) {
console.error("❌ Error fetching Alice's posts:", err);
}
}
// Entrypoint
main()
.catch((err) => {
console.error("❌ Unexpected error:", err);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
console.log("🔌 Disconnected from database.");
});
6. 运行查询并查看跟踪
¥ Run your queries and see the traces
运行查询:
¥Run the queries:
npx tsx src/index.ts
这将执行你的脚本,该脚本:
¥This executes your script, which:
-
注册 Datadog 追踪器。
¥Registers the Datadog tracer.
-
执行多个 Prisma 查询。
¥Performs multiple Prisma queries.
-
记录每个操作的结果。
¥Logs the result of each operation.
然后,在 Datadog 中确认跟踪:
¥Then, confirm the traces in Datadog:
-
打开你的 Datadog APM 页面。
¥Open your Datadog APM page.
-
在侧面板中导航至“APM”>“Traces”>“Explorer”。
¥Navigate to APM > Traces > Explorer in the side panel.
-
浏览 traces 和 spans 列表,每个 traces 和 spans 代表一个 Prisma 查询(例如
prisma:query
)。¥Explore the list of traces and spans, each representing a Prisma query (e.g.
prisma:query
).
根据你的 Datadog 设置,新数据可能需要一两分钟才会显示。如果你没有立即看到跟踪,请刷新或稍等片刻。
¥Depending on your Datadog setup, it may take a minute or two for new data to appear. Refresh or wait briefly if you do not see traces right away.
下一步
¥Next steps
你已成功:
¥You have successfully:
-
使用 Prisma Postgres 创建了一个 Prisma ORM 项目。
¥Created a Prisma ORM project with Prisma Postgres.
-
使用
@prisma/instrumentation
和dd-trace
设置 Datadog 追踪。¥Set up Datadog tracing using
@prisma/instrumentation
anddd-trace
. -
已验证数据库操作在 Datadog 中是否显示为跨度。
¥Verified that database operations show up as spans in Datadog.
为了进一步提高你的可观察性:
¥To improve your observability further:
-
为你的 HTTP 服务器或其他服务(例如 Express、Fastify)添加更多检测工具。
¥Add more instrumentation for your HTTP server or other services (e.g., Express, Fastify).
-
创建仪表板以查看 会从你的数据中提取关键指标。
¥Create Dashboards to view key metrics from your data.
更多指导,请参阅:
¥For additional guidance, check out:
Stay connected with Prisma
Continue your Prisma journey by connecting with our active community. Stay informed, get involved, and collaborate with other developers:
- Follow us on X for announcements, live events and useful tips.
- Join our Discord to ask questions, talk to the community, and get active support through conversations.
- Subscribe on YouTube for tutorials, demos, and streams.
- Engage on GitHub by starring the repository, reporting issues, or contributing to an issue.