この記事はCloudWatchメトリクスをAWS CLIで扱うサンプルをまとめた記事です。
CloudWatchとは
CloudWatchはAWSが提供するモニタリングのためのマネージドサービスです。
この記事で主に取り扱うメトリクスのほかに様々なサービスがあります。
- CloudWatch Metrics: メトリクス
- CloudWatch Alarms: アラーム(通知)
- CloudWatch Logs: ログ
- CloudWatch Events (現在は Amazon EventBridge): イベント契機の通知や処理
- CloudWatch Dashboards: ダッシュボード、コンソール画面
- CloudWatch Synthetics: 外形監視
- CloudWatch ServiceLens: X-Rayと連携したアプリケーション監視・分散トレーシング
- CloudWatch Contributor Insights: パフォーマンスに最も影響を及ぼしている要因の分析
- CloudWatch Container Insights: ECSとEKSのメトリクス・ログ収集
- CloudWatch Application Insights for .NET and SQL Server
- CloudWatch (unified) agent: 任意のサーバーで実行できるメトリクス・ログ収集エージェント
- CloudWatch SDK metrics for Enterprise Support: AWS APIをクライアントからコールした回数等の状況をSDKレベルでメトリクス化
基本操作
メトリクスストレージとしての(狭義の)CloudWatchメトリクスはPut/List/Getの3つの機能(だけ)をもちます。
EC2やRDS、Lambdaなどの各種AWSサービスはそれぞれメトリクスを収集して、CloudWatchに送信しています。
CloudWatchメトリクスはそのメトリクスを保管・参照する機能を提供しているわけです。
CloudWatchはメトリクスを特定するために、Namespace
(文字列)、Metric Name
(文字列)、そしてDimensions
(Key/Valueの配列)の3つの情報をユニーク識別子として使用します。
Put/Getのときにはこの識別子を指定してメトリクスを操作することになります。
まずは基本のPut/List/GetからAWS CLIで実行してみましょう。
Put
CloudWatchではメトリクスのPutにPutMetricData
というAPIを使用します。
- PutMetricData API https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_PutMetricData.html
put-metric-data
以下のput-metric-data
コマンドでは、Namespace=JawsCLI
、Metric Name=TestMetrics
、Dimensions=[TestKey=TestValue]
という識別値に対して、100
という値をPutしています。
$ aws cloudwatch put-metric-data --namespace JawsCLI --metric-name TestMetric --dimensions TestKey=TestValue --value 100
ちなみに、ここではtimestamp
とunit
を指定していません。
CloudWatchはこの場合、timestamp=(現在日時)
、unit=None
を自動で使用します。
List
CloudWatchではメトリクスのListにListMetrics
というAPIを使用します。
- ListMetrics API https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_ListMetrics.html
list-metrics
以下のlist-metrics
コマンドでは、Namespace=JawsCLI
配下のメトリクスをすべて表示しています。
$ aws cloudwatch list-metrics --namespace JawsCLI
{
"Metrics": [
{
"Namespace": "JawsCLI",
"MetricName": "TestMetric",
"Dimensions": [
{
"Name": "TestKey",
"Value": "TestValue"
}
]
}
]
}
さきほどPutしたTestMetricsが確認できます。
なお、新しいメトリクスをPutしてからListできるようになるまでには、最大15分かかることがAPIドキュメントでも説明されています。ただ、ほとんどの場合、数十秒程度でListできますし、Getできるようになるまではもっと短い時間ですみます。
After you create a metric, allow up to fifteen minutes before the metric appears. Statistics about the metric, however, are available sooner using GetMetricData or GetMetricStatistics.
Get
CloudWatchではメトリクスのGetにGetMetricStatistics
とGetMetricData
というAPIを使用します。
- GetMetricStatistics API https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetMetricStatistics.html
- GetMetricData API https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetMetricData.html
get-metric-statistics
以下のget-metric-statistics
コマンドでは、Namespace=JawsCLI
、Metric Name=TestMetrics
、Dimensions=[TestKey=TestValue]
という識別値にひもづくメトリクスの平均値を60秒粒度で、15分前から現在の分まで取得しています。
$ aws cloudwatch get-metric-statistics --namespace JawsCLI --metric-name TestMetric --dimensions Name=TestKey,Value=TestValue --period 60 --statistics Average --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ")
{
"Label": "TestMetric",
"Datapoints": [
{
"Timestamp": "2020-03-02T07:27:00Z",
"Average": 100.0,
"Unit": "None"
}
]
}
get-metric-data
以下のget-metric-data
コマンドでは、Namespace=JawsCLI
、Metric Name=TestMetrics
、Dimensions=[TestKey=TestValue]
という識別値にひもづくメトリクスの平均値を60秒粒度で、15分前から現在の分まで取得しています。
なお、今回はCLIの引数にJSON文字列を含めていますが、file://
プレフィックスによりJSONファイルから読み取らせることもできます。
$ aws cloudwatch get-metric-data --metric-data-queries '{"Id":"q1","MetricStat":{"Metric":{"Namespace":"JawsCLI","MetricName":"TestMetric","Dimensions":[{"Name":"TestKey","Value":"TestValue"}]},"Period":60,"Stat":"Average"}}' --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ")
{
"MetricDataResults": [
{
"Id": "q1",
"Label": "TestMetric",
"Timestamps": [
"2020-03-02T07:56:00Z"
],
"Values": [
100.0
],
"StatusCode": "Complete"
}
],
"Messages": []
}
上記のように、GetMetricStatistics
とGetMetricData
はいずれもメトリクスの取得に使用できます。
違いについては以下のドキュメントに記述があります。
基本的には何も考えずにGetMetricData
を使えばOKです。
参考: CloudWatch メトリクスでは、GetMetricData または GetMetricStatistics を使用する必要がありますか?
https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudwatch-getmetricdata-api/
複数メトリクス同時処理
CloudWatchはAPIごとに秒間実行数の上限値をもちます。また、CloudWatchはAPIコールに課金するサービスです。
このため、APIコール数を減らすことが、上限値の影響の回避、さらにコスト削減につながります。
CloudWatchメトリクスはPut時もGet時も、いずれも複数のメトリクスをまとめて処理できます。
Put
put-metric-data
に--metric-name
などの代わりに--metric-data
を指定するのがポイントです。
$ cat metrics.json
[
{
"MetricName": "TestMetric1",
"Dimensions": [
{
"Name": "TestKey",
"Value": "TestValue"
}
],
"Value": 100
},
{
"MetricName": "TestMetric2",
"Dimensions": [
{
"Name": "TestKey1",
"Value": "TestValue1"
},
{
"Name": "TestKey2",
"Value": "TestValue2"
}
],
"Value": 200
}
]
$ aws cloudwatch put-metric-data --namespace JawsCLI --metric-data file://./metrics.json
なお、複数のメトリクスを同時にPutする場合、Metric Name
やDimensions
は全く異なるものを同時に扱うことができますが、Namespace
は同一である必要があります。
List
$ aws cloudwatch list-metrics --namespace JawsCLI
{
"Metrics": [
{
"Namespace": "JawsCLI",
"MetricName": "TestMetric",
"Dimensions": [
{
"Name": "TestKey",
"Value": "TestValue"
}
]
},
{
"Namespace": "JawsCLI",
"MetricName": "TestMetric1",
"Dimensions": [
{
"Name": "TestKey",
"Value": "TestValue"
}
]
},
{
"Namespace": "JawsCLI",
"MetricName": "TestMetric2",
"Dimensions": [
{
"Name": "TestKey2",
"Value": "TestValue2"
},
{
"Name": "TestKey1",
"Value": "TestValue1"
}
]
}
]
}
Get
先述の通り、GetにはGetMetricStatistics
とGetMetricData
のふたつのAPIがありますが、複数のメトリクスを同時に扱うには、GetMetricData
を使う必要があります。
$ aws cloudwatch get-metric-data --metric-data-queries '[{"Id":"q1","MetricStat":{"Metric":{"Namespace":"JawsCLI","MetricName":"TestMetric1","Dimensions":[{"Name":"TestKey","Value":"TestValue"}]},"Period":60,"Stat":"Average"}},{"Id":"q2","MetricStat":{"Metric":{"Namespace":"JawsCLI","MetricName":"TestMetric2","Dimensions":[{"Name":"TestKey1","Value":"TestValue1"},{"Name":"TestKey2","Value":"TestValue2"}]},"Period":60,"Stat":"Average"}}]' --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ")
{
"MetricDataResults": [
{
"Id": "q1",
"Label": "TestValue TestMetric1",
"Timestamps": [
"2020-03-02T08:19:00Z"
],
"Values": [
100.0
],
"StatusCode": "Complete"
},
{
"Id": "q2",
"Label": "TestValue1 TestValue2 TestMetric2",
"Timestamps": [
"2020-03-02T08:19:00Z"
],
"Values": [
200.0
],
"StatusCode": "Complete"
}
],
"Messages": []
}
Put時とは異なり、GetMetricData
でメトリクスを複数同時に扱う場合は、Namespace
、Metric Name
、Dimensions
のいずれも全く異なるものを同時に扱うことができます。
メトリック計算
CloudWatchメトリクスには、複数のメトリクスをもとに算出した値を取得する機能があります。
Put
ここでは、サンプルとしてInvocations
とErrors
という2種類のメトリクスを用意して、(Lambda関数のような)エラーレートを算出してみましょう。
先述の他のサンプルのように、put-metric-data
でまとめてメトリクスをPutしますが、今回は数が多いのでJSONファイルに外出しします。
$ cat metric-data.json
[
{
"MetricName": "Invocations",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
],
"Timestamp": "2020-03-02T08:00:00Z",
"Value": 10
},
{
"MetricName": "Invocations",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
],
"Timestamp": "2020-03-02T08:05:00Z",
"Value": 10
},
{
"MetricName": "Invocations",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
],
"Timestamp": "2020-03-02T08:10:00Z",
"Value": 10
},
{
"MetricName": "Invocations",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
],
"Timestamp": "2020-03-02T08:15:00Z",
"Value": 10
},
{
"MetricName": "Invocations",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
],
"Timestamp": "2020-03-02T08:20:00Z",
"Value": 10
},
{
"MetricName": "Errors",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
],
"Timestamp": "2020-03-02T08:00:00Z",
"Value": 3
},
{
"MetricName": "Errors",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
],
"Timestamp": "2020-03-02T08:05:00Z",
"Value": 6
},
{
"MetricName": "Errors",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
],
"Timestamp": "2020-03-02T08:10:00Z",
"Value": 2
},
{
"MetricName": "Errors",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
],
"Timestamp": "2020-03-02T08:15:00Z",
"Value": 9
},
{
"MetricName": "Errors",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
],
"Timestamp": "2020-03-02T08:20:00Z",
"Value": 1
}
]
$ aws cloudwatch put-metric-data --namespace MyApplication --metric-data file://./metric-data.json
Get
では、メトリクス計算により算出された値を取得してみましょう。
まず、あらかじめ算出用のクエリを用意します。
ここでは、m1
とm2
に定義したメトリクスにe1
でm1/m2
という式を適用しています。
$ cat metric-data-queries.json
[
{
"Id": "e1",
"Expression": "m1 / m2",
"Label": "ErrorRate"
},
{
"Id": "m1",
"MetricStat": {
"Metric": {
"Namespace": "MyApplication",
"MetricName": "Errors",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
]
},
"Period": 300,
"Stat": "Sum"
},
"ReturnData": true
},
{
"Id": "m2",
"MetricStat": {
"Metric": {
"Namespace": "MyApplication",
"MetricName": "Invocations",
"Dimensions": [
{
"Name": "FunctionName",
"Value": "MyFunc"
}
]
},
"Period": 300,
"Stat": "Sum"
},
"ReturnData": true
}
]
メトリクス計算にはGetMetricData
を使用します。
$ aws cloudwatch get-metric-data --metric-data-queries file://./metric-data-queries.json --start-time 2020-03-02T08:00:00Z --end-time 2020-03-02T08:30:00Z
{
"MetricDataResults": [
{
"Id": "m1",
"Label": "Errors",
"Timestamps": [
"2020-03-02T08:20:00Z",
"2020-03-02T08:15:00Z",
"2020-03-02T08:10:00Z",
"2020-03-02T08:05:00Z",
"2020-03-02T08:00:00Z"
],
"Values": [
2.0,
18.0,
4.0,
12.0,
6.0
],
"StatusCode": "Complete"
},
{
"Id": "m2",
"Label": "Invocations",
"Timestamps": [
"2020-03-02T08:20:00Z",
"2020-03-02T08:15:00Z",
"2020-03-02T08:10:00Z",
"2020-03-02T08:05:00Z",
"2020-03-02T08:00:00Z"
],
"Values": [
20.0,
20.0,
20.0,
20.0,
20.0
],
"StatusCode": "Complete"
},
{
"Id": "e1",
"Label": "ErrorRate",
"Timestamps": [
"2020-03-02T08:20:00Z",
"2020-03-02T08:15:00Z",
"2020-03-02T08:10:00Z",
"2020-03-02T08:05:00Z",
"2020-03-02T08:00:00Z"
],
"Values": [
0.1,
0.9,
0.2,
0.6,
0.3
],
"StatusCode": "Complete"
}
],
"Messages": []
}
e1
で返却されたJSONに、算出されたエラーレートが0.1
, 0.9
等のように確認できます。
統計とパーセンタイル
CloudWatchメトリクスは、Putされたデータを生データのままもつわけではなく、すべて統計値として保管します。
これは、CloudWatchメトリクスがポーリング型のメトリクス収集サービスではなく、メトリクスの登録を待ち受けるかたちのサービスであるためです。
例えば、同じ時間帯(2020-03-02T09:00:00Z
)に異なる値(3,6,9
)をそれぞれ登録したとき、どうすべきでしょうか?後勝ちにして9
で上書きしちゃう?上書き禁止にして3
を採用しちゃう?
CloudWatchではこのような問題は実は起こりません。
なぜなら、すべてのデータを統計値として扱うためです。
この例では、3,6,9
をすべて登録して統計値を計算し、サンプル数=3, 平均=6, 最大=9, 最小=6, 合計=12
というデータとして扱う、ということになります。
標準の統計であるSampleCount
, Maximum
, Minimum
, Average
, Sum
で統計値が変わるのか、さらに異なるパーセンタイル値を指定するとどのような結果が得られるのかを見ていきましょう。
Put
aws cloudwatch put-metric-data --namespace JawsCLI --metric-name Test --value 20
aws cloudwatch put-metric-data --namespace JawsCLI --metric-name Test --value 20
aws cloudwatch put-metric-data --namespace JawsCLI --metric-name Test --value 20
aws cloudwatch put-metric-data --namespace JawsCLI --metric-name Test --value 90
aws cloudwatch put-metric-data --namespace JawsCLI --metric-name Test --value 20
Get
統計(標準)
ここではget-metric-statistics
コマンドの--statistics
に異なる統計をそれぞれ指定した結果をみていきます。
$ aws cloudwatch get-metric-statistics --namespace JawsCLI --metric-name Test --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --period 300 --statistics SampleCount
{
"Label": "Test",
"Datapoints": [
{
"Timestamp": "2020-03-02T08:55:00Z",
"SampleCount": 5.0,
"Unit": "None"
}
]
}
$ aws cloudwatch get-metric-statistics --namespace JawsCLI --metric-name Test --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --period 300 --statistics Maximum
{
"Label": "Test",
"Datapoints": [
{
"Timestamp": "2020-03-02T08:55:00Z",
"Maximum": 90.0,
"Unit": "None"
}
]
}
$ aws cloudwatch get-metric-statistics --namespace JawsCLI --metric-name Test --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --period 300 --statistics Minimum
{
"Label": "Test",
"Datapoints": [
{
"Timestamp": "2020-03-02T08:55:00Z",
"Minimum": 20.0,
"Unit": "None"
}
]
}
$ aws cloudwatch get-metric-statistics --namespace JawsCLI --metric-name Test --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --period 300 --statistics Average
{
"Label": "Test",
"Datapoints": [
{
"Timestamp": "2020-03-02T08:55:00Z",
"Average": 34.0,
"Unit": "None"
}
]
}
$ aws cloudwatch get-metric-statistics --namespace JawsCLI --metric-name Test --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --period 300 --statistics Sum
{
"Label": "Test",
"Datapoints": [
{
"Timestamp": "2020-03-02T08:55:00Z",
"Sum": 170.0,
"Unit": "None"
}
]
}
統計(パーセンタイル)
ここではget-metric-statistics
コマンドの--extended-statistics
に異なるパーセンタイル値をそれぞれ指定した結果をみていきます。
$ aws cloudwatch get-metric-statistics --namespace JawsCLI --metric-name Test --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --period 300 --extended-statistics p95
{
"Label": "Test",
"Datapoints": [
{
"Timestamp": "2020-03-02T08:56:00Z",
"Unit": "None",
"ExtendedStatistics": {
"p95": 89.54594678486895
}
}
]
}
$ aws cloudwatch get-metric-statistics --namespace JawsCLI --metric-name Test --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --period 300 --extended-statistics p90
{
"Label": "Test",
"Datapoints": [
{
"Timestamp": "2020-03-02T08:57:00Z",
"Unit": "None",
"ExtendedStatistics": {
"p90": 89.09418428442875
}
}
]
}
$ aws cloudwatch get-metric-statistics --namespace JawsCLI --metric-name Test --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --period 300 --extended-statistics p50
{
"Label": "Test",
"Datapoints": [
{
"Timestamp": "2020-03-02T08:57:00Z",
"Unit": "None",
"ExtendedStatistics": {
"p50": 20.689021529142646
}
}
]
}
$ aws cloudwatch get-metric-statistics --namespace JawsCLI --metric-name Test --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "15 min ago") --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") --period 300 --extended-statistics p10
{
"Label": "Test",
"Datapoints": [
{
"Timestamp": "2020-03-02T08:57:00Z",
"Unit": "None",
"ExtendedStatistics": {
"p10": 20.135943634260624
}
}
]
}
ここで、10パーセンタイル値として返却された20.135943634260624
みたいな値は実際にPutしたデータではなく、算出されたパーセンタイル値であることが見て取れるかと思います。
おわりに
今回は、JAWS-UG CLI専門支部への参加のお土産(?)として、CloudWatchの各機能をAWS CLIで扱うサンプルを書いてみました。
CloudWatchはもちろんサービスとしても便利ですが、数値をもつ時系列データベースのような使い方もできちゃう柔軟性の高いサービスですので、AWS CLIとの相性がとてもよいかと思います。
ぜひAWS CLIでCloudWatchメトリクスを使い倒してみていただけたら幸いです。