nestjs-prisma
Advanced

Query Logging Extension

Create a PrismaClient extension to log all queries performed by the PrismaClient.

Add query logging extension

Prisma provides an example for Prisma Client Extension - Query Logging. You need to create a new PrismaClient instance with $extends where you will define the query logging extension.

// prisma.extension.ts
import { Logger } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

const logger = new Logger('PrismaClient');

export const extendedPrismaClient = new PrismaClient().$extends({
  query: {
    $allModels: {
      async $allOperations({ operation, model, args, query }) {
        const start = performance.now();
        const result = await query(args);
        const end = performance.now();
        const time = Math.ceil((end - start) * 100) / 100;
        // adjust logging behavior to your needs
        logger.log(`Prisma Query ${model}.${operation} took ${time}ms`);
        return result;
      },
    },
  },
});

export const ExtendedPrismaClient = typeof extendedPrismaClient;

Now you need to register and inject the CustomPrismaService with your extendedPrismaClient. Read more about Prisma Client Extensions.

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

import { CustomPrismaModule } from 'nestjs-prisma';
import { extendedPrismaClient } from './prisma.extension';

@Module({
  imports: [
    // ✅ use `forRootAsync` when using `PrismaClient().$extends({})`
    CustomPrismaModule.forRootAsync({
      name: 'PrismaService',
      useFactory: () => {
        return extendedPrismaClient;
      },
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Inject the CustomPrismaService with the ExtendedPrismaClient type, useful when adding custom methods to your models.

import { Inject, Injectable } from '@nestjs/common';
import { CustomPrismaService } from 'nestjs-prisma';
import { type ExtendedPrismaClient } from './prisma.extension';

@Injectable()
export class AppService {
  constructor(
    // ✅ use `ExtendedPrismaClient` type for correct type-safety of your extended PrismaClient
    @Inject('PrismaService')
    private prismaService: CustomPrismaService<ExtendedPrismaClient>,
  ) {}

  users() {
    return this.prismaService.client.user.findMany();
  }
}

You will see now for the log messages in your terminal

Prisma Query User.findMany took 10ms
...

Query Logging extension function

Extract the query logging extension as shareable extension by following Create a shareable extension.

// query-logger.extension.ts
import { Logger } from '@nestjs/common';
import { Prisma } from '@prisma/client';

export const queryLoggingExtension = (logger: Logger) =>
  Prisma.defineExtension({
    name: 'prisma-extension-query-logger',
    query: {
      $allModels: {
        async $allOperations({ operation, model, args, query }) {
          const start = performance.now();
          const result = await query(args);
          const end = performance.now();
          const time = Math.ceil((end - start) * 100) / 100;
          logger.log(`Prisma Query ${model}.${operation} took ${time}ms`);
          return result;
        },
      },
    },
  });

Now you can import and use queryLoggingExtension(new Logger(...)) in $extends(...).

// prisma.extension.ts
import { Logger } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { queryLoggingExtension } from './query-logger.extension';

const logger = new Logger('PrismaClient');

export const extendedPrismaClient = new PrismaClient().$extends(
  queryLoggingExtension(logger),
);

export const ExtendedPrismaClient = typeof extendedPrismaClient;

Make sure to register and inject the CustomPrismaService described above.

Example

The Extensions example on GitHub includes the query-logging.extension.ts.