📝
NestJS で Prisma の発行するクエリを出力する
NestJS で Prisma を扱うとき、発行されるクエリがどんなものか追いたかったのですが、いずれの公式ドキュメントにも明記されていなかったため備忘録です。
なお、執筆環境の依存モジュールバージョンは以下の通りです。バージョン差異による不具合はご了承ください。
package.json
"dependencies": {
"@nestjs/common": "^8.0.0",
"@nestjs/core": "^8.0.0",
"@prisma/client": "^3.11.1",
"prisma": "^3.11.1"
}
Prisma on NestJS の雛形
NestJS で Prisma を利用する場合、インスタンス化せず以下の様に service として定義、各々の module で利用します。DB 接続を試行するライフサイクルイベントonModuleInit
の定義は現在オプションですが、後続解説のため定義しておきます。
apps/api/src/prisma.service.ts
import {
Injectable,
OnModuleInit,
} from '@nestjs/common';
import { PrismaClient, Prisma } from '@prisma/client';
@Injectable()
export class PrismaService
extends PrismaClient
implements OnModuleInit
{
async onModuleInit() {
await this.$connect();
}
}
Logger の設定
この雛形に対し、以下のとおり実装を追加すれば OK。
-
@nestjs/common
の Logger インスタンスを確保しておく - コンストラクタの
super
で log 出力を指定する- ここの引数は PrismaClient インスタンス化のものと同じ
-
onModuleInit
で、イベントリスナーを登録する
ランタイムの改修は上記 3 点で十分ですが、このままではthis.$on
で型エラーが発生します。このエラーはextends PrismaClient
をextends PrismaClient<Prisma.PrismaClientOptions, Prisma.LogLevel>
に修正することで、this.$on
の型推論が拡張されます。
apps/api/src/prisma.service.ts
import {
Injectable,
OnModuleInit,
+ Logger,
} from '@nestjs/common';
import { PrismaClient, Prisma } from '@prisma/client';
@Injectable()
export class PrismaService
- extends PrismaClient
+ extends PrismaClient<Prisma.PrismaClientOptions, Prisma.LogLevel> // <- here
implements OnModuleInit
{
+ private readonly logger = new Logger(PrismaService.name);
+ constructor() {
+ super({ log: ['query', 'info', 'warn', 'error'] });
+ }
async onModuleInit() {
+ this.$on('query', (event) => {
+ this.logger.log(
+ `Query: ${event.query}`,
+ `Params: ${event.params}`,
+ `Duration: ${event.duration} ms`,
+ );
+ });
+ this.$on('info', (event) => {
+ this.logger.log(`message: ${event.message}`);
+ });
+ this.$on('error', (event) => {
+ this.logger.log(`error: ${event.message}`);
+ });
+ this.$on('warn', (event) => {
+ this.logger.log(`warn: ${event.message}`);
+ });
await this.$connect();
}
}
これで発行されるクエリが出力される様になりました(例示は PostgreSQL によるもの)
prisma:query SELECT "public"."Post"."id", "public"."Post"."title", "public"."Post"."content", "public"."Post"."published", "public"."Post"."authorId" FROM "public"."Post" WHERE "public"."Post"."authorId" IN ($1) OFFSET $2
[Nest] 46661 - 04/01/2022, 1:02:35 PM LOG [PrismaService] Query: SELECT "public"."Post"."id", "public"."Post"."title", "public"."Post"."content", "public"."Post"."published", "public"."Post"."authorId" FROM "public"."Post" WHERE "public"."Post"."authorId" IN ($1) OFFSET $2
[Nest] 46661 - 04/01/2022, 1:02:35 PM LOG [PrismaService] Params: [3,0]
[Nest] 46661 - 04/01/2022, 1:02:35 PM LOG [PrismaService] Duration: 3 ms
参考
Discussion