Log Analytics ワークスペースでの使用量を分析する

Azure Monitorのコストは、Log Analyticsワークスペースで収集されるデータの量によって大きく異なる場合があります。 このボリュームは、ワークスペースを使用するソリューションのセットと、それぞれのソリューションによって収集されるデータの量によって影響を受けます。 この記事では、収集したデータを分析して、データインジェストコストの制御に役立つガイダンスを提供します。 これは、予想を超える使用量の原因の特定に役立ちます。 また、より多くのリソースを監視し、さまざまな Azure Monitor 機能を構成する際のコスト予測にも役立ちます。

ヒント

Azure Monitor のコストを削減するための戦略については、「コストの最適化と Azure Monitor」を参照してください。

予想を超える使用量の原因

各 Log Analytics ワークスペースは個々のサービスとして課金され、Azure サブスクリプションの課金内容に加えられます。 データ インジェストの量は、次に大きく依存する可能性があります。

  • 有効になっている一連の分析情報とサービスおよびその構成。
  • 監視対象のリソースの数と種類。
  • 各監視対象リソースから収集されたデータの量。

これらの要因のいずれかが予期せず増加すると、データ保持に対する料金が増加する可能性があります。 この記事の残りの部分では、このような状況を検出し、収集したデータを分析して、増加した使用量のソースを特定して軽減する方法について説明します。

収集したデータの量が多い場合にアラートを送信する

予期しない請求を避けるため、過剰な使用量が発生した場合は、事前に通知される必要があります。 通知により、請求期間が終了する前に、潜在的な異変に対処できます。

次の例は、過去 24 時間に取り込まれた課金対象データ量が 50 GB を超えた場合にアラートを送信するログ検索アラート ルールです。 アラート ロジック設定を変更し、実際の環境内で予想される使用量に基づいて別のしきい値を使用してください。 また、使用量を毎日複数回チェックするように頻度を上げることもできますが、この場合はアラート ルールの料金が高くなります。

設定
スコープ
ターゲット スコープ Log Analytics ワークスペースを選択します。
Condition
クエリ Usage | where IsBillable | summarize DataGB = sum(Quantity / 1000)
Measurement 測定: DataGB
集計の種類: 合計
集計単位: 1 日
アラート ロジック 演算子:より大きい
しきい値: 50
評価の頻度: 1 日
アクション しきい値を超えたときに通知するアクション グループを選択または追加します。
詳細
重大度 警告
アラート ルール名 24 時間でデータ量が 50 GB を超える課金対象データ。

Azure Monitorでの使用状況分析

Azure Monitor の既存のツールを使用して分析を開始します。 これらのツールは構成を必要とせず、多くの場合、最小限の労力で必要な情報を提供できます。 収集したデータを既存の Azure Monitor 機能よりも詳細に分析する必要がある場合は、Log Analytics で次のいずれかのログ クエリを使用します。

Log Analytics Workspace Insights

Log Analytics Workspace Insights を使用すると、ワークスペース内のデータをすばやく解釈できます。 たとえば、次のことが分かります。

  • メイン テーブルで最も多くのデータ ボリュームを取り込んでいるデータ テーブル。
  • データに寄与している上位のリソース。
  • データ インジェストの傾向。

ソリューションとテーブルごとのインジェストの内訳については、[使用状況]タブを参照してください。 この情報によって、データ ボリュームの大部分に寄与するテーブルをすばやく特定できます。 タブには、時間の経過に伴うデータ収集の傾向も表示されます。 データ収集が時間の経過とともに徐々に増加したか、構成の変更に応じて突然増加したかを判断できます。

データ パターンをさらに解釈するのに役立つ事前構築済みクエリの追加クエリを選択します。

使用量と推定コスト

各ワークスペースの [使用量と推定コスト] ページの [ソリューションごとのデータの取り込み] グラフには、この 31 日間で送信されたデータの総量とソリューションごとの送信量が表示されます。 この情報により、データの全体的な使用状況や特定のソリューションによる使用状況の増加などの傾向を判断できます。

