AWS X-RayをAWS SDK v3と一緒に使ってみた

AWS X-RayをAmazon API Gateway, AWS Lambda, DynamoDBなどとともに使用する方法。Lambdaコード内では、AWS SDK v3を使用しています。
2022.03.29

はじめに

こんにちは。CX事業本部IoT事業部の木村です。

現在携わっているプロダクトでは、Amazon API Gateway(以下、API Gateway), AWS Lambda(以下、Lambda), Amazon DynamoDB(以下、DynamoDB)などのマネージドサービスを組み合わせての開発を行っています。多くのサービスが関連していると、ログなどが分散しているためデバッグやパフォーマンス分析をするのが大変ということがあります。そこで、AWS X-Rayを用いたトレーシングを行います。その対応をする際に、AWS SDK v3におけるキャプチャー方法が少々変わっていたので方法を紹介いたします。

AWS X-Rayの有効化

今回の例としては、

  • API GatewayからLambdaを呼び出し
  • LambdaからDynamoDBにaws-sdk経由でアクセスする
  • 言語はLambda、CDKともにTypeScript
  • バージョン等
    • node: v14.17.6
    • aws-cdk: 2.10.0
    • aws-sdk: 3.43.0

というものを想定します。

AWS CDKでAWS X-Rayを有効化する

まずはCDKで定義しているAPI GatewayとLambdaについてX-Rayの設定を行います。

API Gatewayの場合

/cdk/lib/sample-stack.ts

import * as apigateway from '@aws-cdk/aws-apigateway';

const restApi = new apigateway.RestApi(this, 'SampleRestApi', {
  restApiName: `SampleRestApi`,
  deployOptions: {
    stageName: 'v1',
    tracingEnabled: true, // <= tracingを有効化する
  },
});

Lambdaの場合

/cdk/lib/sample-stack.ts

import * as lambda from '@aws-cdk/aws-lambda';

const sampleFunction = new lambda.Function(
  this,
  'sampleFunction',
  {
    code: lambda.Code.fromAsset(
      '/path/to/asset',
    ),
    environment: {},
    functionName: `sample-function-name`,
    handler: 'index.handler',
    runtime: lambda.Runtime.NODEJS_14_X,
    timeout: cdk.Duration.seconds(3),
    tracing: lambda.Tracing.ACTIVE, // <= tracingを有効化する
  },
);

以上の設定で、以下のような感じになります。上部にサービスマップが表示されています。また、下部のトレースリストを選択すると、メタデータや例外などの情報へのアクセスが可能です。

AWS X-RayでAWS SDK v3をCaptureする

上記までの手順である程度サービスマップも出力されるのですが、LambdaからAWS SDK経由で他リソースへアクセスする部分をキャプチャーするにはもう一工夫必要です。

以下にサンプルコードを示します。公式のドキュメントはこちらをご参照ください。 なお、DynamoDBClientのインスタンスをanyでキャストしているのも公式にしたがっており、eslintをこの行だけ無視するようにインラインコメントで対応しています。

/functions/index.ts

import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, GetCommand } from '@aws-sdk/lib-dynamodb';
import * as AWSXRay from 'aws-xray-sdk';

const patchedDynamoDBClient = AWSXRay.captureAWSv3Client(
  new DynamoDBClient({
    apiVersion: '2012-08-10',
    region: 'ap-northeast-1',
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
  }) as any,
);

const client = DynamoDBDocumentClient.from(patchedDynamoDBClient);

export const handler = async (event: Event): Promise<HttpResponse> => {
  const res = await client.send(
    new GetCommand({
      TableName: 'SampleTable',
      Key: { id: event.id },
    }),
  );
  return {
    statusCode: 201,
    body: res.Item
  };
};

なお、AWS SDK v2においては、こちらの方法にて、モジュールごとまるっとCaptureすることが可能でした。AWS SDK v3からはモジュラーアーキテクチャを採用しているため、一つ一つのクライアントごとにCaptureする必要があります。また、AWS SDK v2とv3の違いはこちらをご覧ください。

ということで、結果はこのようになりました。LambdaからDynamoDBにアクセスする部分が追加されていることがわかると思います。

最後に

X-Rayの設定方法について簡単にご説明しました。これらの設定が済んだ後は、API GatewayからのレスポンスヘッダーやLambdaのEventや終了ログなどから、TracingIDを取得することが可能です。これらのデータを使用して、今後は分析や改善に励んでいきたいと思います。