apm-agent-nodejs icon indicating copy to clipboard operation
apm-agent-nodejs copied to clipboard

Support for prisma

Open toxsick opened this issue 3 years ago • 10 comments
trafficstars

Is your feature request related to a problem? Please describe.

I would love to see support for https://www.prisma.io orm in the agent. Right now I am migrating a big project from sequelize to prisma and queries performed by prisma do not show up in the traces:

KN macOS 10 14 2022-11-18 13-40-02

This can be very misleading. I think because prisma is at this point a very relevant technology the elastic agent should support it.

Thanks and regards

Hannes

toxsick avatar Nov 18 '22 12:11 toxsick

@toxsick Thanks for the feature request!

I looked briefly at this. The reason there is tracing of sequelize's queries is because it uses the various database drivers -- some of which we do instrument. It looks like prisma has its own Rust-implemented engine that is doing all the DB queries, so we'd have to instrument prisma directly, if that is possible.

I say "if that is possible" because it looks like -- again from a very brief look -- that the main Prisma query handling (in the @prisma/client package) is deployed as an esbuild-built bundle. That might make instrumenting it effectively "exciting". :) I'm not sure, however. It might be very straightforward.

trentm avatar Nov 18 '22 18:11 trentm

Hey @trentm,

thanks for looking into this, I wrote my own variant to debug logging for prisma queries, perhaps it helps to get started:

// enable debug logging
// reference: https://github.com/prisma/prisma/issues/5026
const DEBUG = true;

const prisma = new PrismaClient(
  DEBUG
    ? {
        log: [
          {
            emit: 'event',
            level: 'query',
          },
        ],
      }
    : null,
);

if (DEBUG) {
  prisma.$on('query', async ({ query, params, duration }) => {
    const paramsParsed = JSON.parse(params);
    console.log(
      [
        '==> prisma query:\n',
        query
          .split('?')
          .map((segment, i) => {
            if (paramsParsed[i] === undefined) {
              return segment;
            }
            const param = paramsParsed[i];
            if (typeof param === 'string') {
              return `${segment}"${param}"`;
            }
            return `${segment}${param}`;
          })
          .join(''),
        `\n==> took ${duration}ms`,
      ].join('\n'),
    );
  });
}

It will log the actual sql queries performed by prisma with duration. Perhaps this is a start?

toxsick avatar Nov 20 '22 10:11 toxsick

I researched a little bit more and perhaps a prisma middleware would be the right way to go?

  • https://www.prisma.io/docs/concepts/components/prisma-client/middleware
  • https://www.prisma.io/docs/concepts/components/prisma-client/middleware/logging-middleware

@trentm let me know what u think

toxsick avatar Nov 20 '22 14:11 toxsick

@toxsick Thanks! That's very helpful.

trentm avatar Nov 20 '22 17:11 trentm

Its pretty easy to do something simple yourself.

This is what im rocking right now and it works pretty well:

import apm from "elastic-apm-node";

prisma.$use(async (params, next) => {
      const span = apm.startSpan(`prisma.${params.model}.${params.action}`);
      if (span) {
        span.type = "DB";
        span.subtype = "prisma";
        span.action = "query";
      }
      try {
        const result = await next(params);
        span?.end();
        return result;
      } catch (e) {
        span?.end();
        throw e;
      }
    });

mikecann avatar Feb 12 '23 06:02 mikecann

@mikecann Nice.

If you want slightly shorter code you could put the type, subtype, and action in the .startSpan(...) call. E.g.:

const spam = apm.startSpan(`...`, "db", "prisma", "query")
try {
  ...

Also, I used lower-case "db" like the agent does for other database instrumentation. I'm not actually sure if that case difference makes a difference for some UI in the Kibana APM app. E.g. it might for the icon it uses for database spans.

trentm avatar Feb 13 '23 17:02 trentm

Nice thanks :)

mikecann avatar Feb 14 '23 02:02 mikecann

Hey 👋🏽

Alex here from the Prisma team.

We introduced two preview features a while back that gives insight on how Prisma Client interacts with your database: tracing and metrics.

You can enable the Preview features in your application by updating the generator block with:

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["metrics", "tracing"]
}

We built an instrumentation package to help with tracing @prisma/instrumentation you could use for tracing (required for the Preview feature to work). It fully supports the OpenTelemetry standard.

Feel free to reach out for any clarifications or create a GH issue in the Prisma repo if you run into any issues. 🙂

Docs:

ruheni avatar Feb 22 '23 17:02 ruheni

@ruheni , I tried to activate tracing in my project, while installing the dependencies as stated. but still failed to see traces on elastic APM, Or Actually I am seeing traces now, but does not reflect the same info in the span as provided by other ORMs, most importantly the SQL statement itself.

Screen Shot 2023-10-16 at 1 37 45 PM

zahert avatar Oct 15 '23 12:10 zahert