使用状況テーブルからのデータ ボリュームに対してクエリを実行する

特定のサービスまたはソリューションによって収集された課金対象データの量を分析します。 これらのクエリでは、ワークスペース内の各テーブルの使用状況データを収集するUsageテーブルが使用されます。

Note

TimeGenerated を含む句は、Azure portal のクエリ機能が既定の 24 時間を超えてさかのぼって参照するようにするためだけのものです。 Usage データ型を使用する場合、StartTimeEndTime は、結果が表示される時間バケットを表します。

過去1か月間の型別の課金対象データ量

Usage 
| where TimeGenerated > ago(32d)
| where StartTime >= startofday(ago(31d)) and EndTime < startofday(now())
| where IsBillable == true
| summarize BillableDataGB = sum(Quantity) / 1000. by bin(StartTime, 1d), DataType 
| render columnchart

過去1か月間のソリューションと型別の課金対象データ量

Usage 
| where TimeGenerated > ago(32d)
| where StartTime >= startofday(ago(31d)) and EndTime < startofday(now())
| where IsBillable == true
| summarize BillableDataGB = sum(Quantity) / 1000 by Solution, DataType
| sort by Solution asc, DataType asc

イベントからのデータ ボリュームに対して直接クエリを実行する

収集したデータをより詳細に分析する必要がある場合は、Log Analyticsログクエリを使用できます。 Log Analytics ワークスペースの各テーブルには、課金対象データの分析に役立つ次の標準列があります。

  • _IsBillable は、インジェスト料金が発生するレコードを識別します。 課金対象でないデータを除外するには、この列を使用します。
  • _BilledSizeは、レコードのサイズをバイト単位で提供します。

特定のイベントの課金対象データ量

特定のデータ型が過剰なデータを収集している場合は、そのテーブル内のデータを分析して、増加している特定のレコードを識別できます。 次の使用例は、Event テーブル内の特定のイベント ID をフィルター処理し、各 ID にカウントを提供します。 このクエリは、他のテーブルの列を使用して変更できます。

Event
| where TimeGenerated > startofday(ago(31d)) and TimeGenerated < startofday(now()) 
| where EventID == 5145 or EventID == 5156
| where _IsBillable == true
| summarize count(), Bytes=sum(_BilledSize) by EventID, bin(TimeGenerated, 1d)

Azure リソース、リソース グループ、またはサブスクリプションごとのデータ ボリューム

特定のリソースまたはリソースのセットから収集された課金対象データの量を分析できます。 これらのクエリ では、Azureでホストされているリソースからのデータに対して_ResourceId列と_SubscriptionId列が使用されます。

警告

複数の種類のデータにわたるスキャンは、実行に多量のリソースを使うため検索クエリは多用しないようにします。 サブスクリプション、リソース グループ、またはリソース名ごとの結果が不要な場合は、上記のクエリのように Usage テーブルを使用します。

過去 1 日のリソース ID 別の課金対象データ量

find where TimeGenerated between(startofday(ago(1d))..startofday(now())) project _ResourceId, _BilledSize, _IsBillable
| where _IsBillable == true 
| summarize BillableDataBytes = sum(_BilledSize) by _ResourceId 
| sort by BillableDataBytes nulls last

過去 1 日のリソース グループ別の課金対象データ量

find where TimeGenerated between(startofday(ago(1d))..startofday(now())) project _ResourceId, _BilledSize, _IsBillable
| where _IsBillable == true 
| summarize BillableDataBytes = sum(_BilledSize) by _ResourceId
| extend resourceGroup = tostring(split(_ResourceId, "/")[4] )
| summarize BillableDataBytes = sum(BillableDataBytes) by resourceGroup 
| sort by BillableDataBytes nulls last

_ResourceId を解析すると役立つ場合があります。

| parse tolower(_ResourceId) with "/subscriptions/" subscriptionId "/resourcegroups/" 
    resourceGroup "/providers/" provider "/" resourceType "/" resourceName   

