KQLマジックを使ってAzureのログを分析する

# はじめに
Azureに日々溜まるログと格闘している皆さん こんにちは
Log Analytics(以下 LA)やApplication Insights(同 AI)のログどうやって分析してますか？

# TL;DR;
* LA/AIのポータルでの分析は不満がある
* KQLマジック+Azure Notebooksで解決！
* 最初は認証が分かりにくかった

# ポータル上でのログ クエリ
LAやAIではポータル組み込みのログ分析機能が提供されています。
<img src="https://docs.microsoft.com/ja-jp/azure/azure-monitor/log-query/media/get-started-portal/homepage.png" width="50%" />


LAやAIは Azure Data Explorer(Kusto)を基盤としているので、クエリ言語も同じKQL(Kusto Query Language)が利用できます。

インテリセンスもあり、ほどほどに使えますが、不満もあります。

* 不満点１ 結果の保存
実行結果の保存は**CSVかPowerBIへのエクスポートのみ**です。

* 不満点２ 結果を保持できない
テーブルで表示した後にグラフで見ようとすると、再度クエリが走ります。
render演算子で最初から描画すれば別ですが…
2種類のクエリの結果を突き合わせようにも、保存されないので、
統合したクエリを書いて、クエリ実行になるので、分析としては効率が悪いです。

* 不満点3 クエリの保存がいまいち
保存先が`共有`,`ユーザー`と2種類選べますが、いずれもリソース固有になります。
QAと本番等複数環境作っている場合、**環境毎に管理**することになり煩雑です。
また、リソースの内部にクエリが保存されるので、客先サブスク上の作業では汚すのに抵抗があります。
具体的には以下に保存されています。
  * Application Insights

```
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/microsoft.insights/components/{workspaceName}/analyticsItems
```

  * LogAnalytics

