Azure Monitor for VMsで仮想マシンの中のプロセス一覧を取得する

Azure Monitor for VMsの中で、Dependency Agentというエージェントを入れると、仮想マシンの内部でTCP/UDPのコネクション情報と、OS上のプロセス情報を定期的に収集し、Log Analytics workspaceに転送してくれる。

その情報はAzureポータル画面のMapに表示されるが、どんなプロセスが今動いてるのか見るのにわざわざブラウザを開くのは面倒くさいはず。

特に、プロセス監視のような用途だと、せっかくのLog Analytics workspaceなのでAzure MonitorからKustoクエリを使って定期的に監視したくなるはず。
ということでやってみた。

まずは、Dependency Agentが転送してきてるログを見てみる。

Dependency Agentが集めた情報は、InsightsMetricsテーブルに時系列で保管される。また、マスター表として、コンピュータの一覧はVMComputerに、プロセスの一覧はVMProcessにそれぞれ保管される)
なお、過去のバージョンを使っている場合は、ServiceMapComputer_CLやServiceMapProcess_CLと言われる互換用のテーブルに保管されている場合があるが、今後は上記のInsightsMetrics/VMComputer/VMProcessテーブルのセットを使うことが推奨されている。
https://docs.microsoft.com/ja-jp/azure/azure-monitor/insights/vminsights-ga-release-faq

次に、InsightsMetricsテーブルの中から、プロセス情報を持っている行だけを絞り込んでみてみる。これには、Name列がHeartbeatで、Originがvm.azm.ms/mapなものにフィルタすると良い。

Tags列のJSONデータの中に、vm.azm.ms/processIdsとしてVMProcessテーブルのIDが羅列されて並んでいる。多分に、データ収集の都度Process情報全部(PID、ユーザ名、プロセス名、コマンドライン文字列、等々をもたせると重複が多くなりすぎるので別表に参照として飛ばしているのだろう。

で、VMProcessテーブルを眺めてみる。Dependency Agentは定期的(1分おき?)にOS上のプロセス一覧を取得しており、新規に開始されたプロセスがあれば、そのときだけLog Analytics workspaceのVMProcessテーブルに情報を上げてくるようだ。

ということで、InsightsMetricsテーブルと、VMProcessテーブルをうまく結合すれば良さそうである。

まずはInsightsMetricsテーブルから、コンピュータ名を指定して最新時点のプロセスID一覧を表示させてみる。(ちなみに変数宣言→問い合わせクエリのような複数の処理を実施するときは実行したいクエリ全体を選択した上で、Runボタンを押さないとエラーになる)

//検索対象のコンピュータ名
let ComputerName = “LAINDC01”;

InsightsMetrics
| where Name == “Heartbeat” and Origin == “vm.azm.ms/map”
| where Computer startswith ComputerName
// 最新世代を取るために、TimeGeneratedの最大値を取る行を抜き出している
| summarize arg_max(TimeGenerated, *)
// Tags列のJSONの中から、vm.azm.ms/processIds句を取り出して、Process列を生成している
| extend Process = parse_json(extractjson(“$.[‘vm.azm.ms/processIds’]”, Tags))

ここまでだと、Process列は横に配列として並んだままになってしまっている。

mvexpand演算子を使うと、この配列を縦に行として展開することが出来る。

あとは、VMProcessテーブルとProcess列をもとに結合するだけ。

ここまでくれば、CommandLine列を正規表現で検索すれば、プロセス監視もどきとかも実行できる。

最終的なクエリ式はこんな感じになる。

let ComputerName = “LAINDC01”;
let ProcessName = “.*svchost.exe -k netsvcs -p -s Schedule”;

InsightsMetrics
| where Name == “Heartbeat” and Origin == “vm.azm.ms/map”
| where Computer startswith ComputerName
| summarize arg_max(TimeGenerated, *)
| extend Process = parse_json(extractjson(“$.[‘vm.azm.ms/processIds’]”, Tags))
| mvexpand Process to typeof(string)
| join kind= leftouter (VMProcess | where Computer startswith ComputerName | summarize arg_max(TimeGenerated, *) by Process) on Process
| where CommandLine matches regex ProcessName

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です