ごった煮

色々な事を書いてます

Azure Monitor と Log Analytics を組み合わせてアプリケーションを監視する

この記事は、Azure アドベントカレンダー 2019 の8日目の投稿です。

Azure には、アプリケーションの監視用に Application Insights(以下 AI ) があります。 AI は、ログの分析を行う Log Analytics と組み合わせることによって柔軟にログを扱うことが出来ます。

今回は、AI で収集したログを Log Analytics で集約し、Azure Monitor を使って Azure Functions にエラーメッセージを送る方法についてまとめます。

※今回は、AI とアプリケーションの繋ぎ込みなどは、扱わないのでそういった情報は、以下のようなところから調べてみましょう。

docs.microsoft.com

docs.microsoft.com

Log Analytics でログを分析する

Log Analytics でログ分析を行う場合は、基本的に SQL ライクな KQL という言語を使用してクエリを書きます。

Log Analytics のクエリエディタは、Azure ポータルの AI の画面から飛ぶことが出来ます。 AI の画面上部にある Log(Analytics) を選択します。 f:id:papemk2:20191206225727p:plain

クエリエディタは、以下のような画面になります。 赤枠の中にクエリを書いていきます。 f:id:papemk2:20191206231018p:plain

クエリを書いたら Run ボタンを押します。

ログは、以下の項目が検索できます。

  • traces
  • customEvents
  • pageViews
  • requests
  • dependencies
  • exceptions
  • availabilityResults
  • customMetrics
  • performanceCounters
  • browserTimings

自分が良く使う項目は、requests、dependencies、exceptions です。 requests は、アプリケーションに送られてくるリクエスト内容 dependencies は、DB、Web API などアプリケーション外にある依存関係 exceptions は、アプリケーション内で発生した例外が含まれます。

一番簡単なクエリは、以下です。

requests

これを実行すると、ログが表組されて表示されます。 f:id:papemk2:20191206231143p:plain

条件分は、SQL のように書きます。

requests
| where resultCode == 404 or resultCode == 500

カラムの絞り込みは、以下のような感じ

requests
| where resultCode == 404 or resultCode == 500
| project resultCode , url , name 

f:id:papemk2:20191206231805p:plain

サマリーしたいときは、以下のような感じ

requests
| where resultCode == 404 or resultCode == 500
| project resultCode , url , name 
| summarize count(resultCode) by resultCode, url, name

f:id:papemk2:20191206232436p:plain

Log Analytics と Azure Monitor を組み合わせる

先ほど書いたクエリ結果をAzure Monitor と組み合わせてみます。 これは、Azure Monitor の画面から行います。 Azure Monitor のモニタルールは、ポータルの Azure Monitor > Alerts > New alert rule から進みます。 進むと以下のような画面になります。 f:id:papemk2:20191206233303p:plain

Resource で監視対象の AI を指定します。 赤枠の中に Application Insights と入れると絞り込みがされます。

f:id:papemk2:20191206233749p:plain

Condition は、リソースの状態を指定する項目です。 ここで Log Analytics のクエリを指定します。

Custom log search を指定します。

f:id:papemk2:20191206233936p:plain

赤枠のSearch query にクエリを貼り付けます。 今回は、エラーが発生したら通知を行いたいので、閾値(Threshold value)は、0にします。(0を指定すると0回以上になるので、イベントが発生したら全て拾うことになります。) 時間の範囲は、デフォルト(5分)に設定します。 f:id:papemk2:20191206234115p:plain

Actions は、アラートの発行先を指定する項目です。 今回は、Function App を指定します。 Create action group を選択します。 選択後、Action Type に Azure Functions を指定します。 次に出てくるウィンドウで、リソースグループを選択するとHttp Trigger が含まれている Function App が表示されるのでアラートを送りたい Function App を指定します。 f:id:papemk2:20191206234626p:plain

最後に Alert Details で、Alert rule name を指定します。 これで、アラートが発生すると Function App のエンドポイントが呼び出されます。

Azure Functions でメッセージを受け取る

