Calling CloudWatch API (using in blackbird AWS plugin)

ちょっとありふれた記事かもしれないんですが、botoを使ってCloudWatch APIを叩いて、各種Metricを取得してみましょう。この仕組はblackbirdの各種AWS pluginでも使っていまして、一緒にCloudWatchにおけるNameSpaceとかそういった概念的なものも理解を深めましょうっていうところです。

CloudWatch Outline
------------------

CloudWatchの基本的な概念としては、

* Namespaces
* Dimensions
* Metrics
* Periods
* Time stamps
* Statistics
* Units

ってのがあります。では順不同ですけど、わかりやすいものから順に追っていきます。

### Metrics

Metricsは最もわかりやすい概念のひとつで、Zabbix的に言うとItemです。ひとつのアイテムには時系列で各種Valueが入っているイメージです。たとえばRDSならSwapUsageっていうMetricsにはどれだけSwapしたかっていう値がBytesで入ってたりします。

### Namespaces

Namespacesは上記のMetricsがたくさん入ったものです、たくさんってのは、種類的にも量的にもってかんじですね。Zabbix的に言うとHost(あるいはHost Groupsにも)の概念に相当すると思います。

db001っていうHostにSwapUsageっていうMetricとか、DatabaseConnectionsっていうMetricが入ってたりっていう感じですね。

### Dimensions

Dimensionsはちょっとふわっとしていて、わかりづらい概念ですね(少なくとも僕はそう思いましたｗ)。Zabbix的にはApplicationになりますね(HostGroupをNamespacesとした場合、HostがDimensionsになりますね)。

### Periods

MetricをGETするAPIという観点で見るとどの間隔のデータを取得するかで、CloudWatchのUIから見るとAvg(1min)とかAvg(5min)でいう_1min_, _5min_にあたります。Time PeriodのPeriodですね。

### Time stamps

タイムスタンプです。Namespaces内の各種MetricにはTime stampが設定されていて、どの時間のMetricがどれくらいかっていう点を示しています。Zabbix Senderでtime stamp付きでデータを送信することがある人なら、そのtime stampと同等だと考えることができます。

### Statistics

日本語だと統計とされますが、統計っていうよりは個人的にはMethodに近いのかなと、どういう形でDataを取り出すのかって話ですね。これにはMetricによって使用できるものと使用できないものがあります。

たとえば、Metricの単位がBytesな場合、Sumなら単位時間あたりの合計Bytesを算出しますし、Averageなら単位時間あたりの平均を示しますし、Countなら出現頻度を表したりします。

Zabbixで言うと、保存時の計算とかにあたるとは思いますが、raw dataだけを入れて、取り出すときに任意のStatisticsを呼び出せるってところが大きく違いますね。

### Units

その名の通り、単位です。bytesだったり、bytes/secondだったり、%だったり、回数(単純に数字)だったりします。

How to get CloudWatch metrics
-----------------------------

ここまででだいたい概念がわかったところで実際にCloudWatchのAPIを使って、Metricsを取得してみましょう。まずは何はともあれ

```bash
pip install boto
```

botoのインストールです。botoは説明不要かもですが、AWSのAPIをcallするためのPython binding libraryです。blackbirdでも内部的にはbotoを使っています。

### CloudWatch用のConnectionを取得

class名は`boto.ec2.cloudwatch.CloudWatchConnection`となっているのですが、イメージとしてはAPI Token Object的なイメージです。

```py
import datetime

import boto.ec2.cloudwatch

conn = boto.ec2.cloudwatch.connect_to_region(
    region_name='ap-northeast-1',
    aws_access_key_id='YOUR_AWS_ACCESS_KEY_ID',
    aws_secret_access_key='YOUR_AWS_SECRET_ACCESS_KEY'
)
```

ここで正しい認証情報をわたしてやれば、Connectionインスタンスが返ってきます。っで、Connectionインスタンスを使ってELBの直近から15分間のRequestCountを5分毎のSumを取得してみると

```py

end_time = datetime.datetime.utcnow()
start_time = end_time - datetime.timedelta(minutes=15)

metrics = conn.get_metric_statistics(
    #periodは秒数をintで指定
    period=300,
    #start_timeはtime stampの期間の始まりをdatetime.datetimeオブジェクトで指定
    start_time=start_time,
    #end_timeはstart_time同様、
    #time stampの期間の終わりをdatetime.datetimeオブジェクトで指定
    end_time=end_time,
    #metric_nameはその名の通り、Metricの名前をstrで指定
    metric_name='RequestCount',
    #Namespaceをstrで指定
    namespace='AWS/ELB',
    statistics='Sum',
    #Dimensionsはkeyとvalueをdictionaryで指定
    dimensions={
        'LoadBalancerName': 'YOUR_ELB_NAME',
        'AvailabilityZone': 'ap-northeast-1a'
    },
    #unitはMetricに指定しても意味のないものもあったりします
    unit=None
)

print metrics
```

こんな値が返ってきます。

```py
[
    {
        u'Timestamp': datetime.datetime(2014, 12, 7, 10, 48),
        u'Sum': 143426.0,
        u'Unit': u'Count'
    },
    {
        u'Timestamp': datetime.datetime(2014, 12, 7, 10, 38),
        u'Sum': 135535.0,
        u'Unit': u'Count'
    },
    {
        u'Timestamp': datetime.datetime(2014, 12, 7, 10, 43),
        u'Sum': 139088.0,
        u'Unit': u'Count'
    }
]
```

Timestampをkeyにして、`datetime.datetime`オブジェクトをvalueとし、指定したStatisticsをkeyにして、Metricsの値をvalueとし、Unitをkeyに、指定した(あるいはdefualtの)Unitの名前をvalueしたdictionaryのlistがreturnされます(上記の構造をみれば一目瞭然ですね)。

っで、blackbirdではこれを元にzabbix serverへとデータを送信しています。