node.jsからAWS CloudWatchにmetricsをputする


カスタムライブラリを使う方法もいろいろあるようですが、lambdaとかでの利用を考えると標準ライブラリだけで対応したい。

## まずはローカル（というかLambda以外からの実行）

### 準備

いろいろなところからmetricsを送りたい。まあ別にnode.jsである必要はありませんが、Lambdaに移植することを想定してひとまずnode.js。

>PHPとか[ここ](https://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-cloudwatch.html)とか読めば書いてます。

#### aws-sdkのインストール

```bash
npm install aws-sdk
```

#### credentialファイルの用意

コードに直接書くこともできますが、とりあえず外部ファイル作成。

```js:credential.json
{
    "accessKeyId": "xxxxxxxx",
    "secretAccessKey": "xxxxxxxxxxxxxxxxxxxxxxxxx"
}
```

### 実装

特に難しいことはありません。

```js:index.js
const AWS = require('aws-sdk');

//credential情報の読込
AWS.config.loadFromPath('credential.json');

// 直接指定もできる・・・
// var config = new AWS.Config({
//     accessKeyId: 'xxxxxxxx',
//     secretAccessKey: 'xxxxxxxxxxxxxxxxxxxxxxxxx',
//     region: 'ap-northeast-1'
// });

//Metricsの設定
const metric = {
    MetricData: [
      {
        MetricName: 'test-002',
        Dimensions: [
          {
            Name: 'URL', //InstanceIdとかでも
            Value: 'http://www.bluecode.jp'
          },
        ],
        Timestamp: new Date(),
        Unit: 'Count',
        Value: 100
      },
    ],
    Namespace: 'TestMetrics'
  };

//cloudwatchの生成＋リージョン指定
const cloudwatch = new AWS.CloudWatch({region: 'ap-northeast-1'});

//データを投げる
cloudwatch.putMetricData(metric, (err, data) => {

    if (err) {
        console.log(err, err.stack); // error
    } else {
        console.log(data);           // ok
    }
    
});
```

### テスト

実行すると承認番号？的なものが戻ります。

```bash
node index.js

{ ResponseMetadata: { RequestId: '417901e9-5564-11e8-85fa-6b5b78fa63c1' } }
```


## Lambda

同じコードをLambdaから試してみます。

### 準備（といか前知識）

#### 実行権限

Lambdaではcredentialは無視されて、Lambdaの実行ロール（何も考えず作ったならlambda_basic_executionロール）で実行されます。
このロールにCloudWatchを制御するポリシーをアタッチする必要があります。

* 私は一旦CloudWatchFullAccessをアタッチしてみました（もうちょっと範囲狭くてもいいですが・・・）

#### タイムアウト

Lambdaの実行時間はデフォルトで3秒に設定されており、プログラムに問題なくてもタイムアウトに引っかかりエラーとなりました。
CloudWatch連携にはそれなりに時間がかかるようなので、5秒以上が望ましいでしょう（私は10秒にしました。あまり長いと課金に影響します）。

### 実装

まあLambdaなのでexports.hander = (){}の中に入れる必要がります。

```js:index.js
exports.handler = (event, context, callback) => {
    
    const AWS = require('aws-sdk');
    
    //credentialはいらないし、無視されます。lambda実行ロールに適切な権限を与えます。
    
    //Metricsの設定
    const metric = {
        MetricData: [
          {
            MetricName: 'test-002',
            Dimensions: [
              {
                Name: 'URL',
                Value: 'http://www.bluecode.jp'
              },
            ],
            Timestamp: new Date(),
            Unit: 'Count',
            Value: 102 //ちょっと変えてみる
          },
        ],
        Namespace: 'TestMetrics'
    };
    
    const cloudwatch = new AWS.CloudWatch({region: 'ap-northeast-1'});
    
    cloudwatch.putMetricData(metric, (err, data) => {
    
        if (err) {
            console.log(err, err.stack); // error
        } else {
            console.log(data);           // ok
            callback(nukk, data);
        }
        
    });

};
```

### テスト

保存してテストボタンを押します。
無事metricsが取得できました（結果とか省略）。

### ルールの設定

ここまでくれば、CloudWatchにてルール設定して定期実行し、何かの値を常に監視できます（やり方省略。すみません）。


## 参考

* https://stackoverflow.com/questions/40712522/how-to-publish-from-an-aws-lambda-to-a-cloud-watch-metric-in-node-js