Azure AppService のログストリームを Terminal から監視する(Docker使用)

Azure ポータルを開くのがめんどうな方向け情報です。

## 1. Azure AppService でログストリームを有効にする

AppService 作成直後は、OFF になっていたので、 左メニュー → App Service ログ から有効化します。
Blob でも良いのかも知れませんし、「詳細なエラーメッセージ」が何を意味するのかはよく分かっていません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8227/3e2fd291-d113-ba7f-942a-4f0ceb2b778a.png)

## 2. ログストリームを確認する

左メニューから ログストリーム を選択し、Web画面上でログが表示できることを確認します。
次の図は、ログ待機状態で bot のデプロイをしてみた時の様子です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8227/8a955a9a-761a-3de2-89a6-87eaf3e75637.png)

## 3. Terminal でログインする

ここからはクライアントのターミナル(PowerShell)で作業します。たぶんコマンドプロンプトでも大丈夫だし、macOS でもおｋ。

Azure CLI をインストールするのが面倒なので、提供されている Docker イメージを使用します。
次のこまんどで、Azure CLI コンテナを起動し、bash に入ります。

```terminal
docker run -it mcr.microsoft.com/azure-cli

bash-5.0#
```

## 4. Azure にログインして「サービスプリンシパル」なるものを作成する

Azure に CLI からログインしないと AppService のログストリームにアクセスできません。
ユーザーとの対話なしにログインできるように、「サービスプリンシパル」というものを作成します。

まずは、対話型で Azure にログインします。

```bash
bash-5.0# az login

To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code GD3M62X89 to authenticate.
```

と出るので、URL にアクセスして code を入力し、ブラウザでログインします。

ログインできたら、次のコマンドを実行します。

```bash
bash-5.0# az ad sp create-for-rbac --name ＜your-service-principal-name＞
```

＜your-service-principal-name＞ には、管理しやすい名前を付けますが正直よくわからないので ``my-first-principal`` としておきます。

実行すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8227/7ae4378f-4bbc-c52d-88f4-074df564ddda.png)

のような結果が出力されるので、

- appId
- password
- tenant

を控えておきます。

## 5. サービスプリンシパルの権限を設定する

作成したサービスプリンシパルは、「共同作成者(Contributor)」ロールを持っているとの事で、ログを見たいだけなのに権限過多で危険なので、ロールを変更するために、次のコマンドを実行します。

```bash
bash-5.0# az role assignment create --assignee ＜appId＞ --role "Website Contributor"
bash-5.0# az role assignment delete --assignee ＜appId＞ --role "Contributor"
```

＜appId＞ は、前項で控えておいたものです。

[Website Contributor](https://docs.microsoft.com/ja-jp/azure/role-based-access-control/built-in-roles#website-contributor) というロールは、AppService のログの読み取りだけでなく、Webサイトの作成や管理もできてしまうようですが、他に適切な組み込みロールが見つからなかったので妥協します。組み込みロール以外の方法で、さらに目的の機能のみを許可できるのでしょう。

## 6. appId, password, tenant を使って Azure CLI でログインする

4 でメモした情報を使って Azure CLI で「非対話」ログインします。

まず、ログアウトします。

```bash
bash-5.0# az logout
```

appId, password, tenant でログインします。

```bash
bash-5.0# az login --service-principal --username ＜appId＞ --password "＜password＞" --tenant ＜tenant＞
```

password は記号などが含まれるので "" で囲んだほうが無難ですね。

## 7. Terminal から AppService のログストリームを監視する

```bash
bash-5.0# az webapp log tail --name ＜AppService名＞ --resource-group ＜ResourceGroup名＞
```

＜AppService名＞ と ＜ResourceGroup名＞ は、Azure ポータルの AppService の概要で確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8227/30acbec2-7c2c-e3eb-4bbf-baa9f331fc45.png)

次の図は、Windows Terminal で AppServiceのログストリームを監視している様子です。Web画面と同じく、AppService のコンソール出力が見られるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8227/2a5e6829-7105-3f7a-b4da-f76bdcc3a6d6.png)

