expose more prisma metrics

This commit is contained in:
nicktrn
2025-08-29 23:52:26 +01:00
parent 64cd327558
commit 23d1c3d179
+184 -12
View File
@@ -56,6 +56,7 @@ import { logger } from "~/services/logger.server";
import { flattenAttributes } from "@trigger.dev/core/v3";
import { prisma } from "~/db.server";
import { metricsRegister } from "~/metrics.server";
import type { Prisma } from "@trigger.dev/database";
export const SEMINTATTRS_FORCE_RECORDING = "forceRecording";
@@ -336,6 +337,33 @@ function setupMetrics() {
}
function configurePrismaMetrics({ meter }: { meter: Meter }) {
// Counters
const queriesTotal = meter.createObservableCounter("db.client.queries.total", {
description: "Total number of Prisma Client queries executed",
unit: "queries",
});
const datasourceQueriesTotal = meter.createObservableCounter("db.datasource.queries.total", {
description: "Total number of datasource queries executed",
unit: "queries",
});
const connectionsOpenedTotal = meter.createObservableCounter("db.pool.connections.opened.total", {
description: "Total number of pool connections opened",
unit: "connections",
});
const connectionsClosedTotal = meter.createObservableCounter("db.pool.connections.closed.total", {
description: "Total number of pool connections closed",
unit: "connections",
});
// Gauges
const queriesActive = meter.createObservableGauge("db.client.queries.active", {
description: "Number of currently active Prisma Client queries",
unit: "queries",
});
const queriesWait = meter.createObservableGauge("db.client.queries.wait", {
description: "Number of queries currently waiting for a connection",
unit: "queries",
});
const totalGauge = meter.createObservableGauge("db.pool.connections.total", {
description: "Open Prisma-pool connections",
unit: "connections",
@@ -349,26 +377,170 @@ function configurePrismaMetrics({ meter }: { meter: Meter }) {
unit: "connections",
});
// Histogram statistics as gauges
const queriesWaitTimeCount = meter.createObservableGauge("db.client.queries.wait_time.count", {
description: "Number of wait time observations",
unit: "observations",
});
const queriesWaitTimeSum = meter.createObservableGauge("db.client.queries.wait_time.sum", {
description: "Total wait time across all observations",
unit: "ms",
});
const queriesWaitTimeMean = meter.createObservableGauge("db.client.queries.wait_time.mean", {
description: "Average wait time for a connection",
unit: "ms",
});
const queriesDurationCount = meter.createObservableGauge("db.client.queries.duration.count", {
description: "Number of query duration observations",
unit: "observations",
});
const queriesDurationSum = meter.createObservableGauge("db.client.queries.duration.sum", {
description: "Total query duration across all observations",
unit: "ms",
});
const queriesDurationMean = meter.createObservableGauge("db.client.queries.duration.mean", {
description: "Average duration of Prisma Client queries",
unit: "ms",
});
const datasourceQueriesDurationCount = meter.createObservableGauge(
"db.datasource.queries.duration.count",
{
description: "Number of datasource query duration observations",
unit: "observations",
}
);
const datasourceQueriesDurationSum = meter.createObservableGauge(
"db.datasource.queries.duration.sum",
{
description: "Total datasource query duration across all observations",
unit: "ms",
}
);
const datasourceQueriesDurationMean = meter.createObservableGauge(
"db.datasource.queries.duration.mean",
{
description: "Average duration of datasource queries",
unit: "ms",
}
);
// Single helper so we hit Prisma only once per scrape ---------------------
async function readPoolCounters() {
const { gauges } = await prisma.$metrics.json();
async function readPrismaMetrics() {
const metrics = await prisma.$metrics.json();
const busy = gauges.find((g) => g.key === "prisma_pool_connections_busy")?.value ?? 0;
const free = gauges.find((g) => g.key === "prisma_pool_connections_idle")?.value ?? 0;
const total =
gauges.find((g) => g.key === "prisma_pool_connections_open")?.value ?? busy + free; // fallback compute
// Extract counter values
const counters: Record<string, number> = {};
for (const counter of metrics.counters) {
counters[counter.key] = counter.value;
}
return { total, busy, free };
// Extract gauge values
const gauges: Record<string, number> = {};
for (const gauge of metrics.gauges) {
gauges[gauge.key] = gauge.value;
}
// Extract histogram values
const histograms: Record<string, Prisma.MetricHistogram> = {};
for (const histogram of metrics.histograms) {
histograms[histogram.key] = histogram.value;
}
return {
counters: {
queriesTotal: counters["prisma_client_queries_total"] ?? 0,
datasourceQueriesTotal: counters["prisma_datasource_queries_total"] ?? 0,
connectionsOpenedTotal: counters["prisma_pool_connections_opened_total"] ?? 0,
connectionsClosedTotal: counters["prisma_pool_connections_closed_total"] ?? 0,
},
gauges: {
queriesActive: gauges["prisma_client_queries_active"] ?? 0,
queriesWait: gauges["prisma_client_queries_wait"] ?? 0,
connectionsOpen: gauges["prisma_pool_connections_open"] ?? 0,
connectionsBusy: gauges["prisma_pool_connections_busy"] ?? 0,
connectionsIdle: gauges["prisma_pool_connections_idle"] ?? 0,
},
histograms: {
queriesWait: histograms["prisma_client_queries_wait_histogram_ms"],
queriesDuration: histograms["prisma_client_queries_duration_histogram_ms"],
datasourceQueriesDuration: histograms["prisma_datasource_queries_duration_histogram_ms"],
},
};
}
meter.addBatchObservableCallback(
async (res) => {
const { total, busy, free } = await readPoolCounters();
res.observe(totalGauge, total);
res.observe(busyGauge, busy);
res.observe(freeGauge, free);
const { counters, gauges, histograms } = await readPrismaMetrics();
// Observe counters
res.observe(queriesTotal, counters.queriesTotal);
res.observe(datasourceQueriesTotal, counters.datasourceQueriesTotal);
res.observe(connectionsOpenedTotal, counters.connectionsOpenedTotal);
res.observe(connectionsClosedTotal, counters.connectionsClosedTotal);
// Observe gauges
res.observe(queriesActive, gauges.queriesActive);
res.observe(queriesWait, gauges.queriesWait);
res.observe(totalGauge, gauges.connectionsOpen);
res.observe(busyGauge, gauges.connectionsBusy);
res.observe(freeGauge, gauges.connectionsIdle);
// Observe histogram statistics as gauges
if (histograms.queriesWait) {
res.observe(queriesWaitTimeCount, histograms.queriesWait.count);
res.observe(queriesWaitTimeSum, histograms.queriesWait.sum);
res.observe(
queriesWaitTimeMean,
histograms.queriesWait.count > 0
? histograms.queriesWait.sum / histograms.queriesWait.count
: 0
);
}
if (histograms.queriesDuration) {
res.observe(queriesDurationCount, histograms.queriesDuration.count);
res.observe(queriesDurationSum, histograms.queriesDuration.sum);
res.observe(
queriesDurationMean,
histograms.queriesDuration.count > 0
? histograms.queriesDuration.sum / histograms.queriesDuration.count
: 0
);
}
if (histograms.datasourceQueriesDuration) {
res.observe(datasourceQueriesDurationCount, histograms.datasourceQueriesDuration.count);
res.observe(datasourceQueriesDurationSum, histograms.datasourceQueriesDuration.sum);
res.observe(
datasourceQueriesDurationMean,
histograms.datasourceQueriesDuration.count > 0
? histograms.datasourceQueriesDuration.sum / histograms.datasourceQueriesDuration.count
: 0
);
}
},
[totalGauge, busyGauge, freeGauge]
[
queriesTotal,
datasourceQueriesTotal,
connectionsOpenedTotal,
connectionsClosedTotal,
queriesActive,
queriesWait,
totalGauge,
busyGauge,
freeGauge,
queriesWaitTimeCount,
queriesWaitTimeSum,
queriesWaitTimeMean,
queriesDurationCount,
queriesDurationSum,
queriesDurationMean,
datasourceQueriesDurationCount,
datasourceQueriesDurationSum,
datasourceQueriesDurationMean,
]
);
}