メトリクス
Prismaクライアントのメトリクスは、Prismaクライアントがデータベースとどのようにやり取りしているかについて、詳細な洞察を提供します。この洞察は、アプリケーションのパフォーマンス問題の診断に役立てることができます。
Prismaクライアントのパフォーマンスについて、個々の操作レベルでさらに詳細な洞察が必要な場合は、トレーシングを参照してください。
メトリクスについて
メトリクスはJSONまたはPrometheus形式でエクスポートし、コンソールログで表示したり、StatsDやPrometheusのような外部メトリクスシステムに統合したりできます。外部メトリクスシステムに統合すると、時系列でメトリクスデータを表示できます。例えば、アプリケーションのアイドル接続数とアクティブ接続数がどのように変化するかを診断するのにメトリクスを利用できます。
Prismaクライアントは以下のメトリクスを提供します
-
カウンター(常に増加)
prisma_client_queries_total
: 実行されたPrismaクライアントクエリの合計数。prisma_datasource_queries_total
: 実行されたデータソースクエリの合計数(リレーショナルデータベースにおけるSQLクエリ、MongoDBにおけるコマンド)。prisma_datasource_queries_total
によって返される値はprisma_client_queries_total
よりも大きくなることがあります。これは、一部のPrismaクライアント操作が複数のクエリを生成するためです。
prisma_pool_connections_closed_total
: クローズされたプール接続の合計数。prisma_pool_connections_opened_total
: 現在開いているプール接続の数。
-
ゲージ(増減可能)
prisma_client_queries_active
: 現在アクティブなPrismaクライアントクエリの数。prisma_client_queries_wait
: すべての接続が使用中のため、現在接続待ちになっているPrismaクライアントクエリの数。prisma_pool_connections_busy
: 現在ビジー状態のプール接続の数。これらのプール接続は現在データソースクエリを実行中です。prisma_pool_connections_idle
: 現在使用されていないプール接続の数。これらのプール接続は次のデータソースクエリの実行を待っています。prisma_pool_connections_open
: 開いているプール接続の数。
-
ヒストグラム(値のコレクションに分割されたメトリクスデータ。コレクション内の各コンテナを「バケット」と呼びます)
prisma_client_queries_wait_histogram_ms
: すべてのPrismaクライアントクエリにおけるプール接続待ち時間(ms)。prisma_client_queries_duration_histogram_ms
: 実行されたすべてのPrismaクライアントクエリの実行時間(ms)。これには、すべてのデータベースクエリの実行にかかる時間、およびデータの結合や正しい形式へのデータ変換など、すべてのデータベースエンジン活動の実行にかかる時間が含まれます。prisma_datasource_queries_duration_histogram_ms
: 実行されたすべてのデータソースクエリの実行時間(ms)。
グローバルラベルをメトリクスデータに追加して、インフラストラクチャリージョンやサーバーなどでメトリクスをグループ化および分離できます。
前提条件
Prismaクライアントのメトリクスを使用するには、以下を行う必要があります
1. 最新のPrisma ORM依存関係をインストールする
prisma
および@prisma/client
npmパッケージのバージョン3.15.0
以上を使用してください。
npm install prisma@latest --save-dev
npm install @prisma/client@latest
2. Prismaスキーマファイルで機能フラグを有効にする
schema.prisma
ファイルのgenerator
ブロックで、metrics
機能フラグを有効にします
generator client {
provider = "prisma-client-js"
previewFeatures = ["metrics"]
}
JSON形式でメトリクスを取得する
JSON形式でメトリクスを取得する場合、返された形式でそれらを使用するか、時間の経過とともにどのように変化するかを視覚化するためにStatsDに送信することができます。
JSON形式でメトリクスを取得するには、アプリケーションコードに以下の行を追加します
const metrics = await prisma.$metrics.json()
console.log(metrics)
これにより、メトリクスは次のように返されます
{
"counters": [
{
"key": "prisma_client_queries_total",
"labels": {},
"value": 0,
"description": "Total number of Prisma Client queries executed"
},
{
"key": "prisma_datasource_queries_total",
"labels": {},
"value": 0,
"description": "Total number of Datasource Queries executed"
},
{
"key": "prisma_pool_connections_closed_total",
"labels": {},
"value": 0,
"description": "Total number of Pool Connections closed"
},
{
"key": "prisma_pool_connections_opened_total",
"labels": {},
"value": 1,
"description": "Total number of Pool Connections opened"
}
...
],
"gauges": [
...
],
"histograms": [
...
]
}
展開して全出力を表示
{
"counters": [
{
"key": "prisma_client_queries_total",
"labels": {},
"value": 2,
"description": "Total number of Prisma Client queries executed"
},
{
"key": "prisma_datasource_queries_total",
"labels": {},
"value": 5,
"description": "Total number of Datasource Queries executed"
},
{
"key": "prisma_pool_connections_open",
"labels": {},
"value": 1,
"description": "Number of currently open Pool Connections"
}
],
"gauges": [
{
"key": "prisma_client_queries_active",
"labels": {},
"value": 0,
"description": "Number of currently active Prisma Client queries"
},
{
"key": "prisma_client_queries_wait",
"labels": {},
"value": 0,
"description": "Number of Prisma Client queries currently waiting for a connection"
},
{
"key": "prisma_pool_connections_busy",
"labels": {},
"value": 0,
"description": "Number of currently busy Pool Connections (executing a datasource query)"
},
{
"key": "prisma_pool_connections_idle",
"labels": {},
"value": 21,
"description": "Number of currently unused Pool Connections (waiting for the next datasource query to run)"
},
{
"key": "prisma_pool_connections_open",
"labels": {},
"value": 1,
"description": "Number of currently open Pool Connections"
}
],
"histograms": [
{
"key": "prisma_client_queries_duration_histogram_ms",
"labels": {},
"value": {
"buckets": [
[0, 0],
[1, 0],
[5, 0],
[10, 1],
[50, 1],
[100, 0],
[500, 0],
[1000, 0],
[5000, 0],
[50000, 0]
],
"sum": 47.430541000000005,
"count": 2
},
"description": "Histogram of the duration of all executed Prisma Client queries in ms"
},
{
"key": "prisma_client_queries_wait_histogram_ms",
"labels": {},
"value": {
"buckets": [
[0, 0],
[1, 3],
[5, 0],
[10, 0],
[50, 0],
[100, 0],
[500, 0],
[1000, 0],
[5000, 0],
[50000, 0]
],
"sum": 0.0015830000000000002,
"count": 3
},
"description": "Histogram of the wait time of all Prisma Client Queries in ms"
},
{
"key": "prisma_datasource_queries_duration_histogram_ms",
"labels": {},
"value": {
"buckets": [
[0, 0],
[1, 0],
[5, 2],
[10, 2],
[50, 1],
[100, 0],
[500, 0],
[1000, 0],
[5000, 0],
[50000, 0]
],
"sum": 47.134498,
"count": 5
},
"description": "Histogram of the duration of all executed Datasource Queries in ms"
}
]
}
JSONデータ内のヒストグラム
各ヒストグラムの「バケット」には2つの値があります。最初の値はバケットの上限であり、2番目の値はカウント(そのバケットに該当するデータ値の数)です。以下の例では、11から20の間に2つの値、21から30の間に5つの値のインスタンスがあります。
...
[20, 2],
[30, 5],
...
StatsDでPrismaクライアントメトリクスを使用する
JSON形式のメトリクスをStatsDに送信して、時系列でメトリクスデータを視覚化できます。
注:カウンターメトリクスをStatsDに提供するには、以前のメトリクス取得からの増分または減分された値の系列として提供する必要があります。しかし、Prisma Clientのカウンターメトリクスは絶対値を返します。したがって、カウンターメトリクスを増分および減分された値の系列に変換し、ゲージデータとしてStatsDに送信する必要があります。以下のコード例では、diffHistograms
でカウンターメトリクスを増分および減分されたゲージデータに変換しています。
以下の例では、10秒ごとにStatsDにメトリクスを送信しています。このタイミングは、StatsDのデフォルトの10秒のフラッシュレートと一致します。
import StatsD from 'hot-shots'
let statsd = new StatsD({
port: 8125,
})
const diffMetrics = (metrics: Metric<MetricHistogram>[]) => {
return metrics.map((metric) => {
let prev = 0;
const diffBuckets = metric.value.buckets.map<MetricHistogramBucket>(
(values) => {
const [bucket, value] = values
const diff = value - prev
prev = value
return [bucket, diff]
}
)
metric.value.buckets = diffBuckets
return metric
})
}
let previousHistograms: Metric<MetricHistogram>[] = []
const statsdSender = async () => {
const metrics = await prisma.$metrics.json()
metrics.counters.forEach((counter: any) => {
statsd.gauge('prisma.' + counter.key, counter.value, (...res) => {})
});
metrics.gauges.forEach((counter: any) => {
statsd.gauge('prisma.' + counter.key, counter.value, (...res) => {})
})
if (!previousHistograms.length) {
previousHistograms = diffMetrics(metrics.histograms)
return
}
const diffHistograms = diffMetrics(metrics.histograms);
diffHistograms.forEach((diffHistogram, histogramIndex) => {
diffHistogram.value.buckets.forEach((values, bucketIndex) => {
const [bucket, count] = values
const [_, prev] =
previousHistograms[histogramIndex].value.buckets[bucketIndex]
const change = count - prev
for (let sendTimes = 0; sendTimes < change; sendTimes++) {
statsd.timing('prisma.' + diffHistograms.key, bucket)
}
})
})
previousHistograms = diffHistograms
}
setInterval(async () => await statsdSender(), 10000)
Prometheus形式でメトリクスを取得する
Prometheus形式でPrismaクライアントメトリクスを取得する場合、返された形式でそれらを使用するか、時間の経過とともにどのように変化するかを視覚化するためにPrometheusメトリクスシステムに送信することができます。
Prometheus形式でメトリクスを取得するには、アプリケーションコードに以下の行を追加します
const metrics = await prisma.$metrics.prometheus()
console.log(metrics)
これにより、メトリクスは次のように返されます
# HELP prisma_client_queries_total Total number of Prisma Client queries executed
# TYPE prisma_client_queries_total counter
prisma_client_queries_total 14
...
# HELP prisma_pool_connections_busy The number of active connections in use.
# TYPE prisma_pool_connections_busy gauge
prisma_pool_connections_busy 0
...
# HELP prisma_client_queries_wait_histogram_ms The wait time for a worker to get a connection.
# TYPE prisma_client_queries_wait_histogram_ms histogram
prisma_client_queries_wait_histogram_ms_bucket{le="0"} 0
prisma_client_queries_wait_histogram_ms_bucket{le="1"} 3
展開して全出力を表示
# HELP query_total_operations
# TYPE query_total_operations counter
query_total_operations 2
# HELP prisma_datasource_queries_total
# TYPE prisma_datasource_queries_total counter
prisma_datasource_queries_total 28
# HELP prisma_pool_connections_closed_total Total number of Pool Connections closed
# TYPE prisma_pool_connections_closed_total counter
prisma_pool_connections_closed_total 0
# HELP prisma_pool_connections_opened_total Total number of Pool Connections opened
# TYPE prisma_pool_connections_opened_total counter
prisma_pool_connections_opened_total 0
# HELP prisma_client_queries_active Number of currently active Prisma Client queries
# TYPE prisma_client_queries_active gauge
prisma_client_queries_active 0
# HELP prisma_client_queries_wait Number of queries currently waiting for a connection
# TYPE prisma_client_queries_wait gauge
prisma_client_queries_wait 0
# HELP prisma_pool_connections_busy Number of currently busy Pool Connections (executing a datasource query)
# TYPE prisma_pool_connections_busy gauge
prisma_pool_connections_busy 0
# HELP prisma_pool_connections_idle Number of currently unused Pool Connections (waiting for the next pool query to run)
# TYPE prisma_pool_connections_idle gauge
prisma_pool_connections_idle 21
# HELP prisma_pool_connections_open Number of currently open Pool Connections
# TYPE prisma_pool_connections_open gauge
prisma_pool_connections_open 1
# HELP prisma_pool_connections_open Number of currently open Pool Connections (able to execute a datasource query)
# TYPE prisma_pool_connections_open gauge
prisma_pool_connections_open 0
# HELP prisma_client_queries_wait_histogram_ms The wait time for a worker to get a connection.
# TYPE prisma_client_queries_wait_histogram_ms histogram
prisma_client_queries_wait_histogram_ms_bucket{le="0"} 0
prisma_client_queries_wait_histogram_ms_bucket{le="1"} 3
prisma_client_queries_wait_histogram_ms_bucket{le="5"} 3
prisma_client_queries_wait_histogram_ms_bucket{le="10"} 3
prisma_client_queries_wait_histogram_ms_bucket{le="50"} 3
prisma_client_queries_wait_histogram_ms_bucket{le="100"} 3
prisma_client_queries_wait_histogram_ms_bucket{le="500"} 3
prisma_client_queries_wait_histogram_ms_bucket{le="1000"} 3
prisma_client_queries_wait_histogram_ms_bucket{le="5000"} 3
prisma_client_queries_wait_histogram_ms_bucket{le="50000"} 3
prisma_client_queries_wait_histogram_ms_bucket{le="+Inf"} 3
prisma_client_queries_wait_histogram_ms_sum 0.023208
prisma_client_queries_wait_histogram_ms_count 3
# HELP prisma_client_queries_duration_histogram_ms Histogram of the duration of all executed Prisma Client queries in ms
# TYPE prisma_client_queries_duration_histogram_ms histogram
prisma_client_queries_duration_histogram_ms_bucket{le="0"} 0
prisma_client_queries_duration_histogram_ms_bucket{le="1"} 1
prisma_client_queries_duration_histogram_ms_bucket{le="5"} 2
prisma_client_queries_duration_histogram_ms_bucket{le="10"} 2
prisma_client_queries_duration_histogram_ms_bucket{le="50"} 2
prisma_client_queries_duration_histogram_ms_bucket{le="100"} 2
prisma_client_queries_duration_histogram_ms_bucket{le="500"} 2
prisma_client_queries_duration_histogram_ms_bucket{le="1000"} 2
prisma_client_queries_duration_histogram_ms_bucket{le="5000"} 2
prisma_client_queries_duration_histogram_ms_bucket{le="50000"} 2
prisma_client_queries_duration_histogram_ms_bucket{le="+Inf"} 2
prisma_client_queries_duration_histogram_ms_sum 3.197624
prisma_client_queries_duration_histogram_ms_count 2
# HELP prisma_datasource_queries_duration_histogram_ms Histogram of the duration of all executed Datasource Queries in ms
# TYPE prisma_datasource_queries_duration_histogram_ms histogram
prisma_datasource_queries_duration_histogram_ms_bucket{le="0"} 0
prisma_datasource_queries_duration_histogram_ms_bucket{le="1"} 5
prisma_datasource_queries_duration_histogram_ms_bucket{le="5"} 5
prisma_datasource_queries_duration_histogram_ms_bucket{le="10"} 5
prisma_datasource_queries_duration_histogram_ms_bucket{le="50"} 5
prisma_datasource_queries_duration_histogram_ms_bucket{le="100"} 5
prisma_datasource_queries_duration_histogram_ms_bucket{le="500"} 5
prisma_datasource_queries_duration_histogram_ms_bucket{le="1000"} 5
prisma_datasource_queries_duration_histogram_ms_bucket{le="5000"} 5
prisma_datasource_queries_duration_histogram_ms_bucket{le="50000"} 5
prisma_datasource_queries_duration_histogram_ms_bucket{le="+Inf"} 5
prisma_datasource_queries_duration_histogram_ms_sum 1.8407059999999997
prisma_datasource_queries_duration_histogram_ms_count 5
histogram
型のメトリクスは、Prometheus形式で3つの異なるクラスの値を公開します
-
観測バケットの複数の累積カウンター。これらのカウンターには、
_bucket{le="<upper inclusive bound>"}
がサフィックスとして付きます。例えば、prisma_datasource_queries_duration_histogram_ms
はprisma_datasource_queries_duration_histogram_ms_bucket{le="1"}
として公開されるカウンターを持ちます。観測された値がバケットの上限値以下である場合、Prisma Clientメトリクスはそのバケットを1ずつ増加させます。例えば、上限値がそれぞれ0、1、5、10、50のバケットがあるとします。観測された値が5の場合、その値は0より大きく1より大きいが、5、10、50以下であるため、Prisma Clientメトリクスは3番目のバケット以降を増加させます。
-
すべての観測値の単一の合計値。このカウンターには
_sum
がサフィックスとして付きます。例えば、prisma_datasource_queries_duration_histogram_ms
の合計値はprisma_datasource_queries_duration_histogram_ms_sum
として公開されます。 -
観測されたイベントの数の**カウント**。このカウンターには
_count
がサフィックスとして付きます。例えば、prisma_datasource_queries_duration_histogram_ms
イベントの合計カウントはprisma_datasource_queries_duration_histogram_ms_count
として公開されます。
詳細については、メトリクスタイプに関するPrometheusドキュメントを参照してください。
PrometheusメトリクスシステムでPrismaクライアントメトリクスを使用する
ほとんどの場合、Prometheusはメトリクスを取得するためにエンドポイントをスクレイピングする必要があります。以下の例は、Express.js
を使用してデータを送信する方法を示しています。
import { PrismaClient } from '@prisma/client'
import express, { Request, Response } from 'express'
const app = express()
const port = 4000
const prisma = new PrismaClient()
app.get('/metrics', async (_req, res: Response) => {
const metrics = await prisma.$metrics.prometheus()
res.end(metrics)
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
以下の例は、Prisma Clientメトリクスを、Express.js
と組み合わせてREST APIエンドポイントと共に提供される他のPrometheusクライアントライブラリと結合する方法を示しています。
import { PrismaClient } from '@prisma/client'
import express, { Request, Response } from 'express'
import prom from 'prom-client'
const app = express()
const port = 4000
const prisma = new PrismaClient()
const register = new prom.Registry()
prom.collectDefaultMetrics({ register })
app.get('/metrics', async (_req, res: Response) => {
const prismaMetrics = await prisma.$metrics.prometheus()
const appMetrics = await register.metrics()
res.end(prismaMetrics + appMetrics)
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
グローバルラベル
メトリクスにグローバルラベルを追加して、メトリクスをグループ化および分離できます。Prisma Clientの各インスタンスは、生成するメトリクスにこれらのラベルを追加します。例えば、{ server: us_server1', 'app_version': 'one' }
のようなラベルを使用して、インフラストラクチャリージョンやサーバーごとにメトリクスをグループ化できます。
グローバルラベルはJSONおよびPrometheus形式のメトリクスで機能します。
例えば、JSON形式のメトリクスにグローバルラベルを追加するには、アプリケーションに以下のコードを追加します
const metrics = prisma.$metrics.json({
globalLabels: { server: 'us_server1', app_version: 'one' },
})
console.log(metrics)
これにより、情報は以下の形式で返されます
{
"counters": [
{
"key": "query_total_operations",
"labels": { "server": "us_server1", "app_version": "one" },
"value": 0,
"description": "The total number of operations executed"
},
{
"key": "prisma_datasource_queries_total",
"labels": { "server": "us_server1", "app_version": "one" },
"value": 0,
"description": "The total number of queries executed"
},
...
],
"gauges": [
...
],
"histograms": [
...
]
}