Metrics
Prisma Client metrics give you a detailed insight into how Prisma Client interacts with your database. You can use this insight to help diagnose performance issues with your application.
If you want an even more detailed insight into your Prisma Client's performance, at the level of individual operations, see Tracing.
About metrics
You can export metrics in JSON or Prometheus formats and view them in a console log, or integrate them into an external metrics system, such as StatsD or Prometheus. If you integrate them into an external metrics system, then you can view the metrics data over time. For example, you can use metrics to help diagnose how your application's number of idle and active connections changes.
Prisma Client provides the following metrics:
-
Counters (always increase):
prisma_client_queries_total
: The total number of Prisma Client queries executed.prisma_datasource_queries_total
: The total number of datasource queries executed (SQL queries in relational databases, and commands in MongoDB).- The value returned by
prisma_datasource_queries_total
can be greater thanprisma_client_queries_total
, because some Prisma Client operations create multiple queries.
- The value returned by
prisma_pool_connections_closed_total
: The total number of pool connections closed.prisma_pool_connections_opened_total
: The number of currently open pool connections.
-
Gauges (can increase or decrease):
prisma_client_queries_active
: The number of currently active Prisma Client queries.prisma_client_queries_wait
: The number of Prisma Client queries currently waiting for a connection because all connections are in use.prisma_pool_connections_busy
: The number of currently busy pool connections. These pool connections are currently executing a datasource query.prisma_pool_connections_idle
: The number of pool connections that are not currently being used. These pool connections are waiting for the next datasource query to run.prisma_pool_connections_open
: The number of pool connections open.
-
Histograms (metrics data divided into a collection of values; we call each container in the collection a "bucket"):
prisma_client_queries_wait_histogram_ms
: The time waiting for a pool connection for all Prisma Client queries in ms.prisma_client_queries_duration_histogram_ms
: The execution time for all executed Prisma Client queries in ms. This includes the time taken to execute all database queries, and to carry out all database engine activities, such as joining data and transforming data to the correct format.prisma_datasource_queries_duration_histogram_ms
: The execution time for all executed Datasource queries in ms.
You can add global labels to your metrics data to help you group and separate your metrics, for example by infrastructure region or server.
Prerequisites
To use Prisma Client metrics, you must do the following:
Step 1. Install up-to-date Prisma ORM dependencies
Use version 3.15.0
or higher of the prisma
and @prisma/client
npm packages.
npm install prisma@latest --save-dev
npm install @prisma/client@latest --save
Step 2: Enable the feature flag in the Prisma schema file
In the generator
block of your schema.prisma
file, enable the metrics
feature flag:
generator client {
provider = "prisma-client-js"
previewFeatures = ["metrics"]
}
Retrieve metrics in JSON format
When you retrieve metrics in JSON format, you can use them in the format they are returned, or send them to StatSD to visualize how they change over time.
To retrieve metrics in JSON format, add the following lines to your application code:
const metrics = await prisma.$metrics.json()
console.log(metrics)
This returns metrics as follows:
{
"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": [
...
]
}
Expand to view the full output
{
"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"
}
]
}
Histograms in JSON data
Each histogram "bucket" has two values. The first one is the upper bound of the bucket, and the second one is the count (the number of data values that fall into that bucket). In the following example, there are two instances of values between 11 and 20, and five instances of values between 21 and 30:
...
[20, 2],
[30, 5],
...
Use Prisma Client metrics with StatsD
You can send JSON-formatted metrics to StatsD to visualize your metrics data over time.
Note: You must provide counter metrics to StatsD as a series of values that are incremented or decremented from a previous retrieval of the metrics. However, Prisma Client's counter
metrics return absolute values. Therefore, you must convert your counter metrics to a series of incremented and decremented values and send them to StatsD as gauge data. In the code example below, we convert counter metrics into incremented and decremented gauge data in diffHistograms
.
In the following example, we send metrics to StatsD every 10 seconds. This timing aligns with the default 10s flush rate of StatsD.
import StatsD from 'hot-shots'
let statsd = new StatsD({
port: 8125,
})
let diffMetrics = (metrics: any) => {
return metrics.map((metric: any) => {
let prev = 0
let diffBuckets = metric.value.buckets.map((values: any) => {
let [bucket, value] = values
let diff = value - prev
prev = value
return [bucket, diff]
})
metric.value.buckets = diffBuckets
return metric
})
}
let previousHistograms: any = null
let statsdSender = async () => {
let 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 === null) {
previousHistograms = diffMetrics(metrics.histograms)
return
}
let diffHistograms = diffMetrics(metrics.histograms)
diffHistograms.forEach((diffHistograms: any, histogramIndex: any) => {
diffHistograms.value.buckets.forEach((values: any, bucketIndex: any) => {
let [bucket, count] = values
let [_, prev] =
previousHistograms[histogramIndex].value.buckets[bucketIndex]
let change = count - prev
for (let sendTimes = 0; sendTimes < change; sendTimes++) {
statsd.timing('prisma.' + diffHistograms.key, bucket)
}
})
})
previousHistograms = diffHistograms
}
setInterval(async () => await statsdSender(), 10000)