Function App が受け取るペイロードは、以下のような形式です。

{
    "schemaId": "Microsoft.Insights/LogAlert",
    "data": {
        "SubscriptionId": "Your own subscription id",
        "AlertRuleName": "Qiita-Monitoring-2019",
        "SearchQuery": "requests\n| where resultCode == 404 or resultCode == 500\n| project resultCode , url , name \n| summarize count(resultCode) by resultCode, url, name",
        "SearchIntervalStartTimeUtc": "2019-12-06T15:03:56",
        "SearchIntervalEndtimeUtc": "2019-12-06T15:08:56",
        "AlertThresholdOperator": "Greater Than",
        "AlertThresholdValue": 0,
        "ResultCount": 2,
        "SearchIntervalInSeconds": 300,
        "LinkToSearchResults": "https://portal.azure.com#@ef5d34b2-4e7d-468e-b184-b17e34c6be36/blade/Microsoft_OperationsManagementSuite_Workspace/AnalyticsBlade/initiator/AnalyticsShareLinkToQuery/isQueryEditorVisible/true/scope/%7B%22resources%22%3A%5B%7B%22resourceId%22%3A%22%2Fsubscriptions%2F30bc1c24-7c50-471e-97c4-b86a3d9cedb1%2FresourceGroups%2FQiita%2Fproviders%2Fmicrosoft.insights%2Fcomponents%2FQiita-Monitoring-2019%22%7D%5D%7D/query/requests%0A%7C%20where%20resultCode%20%3D%3D%20404%20or%20resultCode%20%3D%3D%20500%0A%7C%20project%20resultCode%20%2C%20url%20%2C%20name%20%0A%7C%20summarize%20count%28resultCode%29%20by%20resultCode%2C%20url%2C%20name/isQuerybase64Compressed/false/timespanInIsoFormat/2019-12-06T15%3a03%3a56.0000000Z%2f2019-12-06T15%3a08%3a56.0000000Z",
        "Description": "",
        "Severity": "3",
        "SearchResult": {
            "tables": [
                {
                    "name": "PrimaryResult",
                    "columns": [
                        {
                            "name": "resultCode",
                            "type": "string"
                        },
                        {
                            "name": "url",
                            "type": "string"
                        },
                        {
                            "name": "name",
                            "type": "string"
                        },
                        {
                            "name": "count_resultCode",
                            "type": "long"
                        }
                    ],
                    "rows": [
                        [
                            "500",
                            "https://localhost:44355/home/error500",
                            "GET /home/error500",
                            8
                        ],
                        [
                            "404",
                            "https://localhost:44355/error",
                            "GET /error",
                            15
                        ]
                    ]
                }
            ],
            "dataSources": [
                {
                    "resourceId": "/subscriptions/30bc1c24-7c50-471e-97c4-b86a3d9cedb1/resourcegroups/qiita/providers/microsoft.insights/components/qiita-monitoring-2019",
                    "tables": [
                        "requests"
                    ]
                }
            ]
        },
        "ApplicationId": "dcd854c3-e6a8-4f05-b58c-8272660d3427",
        "AlertType": "Number of results"
    }
}

columns が、テーブルのカラム名、rows が結果にリンクします

LinkToSearchResults の URL は、Log Analytics の クエリエディタに繋がります。

このペイロードを Slack に送るなどするとアプリのモニタリングがしやすいかと思います。

ペイロードを受け取る場合のC#の例を示します。

#r "Newtonsoft.Json"

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;

public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    
    log.LogInformation(requestBody);

    return (ActionResult)new OkObjectResult(requestBody);
}

Request Body に json が入ってくるので、それを加工して次の処理の送るといった感じで使用します。 Logic App に送るといったことも可能ですが、例えば Slack 通知などは、デフォルトの Slack コネクタだとリッチなメッセージが送れないので Function App が向いているかなという気がします。

まとめ

これらの学習には、Microsoft Learn がおすすめです。

docs.microsoft.com

アプリケーションの監視は、サービス運用の要なので、この機会に是非試してみましょう。