KQL を初めて使う方が KQL の書き方を身に着けるための演習用の問題集と回答、解説です。
実際の KQL を使う場面で頻繁に出現するコマンド(演算子、関数)を様々な角度からいろいろな使い方で実行することで、手でコマンドを覚えてもらうような利用方法を想定しています。
KQL では他のプログラム言語と同じように、各言語要素に対して名前がつけられています。この名前を覚えることは必須ではありませんが、学習効率を高めるためには意識しておいたほうが良い要素です。単に全てを「コマンド」とひとくくりにするのではなく、現在自分はどの要素が使っているのかを意識しながら KQL を書くと仕組みへの理解が速やかに深まります。
Log Analytics DEMO workspace
サンプル データが用意されているデモ ワークスペースです。このページの KQL はこのデータに対して実行することを想定しています。
Kusto Query Language
Azure Data Explorer の KQL のリファレンスです。Log Analytics ではこのなかの一部が実装されています。
Azure Monitor のログを検索するためにはワークスペースにどのようなテーブルがあり、各テーブルはどのような構造のレコードを格納しているかを知る必要があります。ここでは基本的なオペレーターを使用して、目的の情報を含んだテーブルを見つけたり、よく使われる テーブルを題材に、探し出したテーブルに含まれるデータの構造を調べる方法を学習します。
search "contoso"
解説 :
search オペレーターはテーブルを指定しない場合、ワークスペース上の全てのテーブルに対して検索を行います。
一般的な KQL ではテーブルを指定してデータを取得しますが、目的のデータがどのテーブルに含まれているかわからない場合や、そもそもデータがワークスペースに存在するかどうかわからない場合などはsearch オペレーターを使用することができます。
大量のデータを検索する場合パフォーマンス上不利になるため、定期的に実行されるクエリなどでの多用は避けてください。
また、Kusto の実行環境によっては使えません。例えば Log Analytics では使うことができますが、Azure Resource Graph では使うことができません。
// Prefered
search "contoso" and "retail"
// NOT Prefered
// search "contoso" | search "retail"
// search "contoso" | where Name contains "retail"
解説 :
search オペレーターは多くの結果を生成する可能性があり、パフォーマンスに影響を与えます。複数の条件を指定する必要がある場合には、1つの search オペレーターの条件に含めるようにしてください。複数の search オペレーターをパイプしたり、search オペレーターの結果を where でフィルタするような処理は、中間処理のために前の search オペレーターによって大きな結果セットが生成されます。これに対して複数の条件を指定した1つの search オペレーターはそれよりも小さな結果セットを生成します。
search kind=case_sensitive "Contoso"
解説 :
search オペレーターは既定で大文字小文字を区別せずに検索を行いますが、kind 引数で明示的に動作を指定することができます。case_sensitive は大文字小文字を区別する指定です。
search in (Perf) "contosohotels"
// able to search piped Table
Perf
| search "contosohotels"
解説 :
search オペレーターはテーブルを指定して検索を行うことができます。in 引数の値で検索対象とするテーブルを指定します。search オペレーターはパイプから受け取ったテーブルに対して検索を行うこともできます。
search in (SecurityEvent) "contosohotels"
// able to search piped Table
SecurityEvent
| search "contosohotels"
解説 :
この例は1つ前とほとんど同じです。同じ文字列を持つレコードが複数のテーブルに存在する可能性があることを理解するために用意しています。
search in (Alert,SecurityAlert) "contosohotels"
// Other expression
// Need to combine multiple tables
Alert
| union SecurityAlert
| search "contosohotels"
解説 :
“in” 引数では複数のテーブルを指定することができます。この例では関連しそうな情報をもつテーブルをまたいで検索を行います。追加の例は KQL では複数のテーブルをパイプラインから渡すことができないため、予め複数のテーブルを “union” で接続しています。
search *
| distinct $table
解説 :
KQL では通常テーブルを指定して検索を行うため、ワークスペースにどのようなテーブルがあるかを知る必要があります。 search オペレーターの検索結果には所属するテーブルを表す $table カラムが含まれるため、distinct オペレーターで一意の値を抽出することで、ワークスペースに含まれている全てのテーブルを一覧することができます。
存在するテーブルは UI から確認するのは非常に時間がかかるため、簡単にテーブル名だけを確認する方法としてこの例を挙げています。
AzureDiagnostics
| take 10
// limit and take is same
//AzureDiagnostics
//| limit 10
解説 :
take オペレーターは素早くレコードの中身を確認したいときに使います。take は引数の数を上限としてレコードを取り出します。AzureDiagnostics は Azure 診断ログを保存していて非常に多くのレコードを含んでいるます。単純に AzureDiagnostics のテーブルを表示した場合、非常に長い実行時間が必要ですが take で結果を少数のレコードに絞ることですぐに結果を確認することができます。limit オペレーターも take と同じ動作をします。
take は毎回同じ結果が返るわけではありません。たとえば時刻順に最新のデータが取得されるわけではなく、データセットが変わらない場合でも前回実行時と結果が異なる場合があります。
AzureDiagnostics
|distinct Category
解説 :
AzureDiagnostics テーブルに含まれる診断ログには複数のリソースからのログから成り立っています。一般的に数十種類のリソースのログが集約されているため、どのようなリソースのログが含まれているかを把握することが重要です。
Category 列にはログを生成したリソースやログの種類のヒントが含まれているため、distinct オペレーターで Category の値を一覧にすることで、目的のログの有無を判断することが容易になります。
AzureDiagnostics
|distinct ResourceType,Category
解説 :
AzureDiagnostics の ResourceType にはログを生成したリソースの型が含まれるため、Category と組み合わせて distinct することで、どのリソースがどのカテゴリのログを生成しているか、わかりやすく表示することができます。
AzureDiagnostics
|where Category == "ApplicationGatewayAccessLog"
解説 :
where オペレーターは与えられた条件によってレコードを選択するフィルタです。AzureDiagnostics テーブルのログは種類ごとに異なる Category 列の値を持つため、Category 列の値でフィルタすることで、目的のリソースや目的の種類のログだけを選ぶことができます。
AzureDiagnostics
|where Category == "ApplicationGatewayAccessLog"
|sort by TimeGenerated desc
解説 :
フィルタされたログはクエリの実行者が期待する順序で並んでいるとは限りません。特に時系列に従って並べられていることを期待されることが多いですが、そうでない場合が多くあります。
sort オペレーターは指定した列の値によってレコードをソートします。既定では降順でソートを行います。この例では desc 引数を指定して明示的に降順に並び変えていますが、省略することもできます。
AzureDiagnostics
|where Category == "ApplicationGatewayAccessLog"
|sort by TimeGenerated asc
解説 :
sort オペレーターで昇順にソートする場合には asc 引数を指定します。
AzureDiagnostics
|where Category == "ApplicationGatewayAccessLog"
|top 10 by TimeGenerated desc
解説 :
ソートされた結果からいくつかのレコードを取り出したい場合には top オペレーターを使用します。top は by 引数に指定された列の値でレコードをソートします。sort と同じく既定では降順にソートを行い、この例では明示的に desc を指定しています。
AzureDiagnostics
|where Category == "ApplicationGatewayAccessLog"
|top 10 by TimeGenerated asc
解説 :
top オペレーターも sort と同様に asc 引数で昇順のソートを行うことができます。
AzureMetrics
| take 10
解説 :
AzureMetrics テーブルは Azure リソースのメトリックを保持するテーブルです。リソースの診断設定でメトリックを有効にした場合、このテーブルに情報が保存されます。
Metric は Windows でいうところのパフォーマンス カウンターのようなもので、リソースの数値的な側面を計測するために利用します。
AzureMetrics
| distinct MetricName
解説 :
AzureMetrics テーブルには様々なリソースからメトリックが送られます。各メトリックは MetricName というフィールドを持ち、あるレコードがどのメトリックのデータであるかを見分けることができます。
AzureMetrics
| distinct ResourceProvider,MetricName
解説 :
メトリックの種類はかなり多いので、一覧する際には生成元となっているリソース プロバイダーの情報も利用すると見やすくなります。
distinct オペレーターで ResourceProvider と MetricName の一意な組み合わせを表示すると、各リソースプロバイダ―が生成するメトリックを整理することができます。
AzureMetrics
| where MetricName == "Percentage CPU"
解説 :
特定のメトリックを表示するためには where オペレーターで任意の MetricName を指定します。
AzureMetrics
| where Resource == "CH1-SQLVM12" and MetricName == "Percentage CPU"
解説 :
where オペレーターは複数の条件でレコードをフィルタすることができます。リソース名とメトリックを使用することで、特定のリソースの任意のメトリックだけを表示することができます。
AzureActivity
| take 10
解説 :
この例はデモ ワークスペースでは動作しないかもしれませんので、お手持ちの Log Analytics ワークスペースでお試しください。
[参考:Log Analytics ワークスペースに送信する]Log Analytics ワークスペースに送信する(https://docs.microsoft.com/azure/azure-monitor/essentials/activity-log#send-to-log-analytics-workspace)
AzureActivity テーブルはリソースの変更や仮想マシンの起動といった、サブスクリプションに対する操作が記録されます。
変更作業の確認や、不必要なリソースに変更が行われていないかなどを調べることができます。
AzureActivity
| distinct ResourceProviderValue,_ResourceId, OperationNameValue
解説 :
_ResourceId はリソースの一意の識別子、ResourceProviderValue はリソース プロバイダーを表します。このクエリにより、各リソースにどのような操作が行われたかをプロバイダごとに整理して表示することができます。
AzureActivity
| distinct Caller,CallerIpAddress
解説 :
Caller は実行を行ったユーザー、CallerIpAddress はその際の操作元の IP アドレスです。意図しないユーザーや場所からの操作がないかどうかの確認に使うことができます。
AzureActivity
| where CategoryValue == "Administrative"
| distinct Caller
解説 :
管理作業は CategoryValue に Administrative という値を含みます。
AzureActivity
| where ActivityStatusValue == "Failure" and CategoryValue == "Administrative"
| distinct Caller,CallerIpAddress, _ResourceId
解説 :
操作が失敗したエントリは ActivityStatusValue が Failure になります。このクエリにより管理業務を試みて失敗したユーザーを表示することができます。
失敗の理由は様々ですが、例えば CallerIpAddress が普段と異なる場合にはセキュリティ侵害を示唆している可能性があります。
Azure Monitor のログには、標準で定義されている列があり、データソースにより生成される時刻を示す TimeGenerated
列 によってログレコードの時刻が確認できます。TimeGenerated
列を使用することで、時刻を基にしたフィルターやレコードの件数を確認できます。
print now()
解説 :
現在の時刻は、now()
関数を使用すると取得できます。now()
関数を含む日付や時刻に関する関数が返す値は、datetime
型となり Kusto では UTC 時間で表されます。datetime
型のデータは、テーブルの時刻列(TimeGenerated
)等で使用されており、フィルターやソートなどに使えます。
print datetime("2022-01-01 12:00")
解説 :datetime
関数を使うと文字列を指定して日付や時刻を取得できます。datetime
関数の戻り値はdatetime
型として取得できます。
print datetime("2022-01-01 12:00") + 9h
解説 :datetime
関数で返される datetime
型は UTC 時間で扱われます。タイムゾーンを意識した日付を扱う場合、ユーザーがタイムゾーンを指定する必要があります。UTC 時間を他のタイムゾーンに変更するには、その時間をdatetime
型の値に足します(もしくは引きます)。datetime
型に対する足し引きは、timespan
型の値を使います。このクエリのように、9h
(9時間)や30m
(30分)のような表記を使用します。
print datetime("now") + 9h - 30m
解説 :datetime
型に対する足し引きを使うことで、過去や未来の時間を指定できます。datetime
型に対する足し引きは、timespan
型の値が使えます。
Alert
| where TimeGenerated between (datetime("2022-01-01 00:00:00")..1day)
解説 :
トラブルシューティング等で Azure の各サービスが出力するログを確認する際、特定の 1 日のログを確認したいことがあります。TimeGenerated
列に対して、between
関数とdatetime
関数を組み合わせて使用することで時間の範囲を限定できます。
Alert
| where TimeGenerated between (datetime("2022-01-01 00:00:00")..datetime("2022-01-02 23:59:59"))
解説 :between
関数の範囲の始まりと終わりに、datetime
関数を使用するとdatetime
関数に指定した日時を範囲とすることができます。
Alert
| where TimeGenerated between (datetime("2022-01-01 12:00")..datetime("2022-01-02 12:59"))
解説 :between
関数の範囲の始まりと終わりに、datetime
関数を使用するとdatetime
関数に指定した日時を範囲とすることができます。datetime
関数の引数にはさまざまな日付表現を指定できます。
Alert
| where TimeGenerated > startofday(now())
解説 :TimeGenerated
型に対して比較演算子を使うことで、さまざまな時間の範囲の表現ができます。startofday
関数は引数に指定された日付の開始日時を表すdatetime
型の値を返します。つまり、“2022-01-01 12:34” は、“2022-01-01 0:00:00.000” を表します。
Alert
| where TimeGenerated > startofweek(now())
解説 :TimeGenerated
型に対して比較演算子を使うことで、さまざまな時間の範囲の表現ができます。startofweek
関数は引数に指定された日付の週の開始日時を表すdatetime
型の値を返します。つまり、“2022-01-01 12:34” は、“2021-12-26 0:00:00.000” を表します。
Alert
| where TimeGenerated > ago(3day)
解説 :ago
関数を使用すると現在の時刻から指定した日時前を表すdatetime
型の値を返します。つまり、ago(3d)
は、現在の時刻から3日前の時刻を表します。日付以外にも、1m
や1h
などの時間単位を指定できます。
Alert
| where TimeGenerated > ago(30m)
解説 :
大きな時間範囲でクエリを実行すると実行時間が長くなります。Azure Firewall の診断ログや OS のパフォーマンスログ等大量にログが発生し得るテーブルを対象にする場合は、可能な限り時間範囲を絞った上でクエリを実行することを心がけてください。
Alert
| where TimeGenerated > ago(1.5h)
解説 :timespan
型はさまざまな表現が出来ます。このクエリのように小数点を表すこともできます。
Alert
| where TimeGenerated between (now(-3d)..1day)
解説 :now
関数には、引数でtimespan
型のオフセットを指定できます。between
関数と組み合わせるとさまざまな時間範囲の表現ができます。このクエリは now(-3d)
を ago(3d)
としても同じ結果になります。
Alert
| where TimeGenerated > startofday(now()) - 9h
解説 :TimeGenerated
やstartofday
関数は、UTC時間で表現されます。従って、ローカル時間でフィルターする場合はタイムゾーンを考慮する必要があります。
Alert
| where TimeGenerated > ago(30m)
| extend timeAgo = now() - TimeGenerated
解説 :
アクセスログ等が含まれるテーブルにおいて、レコードの時刻と現在時刻の差を確認したいことがあります。extend
と時刻関数を使用すると新たにカラムを追加し、時刻差を出力できます。
AzureDiagnostics
| where TimeGenerated > startofweek(now())
| summarize count() by startofday(TimeGenerated)
解説 :summarize
関数は時刻関数と組み合わされることがよくあります。アクセスログを集計する際等に利用すると便利です。
AzureDiagnostics
| where TimeGenerated >= ago(30m)
| summarize count() by bin(TimeGenerated, 1m)
解説 :summarize
関数とbin
関数、時刻関数を組み合わせると日付に対してより柔軟な集計が出来ます。bin
関数はfloor
関数(床関数)のエイリアスです。
Azure Monitor に保存されるログは生成元のリソースに応じて多様なフィールドをもち、多様な分析を行うことができます。一方、全てのフィールドを表示してしまう、テーブルに非常に多くの列が表示され、結果のデータセットは大きく、見づらくなってしまいます。ここではデータから必要なフィールドだけを選び出したり、フィールドの名前を変更して分析しやすくしたりなど、データを整型する方法について学習します。
Heartbeat
| where TimeGenerated > ago (5m)
| project Computer, TimeGenerated
解説 :
Heartbeat は Log Analytics エージェントによって送信される健全性の状態が記録されるテーブルです。
このテーブルを確認することで、特定の時刻のコンピューターの簡単な死活監視を行うことができます。project
演算子は結果セットの出力を特定の列に絞ることができます。このクエリでは出力結果を Computer 列と TimeGenerated 列に限定しています。出力される列の順番は project
に渡された引数の順番になり、元のテーブルの順序ではなくなります。
Heartbeat 列はこの他にコンピューターの OS の情報や国などの地理情報も含んでいます。
Heartbeat
| where TimeGenerated > ago (5m)
| project VM=Computer, TimeStamp=TimeGenerated
解説 :project
演算子は出力列を選択する際に、列の名前を任意の文字列に変更することができます。
これにより出力列をわかりやすい名前に変更することができるほか、join
など列名を参照するようなオペレーターをより簡単に扱うことができます。
Heartbeat
| where TimeGenerated > ago (5m)
| project ['Virtual Machine']=Computer, ['Time Stamp']=TimeGenerated
解説 :
見やすさのために列名にスペースを使いたいという場合がありますが、単純に ‘変更後 列名’ = 変更前の列名 のように文字列をクォートで囲むだけではうまくいきません。
括弧 [] で文字列を囲むことで、変更後の列名にスペース入が入った文字列を使用することができます。
Heartbeat
| where TimeGenerated > ago (5m)
| project VM=toupper(Computer), TimeStamp=datetime_add("Hour",5,TimeGenerated)
// simplified expression
Heartbeat
| where TimeGenerated > ago (5m)
| project VM=toupper(Computer), TimeStamp= TimeGenerated + 5h
解説 :project
演算子は列を選択する際に計算式を適用することができます。このクエリでは datetime_add 関数を使用して、TimeGenerated に 5時間を加えたものを新しい列の値として設定しています。
Heartbeat
| where TimeGenerated > ago (5m)
| project-away VMUUID, MG, ManagementGroupName, SourceComputerId
解説 :project
演算子は出力する列を選択しますが、project-away
演算子は出力しない列を選択します。出力から取り除きたい列が少ない場合にはこの演算子のほうが効率的かもしれません。
Heartbeat
| where TimeGenerated > ago (5m)
| project-away Resource*
解説 :project-away
演算子は特定のパターンを含む列を除外することができます。ワイルドカード文字を使用して、例えば ABC* を project-away
に渡すと 「ABC から始まる列は除く」という意味になります。
Heartbeat
| where TimeGenerated > ago (5m)
| project-keep Resource*
解説 :project-keep
演算子は project
と同じように列の選択を行います。結果の列の順序はテーブルの素の順序に従うという点が project
との大きな違いです。
Heartbeat
| where TimeGenerated > ago (5m)
| project-reorder * desc
解説 :
出力結果の列は project-reorder
演算子で並び替えることができます。この例では全ての列を降順に並び替えています。
Heartbeat
| where TimeGenerated > ago (5m)
| project-rename VM=Compute
解説 :project-rename
演算子は列名を変更することができます。project
でも列名の変更はできますが、project-rename
は他の列のフィルタリングには影響を与えずに、特定の列の名前だけを変更することができます。
Heartbeat
| extend
Age = now() - TimeGenerated
解説 :extend
演算子は計算列を作成し、結果セットに追加します。この例では現在時刻とログが生成された時刻の差分を計算した新しい列を追加しています。
Heartbeat
| summarize LastReported=now()-max(TimeGenerated) by Computer,TimeGenerated
| extend RecentHeartBeat=iff(TimeGenerated > ago(5m),'✔️ ', '❌ ')
解説 :iif
関数は最初の引数が true であれば 2番目の引数を、false であれば 3 番目の引数の結果を返します。2番目や3番目の引数には計算式を持つこともでき、条件に応じてより複雑な処理を行うこともできます。
ログは特定の目的のために並び替えを行ったり、データの特定の側面にフォーカスするために集計をする必要があります。ここでは summarize
演算子と、集計関数を使用して、ログやメトリックに含まれる情報を整理する方法について学習します。
InsightsMetrics
| summarize count() by Computer, Namespace, Name
解説 :summarize
演算子は入力されたテーブルを様々な形に集計することができます。集計の種類は引数の集計関数で指定することができ、count()
は単純にレコードの数を数える集計関数です。
集計の単位は by に続く列名で指定することができ、この例では Computer と Namespace の組み合わせに対して集計を行っています。
InsightsMetrics は (従来の Log Analytics エージェントによって収集される Perf ではなく) VM Insights によって収集されるパフォーマンス カウンターを格納するためのテーブルです。
InsightsMetrics
| summarize dcount(Name) by Computer
解説 :dcount()
関数は与えられた列の中で、ユニークな値が何個あるかを計算する集計関数です。この例ではコンピューターから収集されるパフォーマンス カンターの名前ですが、ユーザーがログインしている場所の数、コンピューターが接続したことのある IP の数など、様々な集計に使うことができます。
InsightsMetrics
| where Name == "UtilizationPercentage"
| summarize avg(Val) by Computer
解説 :summarize
演算子に与える集計関数を変えることで集計方法が変わります。avg()
関数に対象とする列名を与えることで、列の値の平均値を計算することができます。
InsightsMetrics
| where Name == "UtilizationPercentage"
| summarize max(Val) by Computer
解説 :max()
関数に対象とする列名を与えることで、列の値の最大値を計算することができます。
InsightsMetrics
| where Name == "UtilizationPercentage"
| summarize min(Val) by Computer
解説 :min()
関数に対象とする列名を与えることで、列の値の最小値を計算することができます。
InsightsMetrics
| where Name == "UtilizationPercentage"
| summarize avg(Val) by Computer, bin(TimeGenerated, 1h)
解説 :summarize
演算子の集計は複数の列に対して行うことができます。この例は非常によく使われるパターンで、注目したいリソースと時間に対して集計を行うことで、特定のリソースのふるまいを時系列で集計することができます。
単純に TimeGenerated を使った場合には単位が細かすぎてしまうので、bin()
関数を使って丸めるのが一般的です。例では 1 時間単位に丸めていますが、10 分 (10m) 、100 秒 (100s) といった丸め方もできます。
InsightsMetrics
| where Namespace == "LogicalDisk" and Name == "FreeSpacePercentage"
| extend DiskInstance = tostring(parse_json(Tags).["vm.azm.ms/mountId"])
| summarize FreeDiskSpace = avg(Val) by Computer, DiskInstance
| order by FreeDiskSpace asc
| take 10
解説 :
ディスクの空き容量を表すパフォーマンス カウンターの名前は FreeSpacePercentage
です。この例では集計した時間帯の FreeSpacePercentage
の平均値が最も小さいディスクを 10 個選択しています。
InsightsMetrics テーブルではボリュームのラベルは直接値としては列に現れず、JSON データとして Tags 列に含まれています。
このため parse_json
関数を使用して Tags 列を解析して取得したボリュームのラベルの値を extend
演算子により新たな列の値として設定しています。
let threshold = 20;
InsightsMetrics
| where Namespace == "LogicalDisk" and Name == "FreeSpacePercentage"
| extend DiskInstance = tostring(parse_json(Tags).["vm.azm.ms/mountId"])
| summarize FreeDiskSpace = avg(Val) by Computer, DiskInstance
| where FreeDiskSpace < threshold
解説 :
空き容量が一定の値以下のディスクを表示しています。この例では閾値となる数値を threshold という名前の変数に格納しています。
変数を使用することで変更、再利用が容易で、わかりやすいクエリにすることができます。
Event
| summarize count() by Computer
解説 :
コンピュータごとに収集したイベント数をカウントする
Event
| summarize count() by bin(TimeGenerated, 1h), Computer
解説 :
コンピュータごとに収集したイベント数を1時間のタイムバケットに集約してカウントする
Event
| summarize count() by Computer
| top 10 by Computer
解説 :
コンピュータごとに収集したイベント数をカウントし、イベントを収集している上位10台のコンピュータを表示します。
Perf
| where ObjectName == "Process" and CounterName == "% Processor Time"
| summarize AverageValue = avg(CounterValue) by InstanceName
| top 10 by InstanceName
| order by AverageValue
解説 :
全サーバーにおけるプロセスの % Processor
をまとめ、上位10位までをリストアップしてください。
Azure Monitor ではクエリで取得したデータセットのテーブルを見やすく表示することができます。ここでは render
演算子を使用して、データセットを棒グラフや折れ線グラフとして可視化する方法を学習します。
SecurityEvent
| summarize EventCount = count() by EventID
| top 10 by EventCount
| render columnchart
Description :
Use the render operator to draw a chart of the top 10 Security Events
SecurityEvent
| summarize EventCount = count() by bin(TimeGenerated, 1h), Computer
| render timechart
Description :
Use the render operator to draw a chart of the security event distribution over time, per computer
InsightsMetrics
| where Namespace == "Processor" and Name == "UtilizationPercentage"
| summarize AverageValue = avg(Val) by bin(TimeGenerated, 1h), Computer
| render timechart with (ycolumns = Computer, series= AverageValue)
Description :
Use the render operator to draw a chart of the processor utilisation over time with aggregations into 1 hour averages, broken down by computer
InsightsMetrics
| where Namespace == "Memory" and Name == "AvailableMB"
| extend memorySizeMB = toint(parse_json(Tags).["vm.azm.ms/memorySizeMB"])
| extend PercentageUsed = 100-(Val/memorySizeMB)*100
| summarize AverageValue = avg(PercentageUsed) by bin(TimeGenerated, 30m), Computer
| render timechart
Description :
Use the render operator to draw a chart of the percentage used memory over time with aggregations into 30 minute averages, broken down by computer. The memory used percentage is a calculated column, as only available memory in MB and total memory in MB is presented
AzureDiagnostics
| summarize count() by ResourceProvider
| render piechart
Description :
Use the render operator to draw a chart of the different sources collected into Azure Diagnostics
Update
| where UpdateState == "Needed" and OSType!="Linux"
| summarize arg_max(TimeGenerated, *) by Title
| where (Classification == "Security Updates" or Classification == "Critical Updates" or Classification == "Definition Updates" or Classification == "Others")
| summarize MissingUpdates = count() by Classification
| order by MissingUpdates desc
| render piechart
Description :
Use the render operator to draw a chart of the missing update count in Update Management
AzureMetrics
| where ResourceProvider == "MICROSOFT.LOGIC"
| where MetricName == "RunLatency"
| summarize AverageLatency = avg(Average) by bin(TimeGenerated, 10m), Resource
| render areachart
Description :
Use the render operator to draw a chart of run latency for logic apps
数のテーブルに分散した特定のリソースの情報を分析したいようなケースではテーブルを結合することができます。よく似た(あるいは全く同じ性質の)テーブル同士を結合したデータセットに対して分析を行ったり、あるいはリソースへの追加となる情報を持つテーブルから特定の情報を選び出し、データをエンリッチすることができます。ここではテーブルを結合するための演算子を学習します。
VMComputer
| project Computer, OperatingSystemFullName, _ResourceId
| join (
InsightsMetrics
| where Name == "Heartbeat"
| summarize LastHeartbeat = arg_max(TimeGenerated, *) by _ResourceId
| project LastHeartbeat, _ResourceId
) on _ResourceId
| project-away _ResourceId1
Description :
Use the join operator to join two tables to see last heartbeat per computer
SecurityEvent
| where EventID == 4624 // sign-in events
| project Computer, Account, TargetLogonId, LogonTime=TimeGenerated
| join kind= inner (
SecurityEvent
| where EventID == 4634 // sign-out events
| project TargetLogonId, LogoffTime=TimeGenerated
) on TargetLogonId
| extend Duration = LogoffTime-LogonTime
| project-away TargetLogonId1
| top 10 by Duration desc
Description :
Use the join operator to join two queries from the SecurityEvents table together to determine logon duration
Update
| where OSType!="Linux" and Optional==false
| summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer,SourceComputerId,UpdateID
| where UpdateState=~"Needed" and Approved!=false
| join (UpdateSummary
| summarize arg_max(TimeGenerated, *) by Computer, OsVersion, RestartPending
| project Computer, OsVersion, RestartPending
)
on Computer
| join ( Heartbeat
| summarize LastHeartBeat = arg_max(TimeGenerated, *) by Computer
| project LastHeartBeat, Computer
) on Computer
| summarize arg_max(TimeGenerated, *), SecurityUpdates = countif(Classification == "Security Updates"), CriticalUpdates = countif(Classification == "Critical Updates"), DefinitionUpdates = countif(Classification == "Definition Updates"), ServicePacks = countif(Classification == "Service Packs"), Others = countif(Classification != "Security Updates" and Classification != "Critical Updates" and Classification != "Definition Updates" and Classification != "Service Packs") by Computer, OsVersion, RestartPending, ResourceId, LastHeartBeat
| project Computer, ResourceId, OsVersion, RestartPending, LastHeartBeat, SecurityUpdates, CriticalUpdates, DefinitionUpdates, ServicePacks, Others
Description :
Use the join operator to join Heartbeat table to Update Management table to view update status, last heartbeat and reboot status
Heartbeat
| summarize arg_max(TimeGenerated, *) by Computer, _ResourceId
| join (
Syslog
| summarize SyslogCount = count() by Computer, _ResourceId
) on _ResourceId
| project _ResourceId, Computer, ComputerIP, OSName, ResourceGroup, SubscriptionId, SyslogCount
Description :
Use the join operator to join Heartbeat table to syslog table to get a count of events per computer
Azure Monitor に保存されるログは、全部が分析のために最適な形になっているわけではありません。具体的にはログの生成元が XML や JSON、あるいは構造化されていないただのテキストデータを生成していて、そのデータは複数のフィールドとして加工されずにどこか一つのフィールドに格納されていることがあります。ここでは、そのようなフィールドを扱いやすく加工するための方法について学習します。
AzureDiagnostics
| where ResourceType == "SERVERS/DATABASES"
| parse ResourceId with * "/RESOURCEGROUPS/" ResourceGroupName "/" * "/DATABASES/" Databasename
| project TimeGenerated, Category, OperationName, ResourceGroupName, Databasename
解説 :parse
オペレーターを使用して、リソース ID フィールドからリソースグループとリソー ス名を抽出します。
Syslog
| where Facility == "authpriv"
| parse SyslogMessage with * "(" session "):" * "user" UserName
解説 :
ログの文字列エントリから一貫して文字列値を抽出するには、parse
コマンドを使用します。
VMComputer
| summarize arg_max(TimeGenerated, *) by Computer
| extend IPAddress = tostring(Ipv4Addresses[0])
| extend DNSNAme = tostring(DnsNames[0])
| project Computer, BootTime, IPAddress, DNSNAme, OperatingSystemFullName, PhysicalMemoryMB, Cpus, CpuSpeed, AzureResourceGroup, AzureSubscriptionId
解説 :project
演算子を使用して、クエリの列を特定することができます。
SecurityEvent
| summarize count() by EventID, Activity
| project-away EventID
解説 :
クエリ結果から特定のカラムを除外するには、project-away
演算子を使用します。
ここでは複雑なクエリを書く際に頻繁に使われる記法や、必要とされる頻度は多くないものの特定のな問題を効率よく解決するための KQL を紹介します。
色々な分析の中で
let serviceName= "VirtualDesktop";
externaldata(changeNumber: string, cloud: string, values: dynamic)["https://download.microsoft.com/download/7/1/D/71D86715-5596-4529-9B13-DA13A5DE5B63/ServiceTags_Public_20220228.json"] with(format='multijson')
| mv-expand values
| where values contains serviceName
| mv-expand values.properties.addressPrefixes
| project addressPrefixes= tostring( values_properties_addressPrefixes)
解説 :
Azure のサービスで使われる IP アドレスはサービスタグとして公開されていて、インターネット上から参照することができます。externaldata
オペレーターは外部のストレージ アカウントから CSV や JSON などで記述されたデータを取得します。このサンプルでは直接インターネット上からファイルを取得していますが、SAS を使用してあアクセスが制御されているストレージ アカウントからデータを取得することができます。
注意 - ファイル名 ServiceTags_Public_YYYYMMDD.json は IP リストの更新に伴い変更されるため、次のページから常に新しいファイルを参照する必要があります。
Azure IP Ranges and Service Tags – Public Cloud
KQL で参照するファイルは自身で管理するストレージアカウントに配置し、リストが更新されるたびに自動的にストレージ アカウントのファイルが更新されるような仕組みを考えてください。
Using external data sources to enrich network logs using Azure storage and KQL
print now()
print now(9h)
print ago(9h)
print substring("hello KQL world",6,3)
print 1 + 2 + 3
print iif(true, 100 , 200)
print iif(false, 100 , 200)
解説 :print
オペレーターはスカラー式(複数の行を持つテーブルを作らない計算)を実行します。時刻や文字列の計算を長いクエリに含める際に、予め部分的に計算結果を確認しておきたいような場合に便利です。
参考ドキュメント