Skip to content

Instantly share code, notes, and snippets.

@anuraaga
Created November 7, 2023 07:08
Show Gist options
  • Save anuraaga/1e50f8b2382628287dd486550322393c to your computer and use it in GitHub Desktop.
Save anuraaga/1e50f8b2382628287dd486550322393c to your computer and use it in GitHub Desktop.
Exporting prisma metrics with OTel
const prismaProducer = new PrismaMetricProducer();
export function setPrisma(prisma: PrismaClient) {
prismaProducer.client = prisma;
}
const metricReader = new PeriodicExportingMetricReader({
exportIntervalMillis: 10_000,
exporter: metricExporter,
metricProducers: [prismaProducer],
})
export const otelSdk = new NodeSDK({
instrumentations: [
...
new PrismaInstrumentation(),
],
metricReader,
...
});
otelSdk.start();
import { PrismaClient } from 'generatedprisma';
import {
AggregationTemporality,
CollectionResult,
DataPointType,
InstrumentType,
MetricCollectOptions,
ScopeMetrics,
} from '@opentelemetry/sdk-metrics';
import { Resource } from '@opentelemetry/resources';
import { HrTime, ValueType } from '@opentelemetry/api';
import { hrTime } from '@opentelemetry/core';
export class PrismaMetricProducer {
client?: PrismaClient;
private readonly startTime: HrTime = hrTime();
async collect(options?: MetricCollectOptions): Promise<CollectionResult> {
const result: CollectionResult = {
resourceMetrics: {
resource: Resource.EMPTY,
scopeMetrics: [],
},
errors: [],
};
if (!this.client) {
return result;
}
const endTime = hrTime();
const metrics = await this.client.$metrics.json();
const scopeMetrics: ScopeMetrics = {
scope: {
name: 'prisma',
},
metrics: [],
};
for (const counter of metrics.counters) {
scopeMetrics.metrics.push({
descriptor: {
name: `prisma.${counter.key}`,
description: 'Prisma counter',
unit: '1',
type: InstrumentType.COUNTER,
valueType: ValueType.INT,
},
dataPointType: DataPointType.SUM,
aggregationTemporality: AggregationTemporality.CUMULATIVE,
dataPoints: [
{
startTime: this.startTime,
endTime: endTime,
value: counter.value,
attributes: counter.labels,
},
],
isMonotonic: true,
});
}
for (const gauge of metrics.gauges) {
scopeMetrics.metrics.push({
descriptor: {
name: `prisma.${gauge.key}`,
description: 'Prisma gauge',
unit: '1',
type: InstrumentType.UP_DOWN_COUNTER,
valueType: ValueType.INT,
},
dataPointType: DataPointType.GAUGE,
aggregationTemporality: AggregationTemporality.CUMULATIVE,
dataPoints: [
{
startTime: this.startTime,
endTime: endTime,
value: gauge.value,
attributes: gauge.labels,
},
],
});
}
for (const histogram of metrics.histograms) {
const boundaries = [];
const counts = [];
for (const [boundary, count] of histogram.value.buckets) {
boundaries.push(boundary);
counts.push(count);
}
scopeMetrics.metrics.push({
descriptor: {
name: `prisma.${histogram.key}`,
description: 'Prisma histogram',
unit: 'ms',
type: InstrumentType.HISTOGRAM,
valueType: ValueType.DOUBLE,
},
dataPointType: DataPointType.HISTOGRAM,
aggregationTemporality: AggregationTemporality.CUMULATIVE,
dataPoints: [
{
startTime: this.startTime,
endTime: endTime,
value: {
buckets: {
boundaries,
counts,
},
count: histogram.value.count,
sum: histogram.value.sum,
},
attributes: histogram.labels,
},
],
});
}
result.resourceMetrics.scopeMetrics.push(scopeMetrics);
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment