Skip to content

Instantly share code, notes, and snippets.

@mape
Last active Oct 20, 2021
Embed
What would you like to do?
Elastic APM node client instrumenting Prisma 2 queries
import { condensePrismaQuery } from './utils';
// Screenshot of a trace sample: https://i.imgur.com/XuhuQFq.png
// Service: https://www.elastic.co/apm
// Node module: https://github.com/elastic/apm-agent-nodejs
// Prisma: https://www.prisma.io/
// Using "@prisma/client": "dev"
// Thanks to https://github.com/prisma/prisma/pull/2902
const apmPatchPrisma = (
prisma: PrismaClient<{}, never>,
apm: any /*Agent*/
) => {
// "as any" because these hooks are not available in the TypeScript types yet
(prisma as any).use('all', async (request: any) => {
const name = condensePrismaQuery(request.params.args);
const type = 'db';
const subType = 'prisma';
const action = 'query';
const apmSpan = apm.startSpan(name, type, subType, action);
const result = await request.fetch(request.params);
apmSpan && apmSpan.end();
return result;
});
};
export default apmPatchPrisma;
const apm = require('elastic-apm-node').start({
serviceName: 'app',
secretToken: process.env.AP_TOKEN,
serverUrl: process.env.APM_URL
});
import { PrismaClient } from '@prisma/client';
import apmPatchPrisma from './lib/apmPatchPrisma';
const prisma = new PrismaClient();
apmPatchPrisma(prisma, apm);
export const condensePrismaQuery = (prismaQuery: Object, delimiter = '.') => {
const result = {};
const flatten = (obj: any, stack: any) => {
Object.keys(obj).forEach((key) => {
const s = stack
.concat([key === 'select' ? undefined : key.trim()])
.filter(Boolean);
const child = obj[key];
if (typeof child === 'object') {
flatten(child, s);
} else {
const twoLastInChain = s
.slice(s.length - 2, s.length)
.join(delimiter);
result[twoLastInChain] = true;
}
});
};
flatten(prismaQuery, []);
const output = Object.keys(result).join(', ');
return `Prisma: ${output}`;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment