LambdaからのLambda呼び出し、Instanaでどう見える？

# はじめに

以前、こちらの記事を投稿しましたが、その後さらにLambdaから別のLambdaを呼び出した際、どの様にInstana側で見えるのか？ちゃんとトレースは追えるのか？を検証する機会があったので記事に起こしました。

https://qiita.com/LgmQue/items/a1e847b9198ffe33846f

:::note warn
前回はPythonでしたが、今回はNode.js(14.x)で試しています。
:::

では早速いきましょう

# 子となるLambdaの準備

## Lambdaの作成

関数名を任意のもの、ランタイムを `Node.js 14.x` に設定し、[関数の作成]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/0b8a1ba2-0d3e-ae55-5d57-e3d5340fde9c.png)

このLambdaが呼び出されるたびランダムに正常/異常のレスポンスおよびログ出力を行うように上書きします。

```js
exports.handler = async (event) => {
  var ok = [100, 200, 300];
  var ng = [400, 500];

  const ri = Math.floor(Math.random() * 11);
  if (ri <= 2) {
    const mes = "something error occurred!: " + ri;
    console.error('(child)' + mes);
    return {
      statusCode: ng[Math.floor(Math.random() * ng.length)],
      body: JSON.stringify(mes),
    };
  } else if (ri <= 5) {
    console.warn("(child)something warn occurred!: " + ri);
  } else {
    console.info("(child)healthy!: " + ri);
  }
  return {
    statusCode: ok[Math.floor(Math.random() * ok.length)],
    body: JSON.stringify('Hello Instana!: ' + ri),
  };
};
```

変更ができたら、[Deploy] をクリックします。
動作を確認したい方は、Testにてテスト用のイベントを作成(デフォルトのままでOKです)し何度か実行してみましょう。

## Instanaの設定

Instanaのトップ画面から[エージェントのデプロイ]をクリックします。

プラットフォームは`AWS`,
テクノロジーは`AWS Lambda`,
Lambdaランタイムは`Node.js 10.x以降`,
AWSリージョンは`自身の作成したリージョン`(今回は東京リージョンなので`ap-northeast-1`)
を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/b163c0e4-9d3e-f834-96ec-5aec2ded0be7.png)

設定値が表示されたらLambda側に入力していきます。

### レイヤーの追加

[レイヤーの追加] をクリックし、[ARNを指定] を選択し、Instana側に表示されているARNをコピペします。
[検証] をクリックすると、情報が取得できるはずなので、エラーになる場合はコピペを再度してみてください。
問題なければ [追加] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/0a1b3ea3-4b3d-08f6-e781-7102a5d6499c.png)

### ハンドラーの変更

ランタイム設定の [編集] をクリックし、Instana側に表示されているハンドラで上書きしたら [保存] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/37aed045-3633-b560-4891-2db2dc0057f7.png)

### 環境変数の追加

[設定タブ] > [環境変数] > [編集] をクリックします。
`INSTANA_ENDPOINT_URL`と`INSTANA_AGENT_KEY`の2つを新たに設定し [保存] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/2b514376-573c-ccdb-2c17-84444fbbda80.png)

:::note info
Instana側で任意の名前で表示をしたい場合は、`INSTANA_SERVICE_NAME` を設定します。
:::

# 親となるLambdaの準備

## IAMの設定

親→子のLambda呼び出しを実現するために、AWS SDKのInvokeを使用します。
その際、IAMロールにて`"lambda:InvokeFunction"`のポリシーを許可しておく必要があるので、IAMの設定から始めます。

### ポリシーの作成

AWSのコンソールから [IAM] > [アクセス管理] > [ポリシー] > [ポリシーの作成] と進みます。
ポリシーエディタをJSONに変更し、下記JSONで上書きした後 `Resource` の値を変更します。
リソースを絞らない場合は `"*"` でもOKです。

```JSON:カスタム信頼ポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction"
            ],
            "Resource": [
                "子のlmabdaのARN"
            ]
        }
    ]
}
```

[次へ] をクリックします。

ポリシー名に任意の名前を入力し、 [ポリシーの作成] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/72d26eae-e91d-5876-d368-ee28688a386d.png)

### ロールの作成

[アクセス管理] > [ロール] > [ロールを作成] と進みます。

エンティティタイプは`AWSのサービス`、ユースケースは`Lambda`を選択して [次へ] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/11407695-0a7f-444b-57ac-6e8d6a584e49.png)

先ほど作成したポリシーを追加して [次へ] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/07d43fd6-39ba-2d9f-3898-d63386bba791.png)

ロール名に任意の名前を入力して、[ロールを作成] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/9036090c-6561-c532-0e2e-9abcd7174ded.png)

## Lambdaの作成

関数名を任意のもの、ランタイムを `Node.js 14.x` に設定します。

デフォルトの実行ロールの変更で `既存のロールを使用する` を選択し、先ほど作成したロール(今回は `exec_lambda` )を指定します。
今回もサクッと試したいので、関数URLを有効化し認証タイプは `NONE` を指定し [関数を作成] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/93c40d39-bed4-3254-fd1f-cecb766744e1.png)

親のLambdaの実装は受け取ったレスポンスのHTTPステータスコードおよびボディをそのままレスポンスとして返すように上書きします。(warningもInstana側で見たかったので3xx系を使ってます。深い意味はありません)

```js
const AWS = require('aws-sdk');
const lambda = new AWS.Lambda();
exports.handler = async (event) => {
    const params = {
        FunctionName: '子のLambda名(今回の場合は'qiita_child')',
        InvocationType: 'RequestResponse',
    };
    
    const response = await lambda.invoke(params).promise();
        
    const statusCode = JSON.parse(response.Payload).statusCode;
    const body = JSON.parse(response.Payload).body;
    console.log(statusCode);
    
    switch (statusCode){
        case 500:
        case 400:
            console.error("(parent)error statusCode : " + statusCode);
            return {
                statusCode: statusCode,
                body: JSON.stringify('error : ' + body)
            };
        case 300:
            console.warn("(parent)warn statusCode : " + statusCode);
            return {
                statusCode: statusCode,
                body: JSON.stringify('warn : ' + body)
            };
        default:
            console.info("(parent)healthy statusCode : " + statusCode);
            return {
                statusCode: statusCode,
                body:JSON.stringify(body),
            };
    };
};
```

変更ができたら、[Deploy] をクリックします。
動作を確認したい方は、Testにてテスト用のイベントを作成(デフォルトのままでOKです)し何度か実行してみましょう。

:::note info
初回起動時はLambdaがコールドスタートになる都合もあり少し時間がかかります。
タイムアウトはデフォルト3秒なのでエラーになる可能性が高いですが、何度か実行すると正常に動作する様になります。
:::

## Instanaの設定

子側と同じため割愛します。

# Instanaで見てみよう

ターミナルで下記コマンドを実行して、1秒ずつLambdaを叩いて様子を見てみましょう。

```
watch -n 1 "curl 親の関数URL"
```

Instanaのホーム画面から、[アプリケーション] > [サービス] と移動し、テクノロジーを `AWS Lambda` で絞り込みます。
まずは無事に親と子が出ていますね。(`node14_child`, `node14_parent`)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/398d7ac8-69eb-8d06-c4b4-bd9c1cf34425.png)

親側を開いてみると良い感じにゴールデンシグナルが見えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/5a090691-dc35-e626-341f-e5800b9f6c74.png)

呼び出しの棒グラフをクリックして、 [分析で表示] をさらにクリックし深掘りしてみます。

色々発生していますが、今回は500エラーの中身を見てみましょう。
適当な呼び出し(`GET /`)をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/02792f6d-400d-d2c9-8f85-059b55d2fcbe.png)

そうするとトレースの画面に飛びます。
しっかりと子Lambdaまでトレースが取れていることも確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/c0eabe98-ce0f-5ab7-22f3-233b7052a670.png)

ログはどこで吐き出しているかわかる様に頭に`(child)`もしくは`(parent)`と出力する様に実装していたのですが、それぞれのログも1画面で見られる様になっています。
良い感じ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/68d2f0cf-203e-41d3-db8f-e2de4fe119db.png)

## その他画面

こんな感じで見ることできますよ〜と画面キャプチャを一応残しておきます。

### フロー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/988e2da9-c0a4-2a1d-756e-e1aee2571bba.png)

:::note warn
この画面でわかる様に、Invokeで別のLambdaを呼び出す際、HTTPではなくRPCを使用します。
そのため、子のLambdaの画面を開くと、HTTPステータスコードの内訳を確認することができませんのでご注意ください。
:::

### エンドポイント

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/bb583180-2cca-b85f-f4ee-3d412f9c8ee1.png)

### エラー・メッセージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/ba8f8171-b2e7-f138-93e5-84dc6418aa49.png)

### ログ・メッセージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118463/d3b09a8e-7229-abdb-d145-bd7c437ae2b1.png)

# まとめ

以上でこの記事は終了です。
Lambdaから別のLambdaを呼び出した時もそれほど大きな修正なくトレースが取れることを確認できたかな、と思います。

参考になれば幸いです。