Apache JMeter™のテスト結果をAzure Application Insights / Log Analyticsで分析する

Apache JMeter™のテスト結果をAzure Application Insightsに送り、それをKusto queryを利用して参照する方法を紹介します。

jmeter-backend-azureプラグイン(Microsoftの方が作ってるらしい)を利用すると、JMeterでのテスト結果を、Azure Application Insightsに送ることができます。
結果をApplication Insightsに送ることで、結果の管理や参照、分析が柔軟になります。
また、そのApplication Insightsがワークスペースベースであれば、Log Analyticsと統合され、そのメリットも享受できます。

jmeter-backend-azureプラグインの導入

  1. JMeter Plugins Managerを導入
    JMeterにJMeter Plugins Managerを未導入の場合、以下の手順で導入します。
    導入済みの場合はこれをスキップしjmeter-backend-azureプラグインをインストールに進んでください。
    1. JMeter Plugins Managerのダウンロード
      Webブラウザを利用して以下のページから最新のPlugins Managerをダウンロードします。
      https://jmeter-plugins.org/install/Install/
      コンソールで以下のようなコマンドを実行することでもダウンロードすることができます。

      $ wget -O jmeter-plugins-manager.jar https://jmeter-plugins.org/get/
      
    2. ダウンロードしたファイルをJMeterのプラグイン用ディレクトリに配置 先ほどダウンロードしたJMeter Plugins Managerのjarファイルを $JMETER_HOME/lib/ext にコピーします。

    3. JMeterを起動または再起動

  2. jmeter-backend-azureプラグインをインストール
    1. メニューの Options (オプション) > Plugins Manager から"JMeter Plugins Manager" を表示
    2. Available Pluginsタブで"Azure Backend listener"を選択し、[Apply Changes and Restart JMeter]をクリックしてJMeterを再起動

テストプランでの設定

  1. Application Insightsの接続文字列の取得
    JMeterが結果を送信するApplication Insightsの接続文字列を取得します。
    Azure Portalで該当Application Insightsの概要ブレードから接続文字列をメモします。
    この値は、後のJMeterでのBackend Listerの設定で利用します。
    connection string
  2. JMeterで適当なテストプランを作成します。
  3. Backend Listenerを設定 Backend Listenerをテストプランまたはログを送りたいスレッドグループに追加し、このプラグインの利用といくつかのパラメーターを設定します。
    Add (追加) > Listener (リスナー) > Backend Listener
    Backend Listener
    • Backend Listener implementation: “io.github.adrianmo.jmeter.backendlistener.azure.AzureBackendClient”
    • Parameters
      • testName: テスト名。この値はApplication Insightsログのname列に入ります。
        kustoでテスト結果を参照するときに、フィルタ条件として利用することもできます。
      • connectionString: Application Insightsの接続文字列
      • liveMetrics: Application InsightsのLive Metrics Streamを利用しない場合はfalseを設定します。
      • samplersList: Application Insightsに結果を送信するサンプラーを";“区切りで記入します。空の場合はすべてのサンプラーの結果を送ります。
      • useRegexForSamplerList: samplersListに正規表現を利用する場合はtrueにします。
      • logResponseData: ResponseDataプロパティにレスポンスデータを取得する場合はtrueにします。

テストの実施とApplication Insights / Log Analyticsでの結果の参照

Live Metrics Stream (Application Insights)

JMeterのBackend ListenerでliveMetricsをtrueとしてテストを実施した場合、Application InsightsのLive Metricsでリアルタイムに状況を見ることができます。
Live Metrics

ログ / Workbook

ログやWorkbook(ブック)ではKusto query (kql)を書くことで柔軟に結果を表示/分析することができます。

Application InsightsとLog Analyticsとで、テーブル名や列名が異なるので注意してください。
以下に本記事のサンプルで参照しているテーブルおよび列の対応表を示します。

- Application Insights Log Analytics
テーブル requests AppRequests
name Name
success Success
duration DurationMs
customDimensions Properties

