NestJSで開発したGraphQLのリクエストとレスポンスをAzureのApplication Insightsに登録する
Azureでとあるサービスを開発中です。
開発も終盤に差し掛かってきたので、そろそろ、サービスインした後のことを考えようと、環境を構築しています。
AzureにはApplication Insightsというサービスが提供されており、いろいろなサービスのことを集中管理できるようです。
お客様から問い合わせがあったときに、しっかり対応するためには集中管理は必要不可欠です。
これはシステム管理者としての過去の経験ですが、システムってしっかり管理している(ちゃんと気にかけている)と、トラブルなく動いてくれるものです。
Application Insightsをいじっていて、ふと、NestJSで開発したGraphQL APIへのアクセスをトレースできないと、しっかり対応できないのでは?と思い、調査開始。
NestJSのプロジェクトにちょっとしたコードを書くだけで、Application InsightsにGraphQLへのアクセスを送信できます。
Application Insightsパッケージをインストール
まずは、NestJSプロジェクトに、applicationinsightsパッケージをインストールします。
npm install applicationinsights --save
Application Insightsへのデータ連携準備
main.tsで、Application Insightsへのデータ連携の準備を行います。
bootstrapのできるだけ最初の方で、Application Insightsの初期化、データ送信を開始します。
「ai.cloud.role」にAPIサーバー名を設定しています。
これはメトリックでAPIサーバーをcloud roleで識別するために設定しています。
import * as appInsights from 'applicationinsights';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as helmet from 'helmet';
import * as bodyParser from 'body-parser';
async function bootstrap() {
appInsights.setup();
appInsights.start();
appInsights.defaultClient.context.tags['ai.cloud.role'] = 'xxx-api';
const app = await NestFactory.create(AppModule);
app.use(helmet());
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
app.enableCors();
await app.listen(process.env.PORT || 3000);
}
bootstrap();
プラグインを実装
NestJSからGraphQL APIへのアクセスをApplication Insightsに送信するには、プラグインの実装が必要です。
プラグインは、apollo-server-plugin-baseのApolloServerPluginを基底にします。
これを使うと、APIサーバーでGraphQLリクエストを受けてからレスポンスを返すまでの過程を取得することができます。
詳しくは、下記URLを参照してください。
GraphQLのリクエストとレスポンスをApplication Insightsに送信するには、willSendResponseを使います。
エラーを返す場合も、willSendResponseが使えます。
Application InsightsのtrackTraceを使うと、TraceデータとしてApplication Insightsにデータを送信できます。
送信するデータは、以下のものになります。
リクエストデータ・・・requestContext.request
レスポンスデータ・・・requestContext.response
エラーデータ・・・requestContext.errors
プラグイン全体の実装は、「application-insights-graphql-logging-plugin.ts」に以下のように実装します(ファイルとクラスの名称はなんでも大丈夫です)
import { Plugin } from '@nestjs/graphql';
import { ApolloServerPlugin, GraphQLRequestListener, GraphQLRequestContext } from 'apollo-server-plugin-base';
import * as appInsights from 'applicationinsights';
@Plugin()
export class ApplicationInsightsGraphqlLoggingPlugin implements ApolloServerPlugin {
/**
* GraphQL APIがコールされたときに呼び出される
*/
requestDidStart(): GraphQLRequestListener | void {
const client = appInsights.defaultClient;
client.trackMetric({ name: 'graphql-query', value: 1 });
return {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
willSendResponse(requestContext: GraphQLRequestContext) {
if (requestContext.errors) {
client.trackException({exception: new Error(`graphql-error: ${JSON.stringify(requestContext.errors)}`)});
}
else {
client.trackTrace({message: `graphql-request: ${JSON.stringify(requestContext.request)}`});
client.trackTrace({message: `graphql-response: ${JSON.stringify(requestContext.response)}`});
}
},
}
}
}
プラグインを追加するモジュールの作成と実装
作成したプラグインは、モジュールで追加していきます。
まずは、以下のコマンドで、「ApplicationInsightsGraphqlModule」というモジュールを作成します(クラス名はなんでも大丈夫です)
nest g module ApplicationInsightsGraphqlModule
モジュールのプロバイダ定義に作成したプラグインクラスを追加します。
import { Module } from '@nestjs/common';
import { ApplicationInsightsGraphqlLoggingPlugin } from './application-insights-graphql-logging-plugin';
@Module({
providers: [
ApplicationInsightsGraphqlLoggingPlugin,
],
})
export class ApplicationInsightsGraphqlModule {}
nest g moduleコマンドでApplicationInsightsGraphqlModuleが、app.module.tsに追加されます。
これでAzureにリリースして、Application Insightsのログを確認しましょう。
traceを表示すると、GraphQLのリクエスト、レスポンス、エラーを確認することができます。