過去 1 日のサブスクリプション別の課金対象データ量

find where TimeGenerated between(startofday(ago(1d))..startofday(now())) project _BilledSize, _IsBillable, _SubscriptionId
| where _IsBillable == true 
| summarize BillableDataBytes = sum(_BilledSize) by _SubscriptionId 
| sort by BillableDataBytes nulls last

ヒント

データ量が多いワークスペースの場合、このセクションに示すような大量の生データを対象とするクエリの実行は、1 日に制限する必要がある場合があります。 経時的な傾向を追跡するには、Power BI レポートを設定し、増分更新を使用してリソースごとに 1 日 1 回データ ボリュームを収集することを検討してください。

コンピューターごとのデータ ボリューム

仮想マシンまたは一連の仮想マシンから収集される課金対象データ量を分析できます。 Usage テーブルには特定の仮想マシンについてのデータ ボリュームを示す細分性がないため、これらのクエリでは検索演算子を使用して、コンピューター名を含むすべてのテーブルを検索します。 このクエリは、データの傾向分析にのみ使用されるため、Usage 型は、省略されています。

警告

複数の種類のデータにわたるスキャンは、実行に多量のリソースを使うため検索クエリは多用しないようにします。 サブスクリプション、リソース グループ、またはリソース名ごとの結果が不要な場合は、上記のクエリのように Usage テーブルを使用します。

過去 1 日のコンピューター別の課金対象データ量

find where TimeGenerated between(startofday(ago(1d))..startofday(now())) project _BilledSize, _IsBillable, Computer, Type
| where _IsBillable == true and Type != "Usage"
| extend computerName = tolower(tostring(split(Computer, '.')[0]))
| summarize BillableDataBytes = sum(_BilledSize) by  computerName 
| sort by BillableDataBytes desc nulls last

過去 1 日のコンピューター別の課金対象イベントの数

find where TimeGenerated between(startofday(ago(1d))..startofday(now())) project _IsBillable, Computer, Type
| where _IsBillable == true and Type != "Usage"
| extend computerName = tolower(tostring(split(Computer, '.')[0]))
| summarize eventCount = count() by computerName  
| sort by eventCount desc nulls last

既知の無料のデータ型を除くデータ ボリュームのクエリ

次のクエリでは、データ インジェスト料金が発生しないように想定されているすべてのデータ型を除く、月単位のデータ 量を GB 単位で返します。

let freeTables = dynamic([
"AppAvailabilityResults","AppSystemEvents","ApplicationInsights","AzureActivity","AzureNetworkAnalyticsIPDetails_CL",
"AzureNetworkAnalytics_CL","AzureTrafficAnalyticsInsights_CL","ComputerGroup","DefenderIoTRawEvent","Heartbeat",
"MAApplication","MAApplicationHealth","MAApplicationHealthIssues","MAApplicationInstance","MAApplicationInstanceReadiness",
"MAApplicationReadiness","MADeploymentPlan","MADevice","MADeviceNotEnrolled","MADeviceReadiness","MADriverInstanceReadiness",
"MADriverReadiness","MAProposedPilotDevices","MAWindowsBuildInfo","MAWindowsCurrencyAssessment",
"MAWindowsCurrencyAssessmentDailyCounts","MAWindowsDeploymentStatus","NTAIPDetails_CL","NTANetAnalytics_CL",
"OfficeActivity","Operation","SecurityAlert","SecurityIncident","UCClient","UCClientReadinessStatus",
"UCClientUpdateStatus","UCDOAggregatedStatus","UCDOStatus","UCDeviceAlert","UCServiceUpdateStatus","UCUpdateAlert",
"Usage","WUDOAggregatedStatus","WUDOStatus","WaaSDeploymentStatus","WaaSInsiderStatus","WaaSUpdateStatus"]);
Usage 
| where DataType !in (freeTables) 
| where TimeGenerated > ago(30d) 
| summarize MonthlyGB=sum(Quantity)/1000

