見出し画像

NestJS + Apollo Server でログ出力を行う

はじめまして、2021 年 6 月に入社した技術部の masuda です。
初投稿です。

現在スペースマーケットでは API で NestJS + Apollo Server を導入しており、その際にログ出力の対応をしたのでこれについて書いていきます。

Apollo Serverでのログ出力

Apollo Server でログ出力をする場合、Plugin を実装することで実現可能なのでこれを実装していきます。

NestJS での実装

Plugin を実装する
Plugin を実装をすると書きましたが、ありがたいことに公式サンプルで既に Plugin の実装がされています。

import { Plugin } from '@nestjs/graphql';
import {
 ApolloServerPlugin,
 GraphQLRequestListener,
} from 'apollo-server-plugin-base';

@Plugin()
export class LoggingPlugin implements ApolloServerPlugin {
 async requestDidStart(): Promise<GraphQLRequestListener> {
   console.log('Request started');

   return {
     async willSendResponse() {
       console.log('Will send response');
     },
   };
 }
}

サンプルのコードではレスポンスが送信されるイベントフックである willSendResponse が定義されているので、エラーが発生したときにフックされる didEncounterErrors を追加してみます。

import { Plugin } from '@nestjs/graphql';
import {
 ApolloServerPlugin,
 GraphQLRequestListener,
} from 'apollo-server-plugin-base';

@Plugin()
export class LoggingPlugin implements ApolloServerPlugin {
 async requestDidStart(
   requestContext: GraphQLRequestContext
 ): Promise<GraphQLRequestListener> {
   console.log('Request started');
   const {
     request: { query, operationName, variables },
   } = requestContext;

   return {
     async didEncounterErrors({ errors }) {
       // errors は配列なので JSON 文字列に変換している
       const message = {
         errors: JSON.stringify(errors, null, 2),
       };
       console.error(message);
     },
     async willSendResponse() {
       const message = {
         operationName,
         query,
         variables,
       };
       console.log(message);
     },
   };
 }
}

Plugin を Apollo Server に適用する
実装した Plugin についてをモジュールの providers に追加するだけで OK です。追加した Plugin は Nest が生成し、Apollo Server に適用してくれます。

import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { RecipesModule } from './recipes/recipes.module';
import { LoggingPlugin } from './common/plugins/logging.plugin';

@Module({
 imports: [
   RecipesModule,
   GraphQLModule.forRoot({
     installSubscriptionHandlers: true,
     autoSchemaFile: 'schema.gql',
   }),
 ],
 providers: [LoggingPlugin],
})
export class AppModule {}


実際に動かしてみてログの出力を確認してみましょう。
GraphQL のクエリは下記を使用します。

query Recipes($take: Int) {
 recipes(take: $take) {
   id
   title
 }
}

正常にレスポンスが送信された場合はログが1つ、何かしらエラーが発生した場合はログが2つ出力されます。

スクリーンショット 2021-11-17 16.23.29

正常系のログ

スクリーンショット 2021-11-17 16.23.53

エラー発生時のログ(型の異なるパラメータを送信)

まとめ

公式のサンプルをもとに Apollo Server のログ出力を行ってみました。
今回は console を使用しましたが、pinowinston などのライブラリを使ってリッチなログ出力にしてみるのも良いと思います。調査に役立つよう適切なログ出力を行っていきたいですね。

少しでも参考になれば幸いです。

参考

Metrics and logging - Apollo Server
Creating Apollo Server plugins - Apollo Server
Apollo Server plugin event reference - Apollo Server
GraphQL + TypeScript - Plugins | NestJS

最後に、スペースマーケットでは現在エンジニアを募集しています。
カジュアル面談を行っているので、サービスや会社に少しでも興味があれば下記からご応募ください!!


この記事が気に入ったらサポートをしてみませんか?