以降のサンプルでは、Application Insightsを対象としています。
Log Analyticsを利用する場合は、上記の対応表に従い、テーブル名や列名を置き換えてください。

  • 表示/分析対象の絞り込み
    requests (Application Insights) / AppRequests (Log Analytics)テーブルにはApplication Insightsに送った全てのテスト結果や、JMeterではない他のログも含まれている可能性があります。
    1つのテストのみを対象とした結果を表示/分析したい場合は、nameとcustomDimensions.TestStartTimeで、絞り込むことができます。(テストの度にBackend ListenerのtestNameを変更すればnameのみで絞り込むこともできます。)

    以下のKustoでは、nameとTestStartTimeの一覧を取得します。

    requests
    | extend
        TestStartTime = tostring(customDimensions.TestStartTime)
    | distinct TestStartTime, name
    | extend
        formattedTestStartTime
            = format_datetime(
                unixtime_milliseconds_todatetime(tolong(TestStartTime)),
                'yyyy/MM/dd HH:mm:ss'
            )
    | sort by TestStartTime desc
    

    テスト一覧

  • Aggregate Report (統計レポート)
    JMeterのAggregate Reportリスナーと同様のデータを抽出してみます。

    let testName = "<先に取得したnameの値>";
    let TestStartTime = "<先に取得したTestStartTimeの値>";
    requests
    | where name == testName
        and customDimensions.TestStartTime == TestStartTime
    | summarize
        Samples = count(),
        Average = tolong(avg(duration)),
        (L50, L90, L95, L99)
            = percentiles(duration, 50, 90, 95, 99),
        Min = min(duration),
        Maximum = max(duration),
        ErrorCount = countif(success == false),
        ReceivedKB = sum(tolong(customDimensions.Bytes)),
        SentKB = sum(tolong(customDimensions.SentBytes)),
        StartTime = min(tolong(customDimensions.SampleStartTime)),
        EndTime = max(tolong(customDimensions.SampleEndTime))
        by Label = tostring(customDimensions.SampleLabel)
    | extend s = 0
    | union (
    requests
    | where name == testName
        and customDimensions.TestStartTime == TestStartTime
    | summarize
        Samples = count(),
        Average = tolong(avg(duration)),
        (L50, L90, L95, L99)
            = percentiles(duration, 50, 90, 95, 99),
        Min = min(duration),
        Maximum = max(duration),
        ErrorCount = countif(success == false),
        ReceivedKB = sum(tolong(customDimensions.Bytes)),
        SentKB = sum(tolong(customDimensions.SentBytes)),
        StartTime = min(tolong(customDimensions.SampleStartTime)),
        EndTime = max(tolong(customDimensions.SampleEndTime))
    | extend Label = 'TOTAL', s = 9
    )
    | extend
        tp = Samples / ((EndTime - StartTime) / 1000.0),
        KBPeriod = (EndTime - StartTime) * 1024 / 1000.0
    | sort by s asc
    | project
        Label, Samples, Average,
        Median = round(L50),
        ['90% Line'] = round(L90),
        ['95% Line'] = round(L95),
        ['99% Line'] = round(L99),
        Min, Maximum,
        ['Error %'] = strcat(round(ErrorCount * 100.0 / Samples, 2), '%'),
        ['Throughput'] = iif(tp < 1.0,
                            strcat(round(tp * 60, 1), '/min'),
                            strcat(round(tp, 1), '/sec')
                         ),
        ['Received KB/sec'] = round(ReceivedKB / KBPeriod, 2),
        ['Sent KB/sec'] = round(SentKB / KBPeriod, 2)
    | project-reorder
        Label, Samples, Average,
        ['Median'], ['90% Line'], ['95% Line'], ['99% Line'],
        Min, Maximum, ['Error %'], ['Throughput'],
        ['Received KB/sec'], ['Sent KB/sec']
    

    Aggregate Report \(Application Insights\)Aggregate Report \(JMeter\)

    Median, 90% Line, 95% Line, 99% Lineが、JMeterのAggregate Reportとは異なることがあるようです。
    これは、Kustoのpercentiles関数は推定により算出されているからのようです。
    ここではそれは誤差として受け止め、深堀りはしません。

以上、JMeterのテスト結果をAzure Application Insightsに送り、それをKusto queryを利用して参照する方法を紹介しました。
今後、他のリスナーと同様の結果を出力するKusto queryの紹介もしていきたいと思います。

【宣伝】
Azure JMeter™の分散テスト環境を簡単構築
「Load Tester Powered by Apache JMeter™」