IsBillable が正しく設定されていない可能性がある (誤った課金や、具体的には課金不足になる可能性がある) データを探すには、ワークスペースで次のクエリを使用します。

let freeTables = dynamic([
"AppAvailabilityResults","AppSystemEvents","ApplicationInsights","AzureActivity","AzureNetworkAnalyticsIPDetails_CL",
"AzureNetworkAnalytics_CL","AzureTrafficAnalyticsInsights_CL","ComputerGroup","DefenderIoTRawEvent","Heartbeat",
"MAApplication","MAApplicationHealth","MAApplicationHealthIssues","MAApplicationInstance","MAApplicationInstanceReadiness",
"MAApplicationReadiness","MADeploymentPlan","MADevice","MADeviceNotEnrolled","MADeviceReadiness","MADriverInstanceReadiness",
"MADriverReadiness","MAProposedPilotDevices","MAWindowsBuildInfo","MAWindowsCurrencyAssessment",
"MAWindowsCurrencyAssessmentDailyCounts","MAWindowsDeploymentStatus","NTAIPDetails_CL","NTANetAnalytics_CL",
"OfficeActivity","Operation","SecurityAlert","SecurityIncident","UCClient","UCClientReadinessStatus",
"UCClientUpdateStatus","UCDOAggregatedStatus","UCDOStatus","UCDeviceAlert","UCServiceUpdateStatus","UCUpdateAlert",
"Usage","WUDOAggregatedStatus","WUDOStatus","WaaSDeploymentStatus","WaaSInsiderStatus","WaaSUpdateStatus"]);
Usage 
| where DataType !in (freeTables) 
| where TimeGenerated > ago(30d) 
| where IsBillable == false 
| summarize MonthlyPotentialUnderbilledGB=sum(Quantity)/1000 by DataType

一般的なデータ型のクエリを実行する

特定のデータ型に対して過剰な課金対象データがあることが判明した場合は、そのテーブル内のデータ分析をするため、クエリの実行が必要かもしれません。 次のクエリでは、一般的なデータ型のサンプルを提供します。

Security ソリューション

SecurityEvent 
| summarize AggregatedValue = count() by EventID
| order by AggregatedValue desc nulls last

Log Management ソリューション

Usage 
| where Solution == "LogManagement" and iff(isnotnull(toint(IsBillable)), IsBillable == true, IsBillable == "true") == true 
| summarize AggregatedValue = count() by DataType
| order by AggregatedValue desc nulls last

Perf データの種類

Perf 
| summarize AggregatedValue = count() by CounterPath
Perf 
| summarize AggregatedValue = count() by CounterName

Event データの種類

Event 
| summarize AggregatedValue = count() by EventID
Event 
| summarize AggregatedValue = count() by EventLog, EventLevelName

Syslog データの種類

Syslog 
| summarize AggregatedValue = count() by Facility, SeverityLevel
Syslog 
| summarize AggregatedValue = count() by ProcessName

AzureDiagnostics データ型

AzureDiagnostics 
| summarize AggregatedValue = count() by ResourceProvider, ResourceId

Application Insights データ

クラシックアプリケーションとワークスペースベースのアプリケーションのどちらを使用しているかに応じて、Application Insightsで収集されるデータの量を調査する方法は2種類あります。 ワークスペースベースのリソースとクラシック リソースの両方に対して取り込まれた各イベントで使用できる _BilledSize プロパティを使用します。 クラシックリソースのsystemEventsテーブルで集計された情報を使用することもできます。

Note

SystemEvents を除く Application Insights テーブルに対するクエリは、ワークスペースベースの Application Insights リソースと従来の Application Insights リソースの両方で機能します。 後方互換対応により、従来のテーブル名を引き続き使用できます。 ワークスペースベースのリソースの場合は、[Log Analytics ワークスペース] メニューから [ログ] を開きます。 クラシック リソースの場合は、[Application Insights] メニューから [ログ] を開きます。

