OpenTelemetry 追蹤
追蹤功能提供 Prisma Client 在操作層級執行的活動詳細日誌,包括執行每個查詢所花費的時間。它可以幫助您分析應用程式的效能並找出瓶頸。追蹤功能完全符合 OpenTelemetry 規範,因此您可以將其用作端對端應用程式追蹤系統的一部分。
追蹤功能為您提供關於 Prisma ORM 專案的高度詳細操作層級的洞察。如果您想要彙總的數值報告,例如查詢計數、連線計數和總查詢執行時間,請參閱 指標。
關於追蹤
當您啟用追蹤功能時,Prisma Client 會輸出以下內容
- Prisma Client 執行的每個操作(例如 findMany)都會產生一個追蹤。
- 在每個追蹤中,包含一個或多個跨度。每個跨度代表操作的某個階段所花費的時間長度,例如序列化或資料庫查詢。跨度以樹狀結構表示,其中子跨度表示執行發生在較大的父跨度內。
追蹤中的跨度數量和類型取決於追蹤涵蓋的操作類型,但範例說明如下
您可以將追蹤輸出傳送到主控台,或在任何與 OpenTelemetry 相容的追蹤系統(例如 Jaeger、Honeycomb 和 Datadog)中進行分析。在本頁面上,我們提供如何將追蹤輸出傳送到 Jaeger 的範例,您可以在本機執行。
追蹤輸出
對於每個追蹤,Prisma Client 會輸出一系列的跨度。這些跨度的數量和類型取決於 Prisma Client 操作。典型的 Prisma 追蹤具有以下跨度
prisma:client:operation
:代表整個 Prisma Client 操作,從 Prisma Client 到資料庫再返回。它包含諸如 Prisma Client 呼叫的模型和方法等詳細資訊。根據 Prisma 操作,它包含以下一個或多個跨度prisma:client:connect
:代表 Prisma Client 連接到資料庫所需的時間。prisma:client:serialize
:代表驗證和轉換 Prisma Client 操作為查詢引擎的查詢所需的時間。prisma:engine:query
:代表查詢在查詢引擎中所需的時間。prisma:engine:connection
:代表 Prisma Client 取得資料庫連線所需的時間。prisma:engine:db_query
:代表針對資料庫執行的資料庫查詢。它在標籤中包含查詢,以及查詢執行所需的時間。prisma:engine:serialize
:代表將來自資料庫的原始回應轉換為型別化結果所需的時間。prisma:engine:response_json_serialization
:代表將資料庫查詢結果序列化為對 Prisma Client 的 JSON 回應所需的時間。
例如,假設有以下 Prisma Client 程式碼
prisma.user.findMany({
where: {
email: email,
},
include: {
posts: true,
},
})
追蹤結構如下
prisma:client:operation
prisma:client:serialize
prisma:engine:query
prisma:engine:connection
prisma:engine:db_query
:第一個 SQL 查詢或命令的詳細資訊...prisma:engine:db_query
:...下一個 SQL 查詢或命令的詳細資訊...prisma:engine:serialize
prisma:engine:response_json_serialization
考量與先決條件
如果您的應用程式將大量跨度傳送到收集器,這可能會對效能產生重大影響。有關如何最大限度地減少這種影響的資訊,請參閱降低效能影響。
若要使用追蹤功能,您必須執行以下操作
開始使用 Prisma ORM 中的追蹤功能
本節說明如何在您的應用程式中安裝和註冊追蹤功能。
步驟 1. 安裝最新的 Prisma ORM 相依性
使用 prisma
、@prisma/client
和 @prisma/instrumentation
npm 套件的 6.1.0 或更新版本。您還需要安裝 @opentelemetry/api
套件,因為它是同層級相依性。
npm install prisma@latest --save-dev
npm install @prisma/client@latest --save
npm install @prisma/instrumentation@latest --save
npm install @opentelemetry/api@latest --save
在先前版本的 Prisma ORM 上進行追蹤
追蹤功能在 Prisma ORM 的 4.2.0 版本中作為預覽功能新增。對於 4.2.0 到 6.1.0 之間的 Prisma ORM 版本,您需要在 Prisma schema 檔案中啟用 tracing
預覽功能。
generator client {
provider = "prisma-client-js"
previewFeatures = ["tracing"]
}
步驟 2:安裝 OpenTelemetry 套件
現在安裝適當的 OpenTelemetry 套件,如下所示
npm install @opentelemetry/semantic-conventions @opentelemetry/exporter-trace-otlp-http @opentelemetry/sdk-trace-base @opentelemetry/sdk-trace-node @opentelemetry/resources
步驟 3:在您的應用程式中註冊追蹤功能
以下程式碼提供了在 Prisma 中設定 OpenTelemetry 追蹤功能的兩個範例
- 使用
@opentelemetry/sdk-trace-node
(現有範例),它提供對追蹤設定的細緻控制。 - 使用
@opentelemetry/sdk-node
,它提供更簡單的配置,並與 OpenTelemetry 的 JavaScript 入門指南保持一致。
選項 1:使用 @opentelemetry/sdk-trace-node
此設定可讓您對檢測和追蹤進行細緻的控制。您需要為您的特定應用程式自訂此配置。對於需要快速設定以將追蹤傳送到與 OTLP 相容的後端(例如 Honeycomb、Jaeger 或 Datadog)的使用者來說,此方法簡潔且更容易。
// Imports
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'
import { PrismaInstrumentation, registerInstrumentations } from '@prisma/instrumentation'
import { Resource } from '@opentelemetry/resources'
// Configure the trace provider
const provider = new NodeTracerProvider({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: 'example application', // Replace with your service name
[SEMRESATTRS_SERVICE_VERSION]: '0.0.1', // Replace with your service version
}),
})
// Configure how spans are processed and exported. In this case, we're sending spans
// as we receive them to an OTLP-compatible collector (e.g., Jaeger).
provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter()))
// Register your auto-instrumentors
registerInstrumentations({
tracerProvider: provider,
instrumentations: [new PrismaInstrumentation()],
})
// Register the provider globally
provider.register()
此方法提供最大的靈活性,但可能涉及額外的配置步驟。
選項 2:使用 @opentelemetry/sdk-node
對於許多使用者,尤其是初學者,NodeSDK
類別透過將常見的預設值捆綁到單一統一配置中,簡化了 OpenTelemetry 設定。
// Imports
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'
import { NodeSDK } from '@opentelemetry/sdk-node'
import { PrismaInstrumentation } from '@prisma/instrumentation'
// Configure the OTLP trace exporter
const traceExporter = new OTLPTraceExporter({
url: 'https://api.honeycomb.io/v1/traces', // Replace with your collector's endpoint
headers: {
'x-honeycomb-team': 'HONEYCOMB_API_KEY', // Replace with your Honeycomb API key or collector auth header
},
})
// Initialize the NodeSDK
const sdk = new NodeSDK({
serviceName: 'my-service-name', // Replace with your service name
traceExporter,
instrumentations: [
new PrismaInstrumentation({
middleware: true, // Enable middleware tracing if needed
}),
],
})
// Start the SDK
sdk.start()
// Handle graceful shutdown
process.on('SIGTERM', async () => {
try {
await sdk.shutdown()
console.log('Tracing shut down successfully')
} catch (err) {
console.error('Error shutting down tracing', err)
} finally {
process.exit(0)
}
})
如果符合以下條件,請選擇 NodeSDK
方法
- 您剛開始使用 OpenTelemetry,並且想要簡化的設定。
- 您需要快速整合追蹤功能,並儘可能減少樣板程式碼。
- 您正在使用與 OTLP 相容的追蹤後端,例如 Honeycomb、Jaeger 或 Datadog。
如果符合以下條件,請選擇 NodeTracerProvider
方法
- 您需要詳細控制跨度的建立、處理和匯出方式。
- 您正在使用自訂跨度處理器或匯出器。
- 您的應用程式需要特定的檢測或取樣策略。
OpenTelemetry 具有高度可配置性。您可以自訂資源屬性、要檢測的組件、跨度的處理方式以及跨度的傳送位置。
您可以在此範例應用程式中找到包含指標的完整範例。
追蹤功能操作指南
使用 Jaeger 可視化追蹤
Jaeger 是一個免費且開源的 OpenTelemetry 收集器和儀表板,您可以使用它來可視化您的追蹤。
以下螢幕截圖顯示了追蹤可視化的範例
若要在本機執行 Jaeger,請使用以下 Docker 命令
docker run --rm --name jaeger -d -e COLLECTOR_OTLP_ENABLED=true -p 16686:16686 -p 4318:4318 jaegertracing/all-in-one:latest
現在您可以在 https://127.0.0.1:16686/
找到可用的追蹤儀表板。當您在啟用追蹤功能的情況下使用應用程式時,您將開始在此儀表板中看到追蹤。
將追蹤輸出傳送到主控台
以下範例使用來自 @opentelemetry/sdk-trace-base
的 ConsoleSpanExporter
將追蹤輸出傳送到主控台。
// Imports
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
import {
BasicTracerProvider,
ConsoleSpanExporter,
SimpleSpanProcessor,
} from '@opentelemetry/sdk-trace-base'
import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'
import * as api from '@opentelemetry/api'
import { PrismaInstrumentation, registerInstrumentations } from '@prisma/instrumentation'
import { Resource } from '@opentelemetry/resources'
// Export the tracing
export function otelSetup() {
const contextManager = new AsyncHooksContextManager().enable()
api.context.setGlobalContextManager(contextManager)
//Configure the console exporter
const consoleExporter = new ConsoleSpanExporter()
// Configure the trace provider
const provider = new BasicTracerProvider({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'test-tracing-service',
[SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0',
}),
})
// Configure how spans are processed and exported. In this case we're sending spans
// as we receive them to the console
provider.addSpanProcessor(new SimpleSpanProcessor(consoleExporter))
// Register your auto-instrumentors
registerInstrumentations({
tracerProvider: provider,
instrumentations: [new PrismaInstrumentation()],
})
// Register the provider
provider.register()
}
追蹤 Prisma Client 中介軟體
預設情況下,追蹤功能不會輸出 Prisma Client 中介軟體的跨度。若要在追蹤中包含您的中介軟體,請在您的 registerInstrumentations
語句中將 middleware
設定為 true
,如下所示
registerInstrumentations({
instrumentations: [new PrismaInstrumentation({ middleware: true })],
})
這將在您的追蹤中新增以下跨度類型
prisma:client:middleware
:代表操作在您的中介軟體中花費的時間。
追蹤互動式交易
當您執行互動式交易時,除了標準跨度之外,您還會看到以下跨度
prisma:client:transaction
:一個包裝prisma
跨度的根跨度。prisma:engine:itx_runner
:代表互動式交易在查詢引擎中所需的時間。prisma:engine:itx_query_builder
:代表建構互動式交易所需的時間。
作為範例,採用以下 Prisma schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
}
model Audit {
id Int @id
table String
action String
}
假設有以下互動式交易
await prisma.$transaction(async (tx) => {
const user = await tx.user.create({
data: {
email: email,
},
})
await tx.audit.create({
data: {
table: 'user',
action: 'create',
id: user.id,
},
})
return user
})
追蹤結構如下
prisma:client:transaction
prisma:client:connect
prisma:engine:itx_runner
prisma:engine:connection
prisma:engine:db_query
prisma:engine:itx_query_builder
prisma:engine:db_query
prisma:engine:db_query
prisma:engine:serialize
prisma:engine:itx_query_builder
prisma:engine:db_query
prisma:engine:db_query
prisma:engine:serialize
prisma:client:operation
prisma:client:serialize
prisma:client:operation
prisma:client:serialize
新增更多檢測
OpenTelemetry 的一個優點是能夠以最少的應用程式程式碼變更新增更多檢測。
例如,若要新增 HTTP 和 ExpressJS 追蹤功能,請將以下檢測新增至您的 OpenTelemetry 配置。這些檢測為完整的請求-回應生命週期新增跨度。這些跨度會顯示您的 HTTP 請求所花費的時間。
// Imports
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express'
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'
// Register your auto-instrumentors
registerInstrumentations({
tracerProvider: provider,
instrumentations: [
new HttpInstrumentation(),
new ExpressInstrumentation(),
new PrismaInstrumentation(),
],
})
如需可用檢測的完整清單,請查看 OpenTelemetry 登錄檔。
自訂資源屬性
您可以透過變更資源屬性以使其更符合您的應用程式,來調整應用程式追蹤的分組方式
const provider = new NodeTracerProvider({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'weblog',
[SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0',
}),
})
目前正在努力標準化常見的資源屬性。在可能的情況下,最好遵循標準屬性名稱。
降低效能影響
如果您的應用程式將大量跨度傳送到收集器,這可能會對效能產生重大影響。您可以使用以下方法來減少這種影響
使用 BatchSpanProcessor 以批次方式傳送追蹤
在生產環境中,您可以使用 OpenTelemetry 的 BatchSpanProcessor
以批次方式將跨度傳送到收集器,而不是一次傳送一個。但是,在開發和測試期間,您可能不想以批次方式傳送跨度。在這種情況下,您可能更喜歡使用 SimpleSpanProcessor
。
您可以設定您的追蹤配置以使用適當的跨度處理器,具體取決於環境,如下所示
import {
SimpleSpanProcessor,
BatchSpanProcessor,
} from '@opentelemetry/sdk-trace-base'
if (process.env.NODE_ENV === 'production') {
provider.addSpanProcessor(new BatchSpanProcessor(otlpTraceExporter))
} else {
provider.addSpanProcessor(new SimpleSpanProcessor(otlpTraceExporter))
}
使用取樣將更少的跨度傳送到收集器
減少效能影響的另一種方法是使用機率取樣 將更少的跨度傳送到收集器。這降低了追蹤的收集成本,但仍然可以很好地表示您的應用程式中發生的情況。
範例實作如下所示
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'
import { TraceIdRatioBasedSampler } from '@opentelemetry/core'
import { Resource } from '@opentelemetry/resources'
const provider = new NodeTracerProvider({
sampler: new TraceIdRatioBasedSampler(0.1),
resource: new Resource({
// we can define some metadata about the trace resource
[SemanticResourceAttributes.SERVICE_NAME]: 'test-tracing-service',
[SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0',
}),
})
疑難排解追蹤功能
我的追蹤沒有顯示
您設定追蹤功能的順序很重要。在您的應用程式中,請確保在匯入任何檢測的相依性之前註冊追蹤功能和檢測。例如
import { registerTracing } from './tracing'
registerTracing({
name: 'tracing-example',
version: '0.0.1',
})
// You must import any dependencies after you register tracing.
import { PrismaClient } from '@prisma/client'
import async from 'express-async-handler'
import express from 'express'