Azure CLIからAzureメトリックを収集するコマンド(az monitor metrics list)



#1. はじめに
<!-- 自己紹介や発端や概要を記載 -->
　ATLシステムズの田中です。今回は、**az monitor metrics list**という便利なAzure CLIのコマンドを見つけましたので紹介します。
経緯として、私が案件で**Azure**(クラウド環境)に触ることになり、定期的にリソースのメトリック(稼働状況)を収集していました。メトリックの収集作業では、Azure Portalから**毎回手打ちで日付時刻を指定して、種類ごとファイルをダウンロード・・・と、とても手間がかかっていた**ということがあります。

そこで、Azureに興味を持っている方や、同じことで悩んでいる方を対象に、**az monitor metrics list**の使い方について、解説しようと思います。

本記事のゴールは、**このような書き方で使えます。ということを知ってもらうところ**ですので、お忙しい方は、[3.完成したコード](#3-完成したコード)まで、読んでいただければOKです。それ以外の方は、お気楽に、最後まで読んでいただけると嬉しいです。

**※免責事項(必ず、ご一読ください)**
　　本記事の情報により生じた、いかなる損害や損失についても、当社は一切の責任を負いかねます。
　　また、誤情報が入り込んだり、情報が古くなったりすることもありますので、必ずしも正確性を保証するものではありませんのでご了承ください。

#2. az monitor metrics listついて
　az monitor コマンドのうち、Azure リソースのメトリックを表示するオプションです。
　本来、az monitorコマンドは、本来Azure Monitor サービスを管理するために使われるものですが、今回はそのうちの、**az monitor metrics**(Azure リソースのメトリックを表示)をメトリック収集のために活用します。
　URL：[az monitor](https://docs.microsoft.com/ja-jp/cli/azure/monitor?view=azure-cli-latest)

azコマンドのメリット：Windowsなど各種OSにて、[Azure CLI](https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli)をインストールすれば実行できるので、Windowsならば.batによる自動化に応用することが可能です。

#3. 完成したコード
本記事の以降の章の例にならって完成させたコードは下記です。

```ruby:完成したazコマンド例
call az login --tenant ドメイン名
call az monitor metrics list --resource "/subscriptions/サブスクリプションのGUID値/resourceGroups/TANA-Test-RG/providers/Microsoft.Web/sites/TestQiitaAppService" --metric AverageMemoryWorkingSet --aggregation maximum average --start-time 2021-06-01T00:00:00+09:00 --end-time 2021-06-30T23:59:59+09:00 --interval PT24H
```
オプションの詳しい設定方法は、以降の章をご参照下さい。
取得結果は、量が多いので、[12.付録2](#12-付録2)のレスポンスを参照してください。


#4. 全体の流れ
　今回は、私が社内で作成したAppServiceのリソースのメモリ使用量の最大値、平均値のメトリックを取得したい場合を例にとり解説します。

　[5.リソースグループの特定](#5-リソースグループの特定)
　[6.リソースとメトリックの特定](#6-リソースとメトリックの特定)
　[7.コマンド作成](#7-コマンド作成)
　[8.メトリックログ収集](#8-メトリックログ収集)

#5. リソースグループの特定
　AzurePortalよりリソースグループを特定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661584/178dfb1d-3aad-9512-03f3-820c40b64806.png)
　もし作っていない場合は、[10.付録1](#10-付録1)を参照すること。


#6. リソースとメトリックの特定
　まず、Azure上のリソース名、リソースIDとメトリック名を特定する必要あり。

 ・リソース種類：Azure Virtual Machine / App Service / Azure SQL Server /等...
　　　　　　　　メトリックを持つAzure上のリソースが対象。
 ・リソース名：QiitTestAppService
　　Azureポータル→App Service→App Serviceの名前列　から取得できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661584/1425123c-40a1-a8e8-6005-52513e12cf20.png)
　<font color="Blue">青枠・・・検索フォーム</font>
　<font color="Red">赤枠・・・該当項目</font>

 ・メトリック名：Average memory working set
　　　Azureポータル→App Service→App Service 名前列→メトリック→メトリックプルダウン選択の一覧　から取得できる。App Serviceならば、よく使用されそうな下記メトリックも取得可能。
　　　メモリ使用量 例：**Average memory working set**(平均値、最小値、最大値)
　　　CPU使用時間　例：**CPU Time**(平均値、最小値、最大値)
　　　データ通信量 例：**Data In**(合計),**Data Out**(合計)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661584/81d5bcdf-84c2-6333-2d1e-a859e5f5871d.png)
/subscriptions/"サブスクリプションのGUID値"
 ・リソースID：/subscriptions/サブスクリプションのGUID値/resourcegroups/TANA-Test-RG/providers/Microsoft.Web/sites/TestQiitaAppService
　　　　Azureポータル→リソース名→プロパティ→リソースID　から取得できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661584/22987791-a913-b96b-c45b-a5be1b886d5e.png)
※なお、セキュリティの関係上、文字を伏せている箇所がありますが、ご了承ください。
　"サブスクリプションのGUID値"は、この欄で取得できた実際のGUID値に読み替えてください。
#7. コマンド作成
メトリック収集では、azコマンドを使用するが、Azure CLIというものが必要である。
下記リンクから、まず、Azure CLIをインストールする。
- [Azure CLI　ダウンロードサイト](https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli)

インストール後、azコマンドが、コマンドプロンプトから実行できるか、ログインコマンドを使用して確認する。

```azコマンド1
call az login --tenant ドメイン名
```
Azure Active Directoryの認証が走るはずなので、自分のAzureに登録したアカウントを入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661584/5120ee47-bbfe-fe4a-e4ac-c1a22c1e314d.png)

・わざとBadRequestが返ってくる発行コマンドを実行し、オプションごとのBadRequestのレスポンスを下記コマンドで取得する。
"サブスクリプションのGUID値"

```ruby:azコマンド2
call az monitor metrics list --resource "/subscriptions/サブスクリプションのGUID値/resourceGroups/TANA-Test-RG/providers/Microsoft.Web/sites/TestQiitaAppService" --metric test
```
```ruby:レスポンス
(BadRequest) Failed to find metric configuration for provider: Microsoft.Web, resource Type: sites, metric: test, Valid metrics:CpuTime,Requests,BytesReceived,BytesSent,Http101,Http2xx,Http3xx,Http401,Http403,Http404,Http406,Http4xx,Http5xx,MemoryWorkingSet,AverageMemoryWorkingSet,AverageResponseTime,HttpResponseTime,AppConnections,Handles,Threads,PrivateBytes,IoReadBytesPerSecond,IoWriteBytesPerSecond,IoOtherBytesPerSecond,IoReadOperationsPerSecond,IoWriteOperationsPerSecond,IoOtherOperationsPerSecond,RequestsInApplicationQueue,CurrentAssemblies,TotalAppDomains,TotalAppDomainsUnloaded,Gen0Collections,Gen1Collections,Gen2Collections,HealthCheckStatus,FileSystemUsage
```

metric:を抜粋すると

```ruby:metrics
metric: test, Valid metrics: CpuTime,Requests,BytesReceived,BytesSent,Http101,Http2xx,Http3xx,Http401,Http403,Http404,Http406,Http4xx,Http5xx,MemoryWorkingSet,AverageMemoryWorkingSet,AverageResponseTime,HttpResponseTime,AppConnections,Handles,Threads,PrivateBytes,IoReadBytesPerSecond,IoWriteBytesPerSecond,IoOtherBytesPerSecond,IoReadOperationsPerSecond,IoWriteOperationsPerSecond,IoOtherOperationsPerSecond,RequestsInApplicationQueue,CurrentAssemblies,TotalAppDomains,TotalAppDomainsUnloaded,Gen0Collections,Gen1Collections,Gen2Collections,HealthCheckStatus,FileSystemUsage
```
AzurePortalで確認したAverage memory working setを取得したいので、上記で一番近いmetric、AverageMemoryWorkingSetを指定して、コマンドを作成しなおす。
--aggregationにどんな値が指定できるのかを下記コマンドで確認する。

```ruby:azコマンド3
call az monitor metrics list --resource "/subscriptions/サブスクリプションのGUID値/resourceGroups/TANA-Test-RG/providers/Microsoft.Web/sites/TestQiitaAppService" --metric AverageMemoryWorkingSet
```
```ruby:レスポンス
{
  "cost": 59,
  "interval": "0:01:00",
  "namespace": "Microsoft.Web/sites",
  "resourceregion": "japaneast",
  "timespan": "2021-07-01T06:49:09Z/2021-07-01T07:49:09Z",
  "value": [
    {
      "displayDescription": "The average amount of memory used by the app, in megabytes (MiB).",
      "errorCode": "Success",
      "id": "/subscriptions/サブスクリプションのGUID値/resourceGroups/TANA-Test-RG/providers/Microsoft.Web/sites/TestQiitaAppService/providers/Microsoft.Insights/metrics/AverageMemoryWorkingSet",
      "name": {
        "localizedValue": "Average memory working set",
        "value": "AverageMemoryWorkingSet"
      },
      "resourceGroup": "TANA-Test-RG",
      "timeseries": [
        {
          "data": [
            {
              "average": 0.0,
              "count": null,
              "maximum": null,
              "minimum": null,
              "timeStamp": "2021-07-01T06:49:00+00:00",
              "total": null
            },
            {
　　　　　　　　：～省略～
```

　ここで、"localizedValue"の値を確認する。"Average memory working set"と表示されていれば、Azure Portalのメトリック上で表示されていた、"Average memory working set"という文字列と一致するため、欲しいメトリックであることが確認できる。
 **"localizedValue"の値が欲しいメトリック名と一致**　　→以降の手順に進んでよい。
 **"localizedValue"の値が欲しいメトリック名と不一致**　→上記azコマンド3のmetricオプションに近い名前に変更しながら、実行と確認を繰り返すこと。（要は、ローラー作戦。）
　
"data":[{ }]の中身を見ると、"average","count","maximum,"minimum","timeStamp","total"が--aggregationに指定できることがわかる。シチュエーションを思い出すと、最大値、平均値の両方を取得してみたいので、maximum averageの両方を指定してみる。

```ruby:azコマンド
call az monitor metrics list --resource "/subscriptions/サブスクリプションのGUID値/resourceGroups/TANA-Test-RG/providers/Microsoft.Web/sites/TestQiitaAppService" --metric AverageMemoryWorkingSet --aggregation maximum average
```
```ruby:レスポンス
{
  "cost": 118,
  "interval": "0:01:00",
  "namespace": "Microsoft.Web/sites",
  "resourceregion": "japaneast",
  "timespan": "2021-07-01T06:52:34Z/2021-07-01T07:52:34Z",
  "value": [
    {
      "displayDescription": "The average amount of memory used by the app, in megabytes (MiB).",
      "errorCode": "Success",
      "id": "/subscriptions/サブスクリプションのGUID値/resourceGroups/TANA-Test-RG/providers/Microsoft.Web/sites/TestQiitaAppService/providers/Microsoft.Insights/metrics/AverageMemoryWorkingSet",
      "name": {
        "localizedValue": "Average memory working set",
        "value": "AverageMemoryWorkingSet"
      },
      "resourceGroup": "TANA-Test-RG",
      "timeseries": [
        {
          "data": [
　　　　　　　　：～省略～
            {
              "average": 150277120.0,
              "count": null,
              "maximum": 152150016.0,
              "minimum": null,
              "timeStamp": "2021-07-01T07:12:00+00:00",
              "total": null
            },
            {
              "average": 149686272.0,
              "count": null,
              "maximum": 149688320.0,
              "minimum": null,
              "timeStamp": "2021-07-01T07:13:00+00:00",
              "total": null
            },
            {
              "average": 149645312.0,
              "count": null,
              "maximum": 149667840.0,
              "minimum": null,
              "timeStamp": "2021-07-01T07:14:00+00:00",
              "total": null
            },
　　　　　　　　：～省略～
```
平均値(average)と最大値(maximum)が無事取れている。しかし、ここで**"timeStamp"**には問題がある。

**問題：**デフォルトでは、集計スパンは1分刻みで、過去1時間しか指定しておらず、しかもUTC(協定世界時＝日本標準時-9:00)で出力する期間をコマンドが受け取ってしまう。
**解決策：**日本標準時→UTCと+9：00して修正し、期間を--start-time,--end-timeに指定し、集計スパンを-intervalに指定する。

```ruby:例：6/1～6/31までを1日スパンで集計したメトリックログを収集する場合
 --start-time 2021-06-01T00:00:00+09:00 --end-time 2021-06-30T23:59:59+09:00 --interval PT24H
```

```ruby:完成したazコマンド
call az login --tenant "ドメイン名"
call az monitor metrics list --resource "/subscriptions/サブスクリプションのGUID値/resourceGroups/TANA-Test-RG/providers/Microsoft.Web/sites/TestQiitaAppService" --metric AverageMemoryWorkingSet --aggregation maximum average --start-time 2021-06-01T00:00:00+09:00 --end-time 2021-06-30T23:59:59+09:00 --interval PT24H
```
取得結果は、量が多いので、[11.付録2](#11-付録2)のレスポンスを参照してください。

#8. 次回
　目標は、CSV形式でメトリクスを出力することですので、次回は[jq](https://stedolan.github.io/jq/)で、JSON形式のメトリックを、CSV形式に加工する方法を紹介しようと思います。
→[JSONオブジェクト(メトリクスデータ)をcsvに変換する(jq.exe)](https://qiita.com/ATL_Tanaka/items/6bae0074ca7df71c62d6)

#9. 参考資料
- [az monitor metrics list 文法](https://docs.microsoft.com/ja-jp/cli/azure/monitor/metrics?view=azure-cli-latest)
- [Azure CLI　ダウンロードサイト](https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli)

#10. 最後に一言
　最後まで読んでいただき、ありがとうございます！　今後も様々なデータ分析、データ可視化、データ処理、IoT技術などの最新技術を取り込んでいこうと思います。
　余談ですが、弊社は**facebook**もしております！ぜひご覧ください！
　[![f_logo_RGB-Blue_64.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661584/81cb9432-5fc7-7dfd-0155-15a602114fa2.png)](https://www.facebook.com/atlsystems)

#11. 付録1
この章はまだリソースグループ、リソースを作成していない方向けです。
　・[リソースグループ作成](https://docs.microsoft.com/ja-jp/azure/azure-resource-manager/management/manage-resource-groups-portal)
　　　もし、作っていない場合は、下記を参考にして、リソースグループを作成。
　　　　
　・[App Service](https://docs.microsoft.com/ja-jp/azure/app-service/app-service-plan-manage)
　　　もし、リソースを作成していない場合、VMか上記の"App Service プランを作成する"("アプリを別の App Service プランに移動する"は実施不要。)

　・[IP制限](https://docs.microsoft.com/ja-jp/azure/app-service/app-service-ip-restrictions)
　　　まず、「IP制限」を必ずかけましょう。（デフォルトは全世界に公開(Dany All)なので）
　　　リソースにIP制限を構成。
　　　　"ネットワーク"→"アクセス制限を構成する"→"規則の追加"から設定できます。
　　　　
#12. 付録2
```ruby:レスポンス
{
  "cost": 86396,
  "interval": "1 day, 0:00:00",
  "namespace": "Microsoft.Web/sites",
  "resourceregion": "japaneast",
  "timespan": "2021-05-31T15:00:00Z/2021-06-30T14:59:59Z",
  "value": [
    {
      "displayDescription": "The average amount of memory used by the app, in megabytes (MiB).",
      "errorCode": "Success",
      "id": "/subscriptions/サブスクリプションのGUID値/resourceGroups/TANA-Test-RG/providers/Microsoft.Web/sites/TestQiitaAppService/providers/Microsoft.Insights/metrics/AverageMemoryWorkingSet",
      "name": {
        "localizedValue": "Average memory working set",
        "value": "AverageMemoryWorkingSet"
      },
      "resourceGroup": "TANA-Test-RG",
      "timeseries": [
        {
          "data": [
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-05-31T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-01T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-02T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-03T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-04T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-05T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-06T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-07T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-08T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-09T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-10T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-11T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-12T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-13T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-14T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-15T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-16T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-17T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-18T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-19T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-20T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-21T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-22T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-23T15:00:00+00:00",
              "total": null
            },
            {
              "average": 201014458.7672956,
              "count": null,
              "maximum": 228929536.0,
              "minimum": null,
              "timeStamp": "2021-06-24T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-25T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-26T15:00:00+00:00",
              "total": null
            },
            {
              "average": 0.0,
              "count": null,
              "maximum": 0.0,
              "minimum": null,
              "timeStamp": "2021-06-27T15:00:00+00:00",
              "total": null
            },
            {
              "average": 221577549.54347825,
              "count": null,
              "maximum": 391376151.0,
              "minimum": null,
              "timeStamp": "2021-06-28T15:00:00+00:00",
              "total": null
            },
            {
              "average": 147462620.27906978,
              "count": null,
              "maximum": 153468928.0,
              "minimum": null,
              "timeStamp": "2021-06-29T15:00:00+00:00",
              "total": null
            }
          ],
          "metadatavalues": []
        }
      ],
      "type": "Microsoft.Insights/metrics",
      "unit": "Bytes"
    }
  ]
}
```