## 8. 一発で監視を呼び出せるようにする

docker run して az login して az webapp log するのは面倒なので、コマンド一発で実行できるようにします。
docker-compose を使った方が楽です。

適当なディレクトリを作成（ここでは ``log`` ディレクトリとします）して、その中に ``log_tail.sh`` を作成し、次の内容を記述します。

**log_tail.sh**

```sh
#!/bin/bash

az login --service-principal \
         --username "c22b88da-35d7-4044-xxx-xxxxxxxx" \
         --password "xxxxxxxxxxxxxxxxxxxxx" \
         --tenant "da519484-d2e7-4d6b-xxxx-xxxxxxxx" \
         --output none

az webapp log tail \
         --name mybot001 \
         --resource-group my_bot_001_rc
```

パラメータ部分は、上で記述した自分の環境に置き換えてください。
また az login に ``--output none`` を追加しました。ログイン完了結果が出力されてしまうのが邪魔だったのでそれを無くしました。

次に同じディレクトリの中に ``docker-compose.yml`` を作成し、次の内容を記述します。

**docker-compose.yml**

```yaml
version: '2'
services:
  log-tail:
    image: mcr.microsoft.com/azure-cli
    volumes:
      - .:/work
    working_dir: /work
    command: bash log_tail.sh
```

Azure CLI のイメージからコンテナを定義し、起動時に ``log_tail.sh`` を実行します。

これを Terminal で実行します。

```terminal
# log ディレクトリに移動してから実行
cd log
docker-compose run --rm log-tail

# log ディレクトリ外から実行
cd ..
docker-compose -f ./log/docker-compose.yml run --rm log-tail
```

これで、一発で AppService のログ監視ができるようになりました。
私は Bot 開発を node.js で行っているので、package.json の scripts に次の用に登録して、

```json
{
    "name": "my-bot",
    "version": "1.0.0",
    "scripts": {
        "log-tail": "docker-compose -f ./scripts/log/docker-compose.yml run --rm log-tail",
        ＜以下省略＞
```

``npm run log-tail`` または ``yarn log-tail`` で呼び出せるようにしています。とても便利になりました。

**注意:** log_tail.sh にパスワードなどの秘匿情報を直書きしてしまっているので、環境変数などに外出しすべきですね。。。

## 9. サービスプリンシパルを削除する

使用しなくなった、または不正使用が判った場合は、サービスプリンシパルを削除して、非対話ログインを無効にします。

1. まず、対話の ``az login`` を行います。
2. 次に、``az ad sp list --all`` でサービスプリンシパルの一覧を表示します([出力結果をカスタマイズ](https://dev.classmethod.jp/articles/form-aws-cli-output-by-jmespath/) できるようなので、調整すると見やすくなると思われますが、私には難しすぎた…、 ``--display-name my-first`` で絞り込むのは簡単です)。
3. 目的のサービスプリンシパルを見つけて appID を控えます。
4. パスワードなどを変更する場合は、 ``az ad sp credential reset --name ＜appID＞`` を実行します。新しいパスワードが発行されます。
5. プリンシパルを削除する場合は、 ``az ad sp delete --id ＜appID＞`` を実行します。

## 参考

- [診断ログの有効化 - Azure App Service | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/app-service/troubleshoot-diagnostic-logs)
- [Azure CLI で Azure サービス プリンシパルを使用する | Microsoft Docs](https://docs.microsoft.com/ja-jp/cli/azure/create-an-azure-service-principal-azure-cli?view=azure-cli-latest#create-a-service-principal)
- [Azure 組み込みロール - Azure RBAC | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/role-based-access-control/built-in-roles)
- [Azure CLI を使用してサインインする | Microsoft Docs](https://docs.microsoft.com/ja-jp/cli/azure/authenticate-azure-cli?view=azure-cli-latest#sign-in-with-credentials-on-the-command-line)
- [Azure App Service からログをストリーム配信する | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/developer/javascript/tutorial-vscode-azure-cli-node-05)