依存関係操作では、過去 30 日間で最も多くのデータ ボリュームが生成されます (ワークスペースベースまたはクラシック)

dependencies
| where timestamp >= startofday(ago(30d))
| summarize sum(_BilledSize) by operation_Name
| render barchart  

この Application Insights リソースの過去 7 日間の種類別の日次データ量 (クラシックのみ)

systemEvents
| where timestamp >= startofday(ago(7d)) and timestamp < startofday(now())
| where type == "Billing"
| extend BillingTelemetryType = tostring(dimensions["BillingTelemetryType"])
| extend BillingTelemetrySizeInBytes = todouble(measurements["BillingTelemetrySize"])
| summarize sum(BillingTelemetrySizeInBytes) by BillingTelemetryType, bin(timestamp, 1d)  

ワークスペースベースの Application Insights リソースのデータ ボリュームの傾向を確認するには、すべての Application Insights テーブルを含むクエリを使用します。 次のクエリでは、ワークスペースベースのリソースに固有のテーブル名を使用します。

ワークスペース内のすべての Application Insights リソースの過去 7 日間の種類別の日次データ量

union AppAvailabilityResults,
      AppBrowserTimings,
      AppDependencies,
      AppExceptions,
      AppEvents,
      AppMetrics,
      AppPageViews,
      AppPerformanceCounters,
      AppRequests,
      AppSystemEvents,
      AppTraces
| where TimeGenerated >= startofday(ago(7d)) and TimeGenerated < startofday(now())
| summarize sum(_BilledSize) by _ResourceId, bin(TimeGenerated, 1d)

1 つの Application Insights リソースのみのデータ量の傾向を確認するには、上記のクエリの summarize の前に次の行を追加します。

| where _ResourceId contains "<myAppInsightsResourceName>"

ヒント

データ量が多いワークスペースの場合、上記のような大量の生データに対するクエリの実行は、1 日に制限する必要がある場合があります。 経時的な傾向を追跡するには、Power BI レポートを設定し、増分更新を使用してリソースごとに 1 日 1 回データ ボリュームを収集することを検討してください。

データを送信するノードについて理解する

特定のソースからの過剰なデータがない場合は、データを送信しているエージェントの数が多すぎる可能性があります。

過去1か月間に毎日ハートビートを送信しているエージェントノードの数

Heartbeat 
| where TimeGenerated > startofday(ago(31d))
| summarize nodes = dcount(Computer) by bin(TimeGenerated, 1d)    
| render timechart

警告

複数の種類のデータにわたるスキャンは、実行に多量のリソースを使うため検索クエリは多用しないようにします。 サブスクリプション、リソース グループ、またはリソース名ごとの結果が不要な場合は、上記のクエリのように Usage テーブルを使用します。

過去24時間以内にデータを送信しているノードの数

find where TimeGenerated > ago(24h) project Computer
| extend computerName = tolower(tostring(split(Computer, '.')[0]))
| where computerName != ""
| summarize nodes = dcount(computerName)

過去24時間以内に各ノードによって送信されたデータボリューム

find where TimeGenerated > ago(24h) project _BilledSize, Computer
| extend computerName = tolower(tostring(split(Computer, '.')[0]))
| where computerName != ""
| summarize TotalVolumeBytes=sum(_BilledSize) by computerName

レガシのノードごとの価格レベルによって課金されるノード

従来のノードごとの価格レベルでは、ノードに対して時間単位の粒度で課金されます。 また、一連のセキュリティ データ タイプのみを送信しているノードもカウントされません。 ワークスペースが従来のノードごとの価格レベルである場合、ノードとして課金対象になるコンピューターの一覧を取得するには、一部のデータの種類が無料であるため、課金対象のデータの種類を送信しているノードを探します。 この場合、プロパティを使用し、完全修飾ドメイン名の左端のフィールドを使用します。

