LoginSignup
2
1

More than 3 years have passed since last update.

X-RayのSAMとLambda内への組み込みとjestでのモック化

Last updated at Posted at 2020-07-04

2017年頃からサーバレスに浸っている、TISの小西啓介です。

image.png

概要

SAM(Serverless Application Model)を使ったnode.jsのLambdaプログラム等に対して、
パフォーマンス計測等を行いX-Ray機能の組み込みについて説明します。

また、X-Ray機能を組み込むと、aws-sdk-mockを使用したユニットテストでは
通らなくなるので、aws-xray-sdkのモック化についても説明します。

SAMへのX-Rayの追加

API Gateway - Lambda - DynamoDBのような構成だとして、
SAM(Serverless Application Model)へのX-Rayの組み込みは、
以下のように、SAMのテンプレーレートのGlobalセクションの
Function に対して、Tracing: Active
Api に対して、TracingEnabled: Trueを追加するだけです。

もちろん、Globalではなく、AWS::Serverless::Functionや
AWS::Serverless::ApiのPropertiesに追加しても良いです。

変更前SAM-Template

Globals:
  Function:
    Timeout: 15
  Api:
    # https://github.com/awslabs/serverless-application-model/issues/191
    OpenApiVersion: 3.0.0
変更後SAM-Template
Globals:
  Function:
    Timeout: 15
    Tracing: Active # 追加
  Api:
    # https://github.com/awslabs/serverless-application-model/issues/191
    OpenApiVersion: 3.0.0
    TracingEnabled: True # 追加

Lambda内のAWSサービス呼出へのX-Rayの組み込み

API GatewayからLambdaへの呼出のみであれば、上記のSAMへの組み込みのみで十分なのですが、
Lambda内で、AWS-SDKを使ってAWSのサービスを呼び出している場合、その呼出のトレースを行う場合、コードの変更が必要です。
ただ、コードの変更と言っても、 npm i -S aws-xray-sdk-coreaws-xray-sdk を組み込んで以下のコードの変更を行うだけです。

変更前js
const AWS = require('aws-sdk');
変更後js
const AWSXRay = require('aws-xray-sdk-core');
const AWS = AWSXRay.captureAWS(require('aws-sdk'));

なお、aws-xray-sdkには、 以下の4つのモジュールが含まれます。

  • aws-xray-sdk-core
  • aws-xray-sdk-express
  • aws-xray-sdk-mysql
  • aws-xray-sdk-postgres

Lambdaの場合、mysqlやpostgresに接続しないのであれば、aws-xray-sdk-coreで十分だと思います。
Lambda内で、AWS Serverless Expressを使用している場合、aws-xray-sdk-express が気になりますが、これはEC2用の為、使用できません(Lambdaでは、呼出時にX-Rayのセグメントが既に作られているので、新たにセグメントを設定することは出来ないため)

ユニットテスト(jest)でのモック化

上記のようなAWS-SDKを使用しているプログラムのユニットテストで便利な AWS-SDK-Mockがあるのですが、AWS-SDKをラップしている関係で、そのままのコードでは動かなくなってしまします。

AWSXRayが使用する部分AWS-SDKの処理をAWS-SDK-Mockで書けば良いのもしれないのですが、情報が無くよくわかりませんでした。
(AWS_XRAY_CONTEXT_MISSING などの環境変数を設定してもだめでした)

また、Jest用にaws-xray-Mockというのが有るのですが、上記のような呼び出し方(captureAWS)には対応しておらず、個別の(AWSサービス毎の)クライアントにしか対応していないようです。プルリクも出ていますが、5月から、放置されてしまっています。
https://github.com/MechanicalRock/aws-xray-mock/pull/4

そこで、上記のコードを参考に、captureAWSのみに対応する場合、
以下の追加で、aws-sdk-mockを使ったテストが全て通るようになりました。

beforeAll(async () => {
    jest.mock('aws-xray-sdk-core', () => {
        return { captureAWS: aws => aws };
    });
});

サブセグメントの追加やAWSクライアント(サービス)単位の設定等を行う場合、
以下のように、利用するメソッドを追加しましょう。
(出典:aws-xray-mock 及び aws-xray-mockのプルリク)

let xRaySegment;
class MockXraySegment {
    constructor(name) {
        this.name = name;
        xRaySegment = this;
    }
    addNewSubsegment(name) {
        return new MockXraySegment(name);
    }
    addError(error) { }
    close() { }
}
beforeAll(async () => {
    // process.env.AWS_XRAY_CONTEXT_MISSING = 'LOG_ERROR';
    jest.mock('aws-xray-sdk-core', () => {
        return {
            captureAWS: aws => aws,
            captureAWSClient: client => client,
            captureHTTPs: http => http,
            captureHTTPsGlobal: httpGlobal => httpGlobal,
            getSegment: () => {
                if (!xRaySegment) {
                    xRaySegment = new MockXraySegment('Parent Segment');
                    return xRaySegment;
                }
                return xRaySegment;
            }
        };
    });
});
beforeEach(async () => {
    xRaySegment = null;
});

やはり、 aws-xray-mock のプルリクマージして欲しいですね。
(aws-xray-sdkだけでなくて、aws-xray-sdk-core もモック化してほしいですが。。)

おわり

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1