```
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}/savedSearches/
```
　　特にこちらは[Log Analytics Alert API](https://qiita.com/HiroyukiSakoh/items/3fb95e224b0640d11b8d#log-analytics-alert-api)関連でも参照する子リソースで、
　　テンプレートで投入する場所でもあり避けたいところです。

# KQLマジック
上記不満を解消して、サクサク分析できる方法を紹介します。

**[jupyter-Kqlmagic](https://github.com/Microsoft/jupyter-Kqlmagic)**です。
Jupyter Notebookから、KustoやApplication Insights、LogAnalyticsにKQLを投げられます。

ちなみに、[Azure Notebooks](https://notebooks.azure.com/)では、あらかじめインストールしてあるので、すぐ使えます。
(Notebook作成時はPython 3.6を選びましょう)

# つかいかた ざっくり

```python
#インストール(アップデート)して
!pip install Kqlmagic --no-cache-dir --upgrade
#ロードして
%reload_ext Kqlmagic
#接続(認証)して
%kql loganalytics://code;workspace='ワークスペースID';alias='YYYY';
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260166/67bb72a5-b35e-851c-b9fc-47a82d767c8f.png" width="50%" />

```python
#クエリ投げる！
%%kql AppServiceHTTPLogs
| summarize count() by bin(TimeGenerated,1h)
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260166/f3295099-1b8b-5617-8fb9-eac7d82a3051.png" width="50%" />

```python
#DataFrameにして、プロットとか
df = _.to_dataframe()
df.plot(x=0,y=1)
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260166/dde8e7ab-1c8f-2027-11c0-dc8d2b213889.png" width="50%" />

```python
#KQLのrenderも使える
%%kql AppServiceHTTPLogs
| summarize count() by bin(TimeGenerated,1h) 
| render  timechart 
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260166/96df5fae-402a-2433-8ff0-e0f65ea3f8ed.png" width="50%" />

## 認証
GitHubの説明では、認証方式として5種類提示されています。
基本的には`AADのコード`方式で良いと思います。

### AADのコード(デバイス コードフロー)
KQLMagicの出力するデバイスコードを[認証画面](https://aka.ms/devicelogin)に入力した後、AADにログインする方式です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260166/e97a3e49-170a-d5fe-6cf9-e2feabc24fb5.png" width="30%" />

```python
%kql loganalytics://code;workspace='全般>プロパティ>ワークスペースID';alias='YYYY';
%kql appinsights://code;appid='構成>APIアクセス>アプリケーションID';alias='YYYY';
#LAやAIの存在するAADテナントにゲストとして参加している場合
%kql loganalytics://code;workspace='全般>プロパティ>ワークスペースID';alias='YYYY';tenant='AADのテナントID'
%kql appinsights://code;appid='構成>APIアクセス>アプリケーションID';alias='YYYY';tenant='AADのテナントID'
```

AADのゲストアカウントはリソースのテナントIDをあらかじめ教えておかないと、以下の様なエラーが出ます。
```json
{"error":{"message":"The provided authentication is not valid for this resource","code":"InvalidTokenError"}}
```

### AADのID/PW
ヘルプには組織ネットワークでしか機能しないと書かれていますが、
組織ネットワーク上ってことはADなのか何なのか、結局この方式では認証を通すことができませんでした。
パスワードnotebookに書くのも気持ち悪い。

```python
%kql loganalytics://username='<username>';password='<password>';workspace='<workspace-id>';alias='<workspace-friendly-name>'
%kql appinsights://username='<username>';password='<password>';appid='<app-id>';alias='<appid-friendly-name>'
```
### AADのサービスプリンシパル(シークレット)
外部ゲストとして招待された、アプリ登録できないAADテナントのサブスクにある、LAやAIにアクセスしたかったので試していません。

```python
%kql loganalytics://tenant='<tenant-id>';clientid='<aad-appid>';clientsecret='<aad-appkey>';workspace='<workspace-id>';alias='<workspace-friendly-name>'
%kql appinsights://tenant='<tenant-id>';clientid='<aad-appid>';clientsecret='<aad-appkey>';appid='<app-id>';alias='<appid-friendly-name>'
```
### AppId/Key(AIのみ)
LAで使えないので…

```python
%kql appinsights://username='<username>';password='<password>';appid='<app-id>';alias='<appid-friendly-name>'
```

### 匿名(anonymous)
```python
%kql loganalytics://anonymous;workspace='<workspace-id>';alias='<workspace-friendly-name>'
%kql appinsights://anonymous;appid='<app-id>';alias='<appid-friendly-name>'
```
ヘルプにはローカルクラスタとか書かれてるけど、使いどころが不明…

# 参考
[GitHub jupyter-Kqlmagic](https://github.com/Microsoft/jupyter-Kqlmagic)
[Docs Azure Notebooks を使用した Kusto のクエリ](https://docs.microsoft.com/ja-jp/azure/kusto/tools/azurenotebooks)

# AzureDiagnosticsテーブル
そういえば、
Azure Monitorリソースログ(診断ログ)に[リソース ログ収集モード](https://docs.microsoft.com/ja-jp/azure/azure-monitor/platform/resource-logs-collect-workspace#resource-log-collection-mode)というのが増えてますね。

今まではAzureDiagnosticsだったのが、リソースタイプ固有のテーブルに格納されるようになるとか。
`移行の一環として、一部のリソースでは診断設定でモードを選択できる`らしいです。

再登場した[AppService](https://azure.github.io/AppService/2019/11/01/App-Service-Integration-with-Azure-Monitor.html)の診断ログは最初から`リソース固有モード`ですね。
他には`BastionHost`が`MicrosoftAzureBastionAuditLogs`テーブルに出てたり、
`StorageBlobLogs`テーブルが増えてるので、Blobの$logsにしか出せなかったログがLAに出せるように(アラートが使えるように)なりそう。

どのリソースが対応してるのか一覧がないので、使うリソースがどういう状態か 度々調べたほうがよさそうです。
**既存のアラートルールの突然死が怖いので、アナウンスなしで固有モード固定に変更とかはしないでね。。**

実は、`テーブルあたり500 のプロパティ制限`があるから、
`複数のサービスからリソースログを収集している場合、AzureDiagnostics は、この制限を超えることがあり、データが失われる可能性が`
あるそうで。DataFactoryを使ってると影響を受けやすい らしい。**もうちょっと大きな声でアナウンスしてほしい。**

# おわりに
VSCodeでもJupyter Notebookが使えるらしいので、PCスペックが高い方は そちらも良いでしょう。
私の客先貸与のノートPCは、**ストレージがHDD**で、Electron系アプリが死ぬほど重いので無理ですが。
Azure Notebooksがあってよかった。

KQLマジックを使って、良いログ分析ライフをお過ごしください！！