次のクエリは、1時間あたりの課金データを含むコンピューターの数を返します。 請求書の単位数は、クエリで billableNodeMonthsPerDay によって表されるノード月の単位になります。 ワークスペースにUpdate Managementソリューションがインストールされている場合は、where句の一覧にUpdateおよびUpdateSummaryデータの種類を追加します。

find where TimeGenerated >= startofday(ago(7d)) and TimeGenerated < startofday(now()) project Computer, _IsBillable, Type, TimeGenerated
| where Type !in ("SecurityAlert", "SecurityBaseline", "SecurityBaselineSummary", "SecurityDetection", "SecurityEvent", "WindowsFirewall", "MaliciousIPCommunication", "LinuxAuditLog", "SysmonEvent", "ProtectionStatus", "WindowsEvent")
| extend computerName = tolower(tostring(split(Computer, '.')[0]))
| where computerName != ""
| where _IsBillable == true
| summarize billableNodesPerHour=dcount(computerName) by bin(TimeGenerated, 1h)
| summarize billableNodesPerDay = sum(billableNodesPerHour)/24., billableNodeMonthsPerDay = sum(billableNodesPerHour)/24./31.  by day=bin(TimeGenerated, 1d)
| sort by day asc

Note

ソリューションのターゲット設定を使用した場合の実際の課金アルゴリズムの複雑さは、上記のクエリでは表されていません。

セキュリティ ノード数と Automation ノード数

個別のセキュリティノードの数

union
(
    Heartbeat
    | where (Solutions has 'security' or Solutions has 'antimalware' or Solutions has 'securitycenter')
    | project Computer
),
(
    ProtectionStatus
    | where Computer !in (Heartbeat | project Computer)
    | project Computer
)
| distinct Computer
| project lowComputer = tolower(Computer)
| distinct lowComputer
| count

個別の Automation ノードの数

 ConfigurationData 
 | where (ConfigDataType == "WindowsServices" or ConfigDataType == "Software" or ConfigDataType =="Daemons") 
 | extend lowComputer = tolower(Computer) | summarize by lowComputer 
 | join (
     Heartbeat 
       | where SCAgentChannel == "Direct"
       | extend lowComputer = tolower(Computer) | summarize by lowComputer, ComputerEnvironment
 ) on lowComputer
 | summarize count() by ComputerEnvironment | sort by ComputerEnvironment asc

到着遅延データ

Usage レコードを使用して多数のデータ インジェストが報告されているが、データ型で直接 _BilledSize を合計したときに同じ結果が確認できない場合は、到着が遅延しているデータがある可能性があります。 この状況は、データが古いタイムスタンプで取り込まれる場合に発生します。

たとえば、エージェントに接続の問題があり、再接続後に蓄積されたデータが送信される場合があります。 または、ホストの時刻が正しくない可能性があります。 どちらの例でも、Usage データ型によって報告される取り込まれたデータと、イベントが生成されたタイムスタンプである TimeGenerated によって指定された特定の日の生データの _BilledSize を合計するクエリとの間の明らかな不一致が起こる可能性があります。

到着遅延データの問題を診断するには、_TimeReceived 列と TimeGenerated 列を使用します。 _TimeReceived プロパティは、そのレコードが Azure クラウド内の Azure Monitor インジェスト ポイントによって受信された時刻です。

次の例は、2021 年 5 月 2 日に大量のデータが取り込まれた W3CIISLog データに対応して、この取り込まれたデータのタイムスタンプを識別するものです。 where TimeGenerated > datetime(1970-01-01)ステートメントは、すべてのデータを調べる手掛かりをLog Analyticsユーザーインターフェイスに提供する目的で含まれます。

W3CIISLog
| where TimeGenerated > datetime(1970-01-01)
| where _TimeReceived >= datetime(2021-05-02) and _TimeReceived < datetime(2021-05-03) 
| where _IsBillable == true
| summarize BillableDataMB = sum(_BilledSize)/1.E6 by bin(TimeGenerated, 1d)
| sort by TimeGenerated asc 

次のステップ