MQL 言語の概要

このページでは、以下のトピックのような、Monitoring Query Language(MQL)に関する一般的な情報を提供します。

この情報は、Google Cloud Console または Cloud Monitoring API のどちらから MQL を使用するかに関係なく適用されます。MQL クエリの構造については、をご覧ください。

テーブル オペレーションと関数のショートカット

クエリは通常、パイプ(|)で接続されたテーブル オペレーションの接続されたチェーンで構成されます。各チェーンは、テーブル オペレーションの名前で始まり、その後に式のリストが続きます。式には、すべての引数を明示的にリストする関数呼び出しを含めることができます。ただし Monitoring Query Language では、クエリをいくつかのショートカットで表現できます。

このセクションでは、関数をテーブル オペレーションとして使用するテーブル オペレーションのショートカットと、関数の引数として値列のショートカットについて説明します。

詳細な一覧については、テーブル オペレーションのショートカットをご覧ください。

テーブル オペレーションのショートカット

fetchgroup_byfilter のオペレーションを使用する場合、目的のオペレーションを決定するのに十分な引数がある場合、明示的なテーブル オペレーションを省略できます。たとえば、次のクエリの場合:

gce_instance::compute.googleapis.com/instance/cpu/utilization

これは次と同等です。

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization

次の group_by オペレーションは同等です。

         [zone], mean(val())
group_by [zone], mean(val())

フィルタテストを丸括弧で囲む場合は、単語 filter を省略できます。たとえば、次の 2 つの filter オペレーションは同等です。

       (instance_name =~ 'apache.*')
filter instance_name =~ 'apache.*'

これらのショートカット フォームは、クエリと組み合わせることが可能です。たとえば、次のクエリの場合:

gce_instance::compute.googleapis.com/instance/cpu/utilization
| (instance_name =~ 'apache.*')
|  [zone], mean(val())

これは、以下の明示的な形式と同等です。

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| filter instance_name =~ 'apache.*'
| group_by [zone], mean(val())

テーブル オペレーションのショートカットの詳細については、MQL リファレンスのテーブル オペレーションのショートカットをご覧ください。

関数をテーブル オペレーションとして使用する

テーブル オペレーションは通常、テーブル オペレーションの名前で始まります。ただし MQLでは、代わりに関数名でテーブル オペレーションを開始できます。

名前付き関数が入力テーブルの値列の変換を実行する場合は、関数名を使用できます。この置換は、名前が指定されている関数の種類に応じて、group_byalignvalue テーブル オペレーションのショートカットです。

一般的な形式を次に示します。

|  FUNCTION_NAME ARG, ARG ... 

テーブル オペレーションで、関数は入力テーブルの値列を引数として受け取り、その後に関数自体の引数が続きます。関数をテーブル オペレーションとして使用するときは、テーブル オペレーション形式の引数を、通常のかっこ(())ではなく、カンマ区切りのリストとして指定します。

ショートカットを展開することで生成される完全なテーブル オペレーションは、関数の種類によって異なります。

  • group_by: すべての時系列識別子列を集計する(グループ化に [] を使用する)group_by オペレーションで集計関数を使用している場合は、この関数をショートカットとして使用できます。たとえば、

    | distribution powers_of(1.1)

    これは、以下のショートカットです。

    | group_by [], distribution(val(0), powers_of(1.1))
  • align: align オペレーションの引数としてアライメント関数を使用する場合は、この関数をショートカットとして使用できます。たとえば、

    | delta

    これは、以下のショートカットです。

    | align delta()

    同様に、

    | rate 10m

    これは、以下のショートカットです。

    | align rate(10m)

    整列指定子関数は入力時系列を暗黙の引数として受け取るため、値列は明示的に指定されません。

  • value: 他のすべての関数は、value テーブル オペレーションのショートカットとして機能します。たとえば、

    | mul 3.3

    これは、以下のショートカットです。

    | value mul(val(0), 3.3)

    同様に、

    | div

    これは、以下のショートカットです。

    | value div(val(0), val(1))

    div は、2 つの値列を持つ入力テーブル オペレーションをショートカットし、1 つの値列(比率)を持つテーブル オペレーションを生成します。

値列の関数のショートカット

入力に単一の値列がある場合は、function(val()) のショートカットとして .function を使用できます。2 つの値列がある場合は function(val(0), val(1)) のショートカットとして使用できます。

先頭のドットは、「次の関数を呼び出して、入力ポイントの値列を関数の引数として関数に渡す」という意味です。

たとえば、.meanmean(val()) のショートカットです。以下はすべて同じ結果になります。

group_by [zone], .mean
group_by [zone], mean(val())

入力テーブルに複数の値列がある場合、各列はこのショートカットの関数の引数になります。たとえば、入力テーブルに 2 つの値列がある場合:

.div

これは、以下のショートカットです。

div(val(0), val(1))

このショートカットでは、値列を参照しない引数を指定できます。追加の引数は、value-column 引数の後に指定します。たとえば、入力テーブルに 1 つの値列がある場合:

.div(3)

は、次と等価です。

div(val(0), 3)

fetch のバリエーション

fetch オペレーションは通常、モニタリング対象リソースタイプと指標タイプのペアで指定された時系列のテーブルを返します。例:

fetch gce_instance :: compute.googleapis.com/instance/cpu/utilization

指標が 1 つのモニタリング対象リソースタイプのみに適用される場合、クエリからモニタリング対象リソースを除外できます。次のクエリでは、CPU 使用率指標が gce_instance モニタリング対象リソースのみ適用されるため、前のクエリと同じになります。

fetch compute.googleapis.com/instance/cpu/utilization

fetch オペレーションで指定できるのは、後続の metric オペレーションに指定された指標のモニタリング対象リソースタイプのみです。たとえば、以下の例は前の fetch の例と同じです。

fetch gce_instance
| metric metric compute.googleapis.com/instance/cpu/utilization

fetch をこのように分割すると、同じモニタリング対象リソースに対して 2 つの異なる指標を取得する場合に役立ちます。たとえば次のクエリは、CPU 秒あたりの消費パケット数を計算します。

fetch gce_instance
| {
    metric compute.googleapis.com/instance/network/received_packets_count ;
    metric compute.googleapis.com/instance/cpu/usage_time
  }
| ratio

fetch を分割すると、モニタリング対象リソースのラベルのみをフィルタリングすることもできます。

fetch gce_instance
| filter resource.zone =~ "asia.*"
| {
    metric compute.googleapis.com/instance/network/received_packets_count ;
    metric compute.googleapis.com/instance/cpu/usage_time
  }
| ratio

モニタリング対象リソースタイプの名前を指定する fetch は、その後に metric オペレーションが続く場合、filter オペレーションがインターセプトされる必要があります。

厳密な形式のクエリ

厳密な形式のクエリとは、簡潔なクエリで使用されるショートカットや暗黙的な値を含まないクエリです。厳密なクエリの特徴は次のとおりです。

  • すべてのショートカットは置き換えられます。
  • 暗黙的な引数はすべて明示的になります。
  • 列はフルネームで参照されます。
  • 新しい列には明示的に名前が付けられます。
  • 暗黙的に指定されたアライメント操作は明示的に指定されるようになります。

厳密な形式を使用すると、入力テーブルの構造の変更に対するクエリの復元力が高まり、クエリの実行内容が明確になります。クエリを厳密な形式で配置しても、クエリの効率は向上しません。

グラフ用のクエリを保存すると、厳密な形式に変換されます。保存操作の確認ダイアログに厳密な形式が表示されます。

アラート ポリシーの簡潔なクエリは、厳密な形式に変換されません。アラート ポリシーのクエリは、指定したとおりに保存され、簡潔または厳密な形式を使用できます。

ショートカットと厳密な形式の両方が利用可能な場合、互いに大きく異なるように見える同等の MQL クエリが発生する可能性があります。消費された CPU 秒あたりの受信パケット数を計算する次のクエリは、多くのショートカットを使用します。

gce_instance
| (zone =~ ".*-a")
| {
    compute.googleapis.com/instance/network/received_packets_count ;
    compute.googleapis.com/instance/cpu/usage_time
  }
| join
| div

このクエリをグラフに保存するか、アラートポリシーの一部として保存すると、結果の厳密な形式のクエリはまったく同じことを行います。ただし、次の例に示すように、厳密な形式はまったく異なる場合があります。

fetch gce_instance
| filter (resource.zone =~ '.*-a')
| { t_0:
      metric 'compute.googleapis.com/instance/network/received_packets_count'
      | align delta() ;
    t_1:
      metric 'compute.googleapis.com/instance/cpu/usage_time'
      | align delta() }
| join
| value [v_0: div(t_0.value.received_packets_count, t_1.value.usage_time)]

グラフの保存された定義を編集すると、コードエディタに厳密な形式が表示されます。

resource.project_id 列の照合

Google Cloud プロジェクトには表示名があります。この表示名はメニューには表示されますが、一意に識別することはできません。プロジェクトの表示名は「Monitoring demo」のようになります。

プロジェクトには、識別子として機能するフィールドが 2 つあります。

  • プロジェクト ID: 一意の文字列の識別子です。この識別子は多くの場合、表示名に基づいたものになります。プロジェクト ID は、プロジェクトの作成時に設定されます。通常は、プロジェクト名の要素をつなげたものであり、一意性を保つために必要に応じて末尾に数字が追加されます。プロジェクト ID の形式は、「monitoring-demo」や「monitoring-demo-2349」のようになります。プロジェクト ID は、単にプロジェクト名と呼ばれることもあります。
  • プロジェクト番号: 一意の数値の識別子です。

すべてのモニタリング対象リソースタイプには、そのリソースを所有するプロジェクトのプロジェクト番号と、そのリソースに関するデータを表す project_id ラベルが含まれます。

MQL クエリでは、このラベルを resource.project_id と呼びます。resource.project_id ラベルには、値としてテキスト形式のプロジェクト番号がありますが、その値は特定の状況では MQL によってプロジェクト ID に変換されます。

以下の例では、MQL は resource.project_id ラベルの値をプロジェクト番号ではなくプロジェクト ID として扱います。

  • グラフの凡例には、resource.project_id ラベルのプロジェクト番号ではなく、プロジェクト ID が表示されます。

  • resource.project_id の値と文字列リテラルの等価比較では、プロジェクト番号とプロジェクト ID の両方が認識されます。たとえば、次のプロジェクトが所有するリソースには、どちらも true を返します。

    • resource.project_id == "monitoring-demo"
    • resource.project_id == "530310927541"

    このケースは、== 演算子と != 演算子、およその関数のフォーム(eq()ne())に適用されます。

  • resource.project_id ラベルの正規表現の一致は、プロジェクト番号またはプロジェクト ID のいずれかに対して正しく機能します。たとえば、次の式はどちらも、このプロジェクトが所有するリソースに対して true を返します。

    • resource.project_id =~ "monitoring-.*"
    • resource.project_id =~ ".*27541"

    このケースでは、=~ 演算子と !~ 演算子で機能し、関数では re_full_match を形成します。

それ以外の場合は、resource.project_id ラベルの実際の値が使用されます。たとえば、concatenate("project-", resource.project_id) と指定すると、project-monitoring-demo ではなく project-530310927541 という値になります。

比率と「エッジ エフェクト」

一般に、ラベル値を使用して、単一の指標タイプに対して収集された時系列に基づいて比率を計算することが最適です。2 つの異なる指標タイプで計算された比率は、サンプリング期間とアライメント ウィンドウが異なるため、異常が発生する可能性があります。

たとえば、RPC の合計数と RPC のエラー数の 2 つの異なる指標タイプがあり、RPC の合計数に対する RPC のエラー数の割合を計算するとします。失敗した RPC は、両方の指標タイプの時系列でカウントされます。そのため、時系列をアライメントすると、失敗した RPC が両方の時系列の同じアライメント間隔に表示されない場合があります。この差は、次のような原因で発生することがあります。

  • 同じイベントを記録する 2 つの異なる時系列があるため、コレクションを実装する 2 つの基になるカウンタ値があり、それらはアトミックに更新されません。
  • サンプリング レートは異なる場合があります。時系列が共通の期間にアラインメントされると、単一のイベントのカウントが、異なる指標の時系列の隣接するアラインメント間隔に表示される場合があります。

対応するアライメント間隔の値の数の差は、1/0 や 2/1 などの意味のない error/total 比率値になる場合があります。

大きな数値の比率の場合、意味のない値になる可能性は低くなります。 サンプリング期間よりも長いアライメント ウィンドウを使用するか、特定のラベルのデータをグループ化すれば、集計で大きな数値を取得できます。これらの手法は、特定の間隔でのポイント数のわずかな違いによる影響を最小限に抑えます。つまり、間隔内の予想されるポイント数が 3 の場合、予想される数が 300 の場合よりも、2 ポイントの不一致による影響が大きくなります。

組み込みの指標タイプを使用している場合は、指標タイプ全体の比率を計算して、必要な値を取得せざるを得ない場合があります。

2 つの異なる指標で同じもの(エラー ステータスを返す RPC など)をカウントする可能性のあるカスタム指標を設計している場合は、代わりに、各カウントを 1 回だけ含む単一の指標を検討してください。たとえば、RPC をカウントしていて、すべての RPC に対する失敗した RPC の比率を追跡するとします。RPC をカウントする単一の指標タイプを作成し、ラベルを使用して「OK」ステータスを含む呼び出しのステータスを記録します。次に、その場合の単一のカウンタを更新することにより、各ステータス値、エラーまたは「OK」が記録されます。

MQL の日付形式

MQL で現在サポートされる日付形式には制限があります。MQL クエリでは、日付は次のいずれかの形式で表現されます。

  • d'BASE_STRING'
  • D'BASE_STRING'

BASE_STRING2010/06/23-19:32:15-07:00 の形式の文字列です。日付と時刻を区切る最初のダッシュ(-)はスペースにすることもできます。時間コンポーネントでは、実時間(19:32:15)またはタイムゾーン指定子(-07:00)の一部を削除できます。

以下は、MQL クエリの有効な日付の例です。

  • d'2010/06/23-19:32:15-07:00'
  • d'2010/06/23 19:32:15-07:00'
  • d'2010/06/23 19:32:15'
  • D'2010/06/23 19:32'
  • d'2010/06/23-19'
  • D'2010/06/23 -07:00'

次のテーブルは、BASE_STRING の文法を示しています。

構造 意味
%Y/%m/%d 日付
%Y/%m/%d %H
%Y/%m/%d-%H
日付、時
%Y/%m/%d %H:%M
%Y/%m/%d-%H:%M
日付、時、分
%Y/%m/%d %H:%M:%S
%Y/%m/%d-%H:%M:%S
日付、時、分、秒
%Y/%m/%d %H:%M:%E*S
%Y/%m/%d-%H:%M:%E*S
日付、時、分、秒、秒の小数部
%Y/%m/%d %Ez タイムゾーン情報を含む日付
%Y/%m/%d %H%Ez
%Y/%m/%d-%H%Ez
タイムゾーン情報を含む日付、時
%Y/%m/%d %H:%M%Ez
%Y/%m/%d-%H:%M%Ez
タイムゾーン情報を含む日付、時、分
%Y/%m/%d %H:%M:%S%Ez
%Y/%m/%d-%H:%M:%S%Ez
タイムゾーン情報を含む日付、時、分、秒
%Y/%m/%d %H:%M:%E*S%Ez
%Y/%m/%d-%H:%M:%E*S%Ez
タイムゾーン情報を含む日付、時、分、秒、秒の小数部

クエリの長さと複雑さ

Monitoring Query Language クエリが長く複雑になる場合がありますが、制限がないわけではありません。

  • UTF-8 でエンコードされたクエリテキストは 10,000 バイトに制限されます。
  • クエリは 2,000 の言語構文に制限されています。つまり、AST の複雑さは 2,000 ノードに制限されます。

抽象構文ツリー(AST)は、ソースコード(この場合は MQL クエリ文字列)の表現であり、ツリー内のノードはコード内の構文構造にマッピングされます。

MQL のマクロ

MQL にはマクロ定義ユーティリティが含まれています。MQL のマクロを使用して、繰り返しオペレーションを置き換え、複雑なクエリを読みやすくし、クエリの開発を容易にできます。マクロは、テーブル オペレーションと関数のマクロを定義できます。

マクロ定義はキーワード def で始まります。

クエリを厳密な形式に変換すると、マクロの呼び出しが対応するテキストに置き換えられ、マクロの定義は削除されます。

マクロを含むグラフクエリを保存すると、クエリは厳密な形式に変換されるため、マクロは保持されません。アラート ポリシーの条件に対するクエリを保存すると、そのクエリは厳密な形式に変換されないため、マクロが保持されます。

テーブル オペレーションのマクロ

マクロを作成して、新しいテーブル オペレーションを作成できます。一般的な構文は次のようになります。

def MACRO_NAME [MACRO_PARAMETER[, MACRO_PARAMETER]] = MACRO_BODY ;

マクロを呼び出すには、次の構文を使用します。

@MACRO_NAME [MACRO_ARG [, MACRO_ARG]]

たとえば、次のクエリを使用して CPU 使用率データを取得するとします。

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| every 1m
| group_by [zone], mean(val())

最初の行は次のマクロに置き換えることができます。

def my_fetch = fetch gce_instance::compute.googleapis.com/instance/cpu/utilization ;

クエリでマクロを呼び出すには、元の fetch を次のように置き換えます。

def my_fetch = fetch gce_instance::compute.googleapis.com/instance/cpu/utilization ;

@my_fetch
| every 1m
| group_by [zone], mean(val())

2 行目と 3 行目は、引数を取るマクロに置き換えることができます。マクロ定義では、マクロにパラメータが列挙され、マクロ本文ではパラメータがマクロに対し $MACRO_PARAMETER として参照されます。たとえば、次のマクロを定義できます。

def my_every time_arg = every $time_arg ;

def my_group label, aggr = group_by [$label], $aggr ;

これらのマクロを呼び出して引数を指定するには、マクロ呼び出しのカンマ区切りリストで引数を指定します。定義されたすべてのマクロとその呼び出しによるクエリを次に示します。

def my_fetch = fetch gce_instance::compute.googleapis.com/instance/cpu/utilization ;
def my_every time_arg = every $time_arg ;
def my_group label, aggr = group_by [$label], $aggr ;

{@my_fetch}
| @my_every 1m
| @my_group zone, mean(val())

クエリが厳密な形式に変換されると、マクロは保持されません。たとえば、前のクエリの厳密な形式は、次のようになります。

fetch gce_instance::compute.googleapis.com/instance/cpu/utilization
| align mean_aligner()
| every 1m
| group_by [resource.zone],
           [value_utilization_mean: mean(value.utilization)]

関数のマクロ

MQL 関数の場合は、カンマ区切りリストで、かっこで囲んでパラメータを指定します。かっこによって、関数マクロとテーブル オペレーション マクロを区別します。引数がない場合でも、呼び出しにかっこが記述されている必要があります。クエリが厳密な形式に変換されると、マクロは保持されません。

def MACRO_NAME([MACRO_PARAMETER [, MACRO_PARAMETER]]) = MACRO_BODY ;

たとえば、次のクエリは 2 つの指標に対するテーブルを取得し、2 つのテーブルを、2 つの値列を持つ 1 つのテーブルにまとめ、received_percent という列について、受け取ったバイト数と合計バイト数の比を計算します。

{
  fetch k8s_pod :: kubernetes.io/pod/network/received_bytes_count ;
  fetch k8s_pod :: kubernetes.io/pod/network/sent_bytes_count
}
| join
| value [received_percent: val(0) * 100 / (val(0) + val(1))]

received_percent の計算は、次の例のようなマクロに置き換えることができます。

def recd_percent(recd, sent) = $recd * 100 / ($recd + $sent) ;

関数のマクロを呼び出すには、次の構文を使用します。

@MACRO_NAME([MACRO_ARG[, MACRO_ARG]])

引数のない関数マクロを呼び出す場合、その呼び出しをテーブル オペレーション マクロの呼び出しと区別するように、空のかっこを指定する必要があります。

次の例は、比率計算用のマクロを使用した、前のクエリを示しています。

def recd_percent(recd, sent) = $recd * 100 / ($recd + $sent) ;

{
  fetch k8s_pod :: kubernetes.io/pod/network/received_bytes_count ;
  fetch k8s_pod :: kubernetes.io/pod/network/sent_bytes_count
}
| join
| value [received_percent: @recd_percent(val(0), val(1))]

マクロの機能

MQL マクロは構文要素であり、C プリプロセッサで使用されるマクロなどのテキスト要素とは異なります。この区別は、MQL マクロの本文は常に構文的に有効な式でなければならないことを意味します。これは意味的に有効ではない場合があり、マクロ引数とマクロが展開される場所によっても異なります。

MQL マクロは構文であるため、拡張できる式の種類はほとんどありません。構文マクロは、抽象構文ツリーを操作するもう 1 つの方法です。以下の例では、構文マクロを使用してできることのいくつかを示します。

# Abbreviating a column name.
def my_col() = instance_name;

# Map-valued macro.
def my_map(c) = [$c, @my_col()];

# Abbreviating a string.
def my_zone() = 'us-central.*';

# Abbreviating a filter expression.
def my_filter(f) = zone =~ @my_zone() && $f;

MQL では、暗黙的な文字列リテラルの連結もサポートされます。この機能は、長い指標名を含むクエリを作成する場合に非常に有用です。文字列リテラルとマクロ引数(これらは文字列リテラルでなければならない)がマクロ本文内で互いに隣接する場合は、マクロ展開によって 1 つの文字列リテラルに連結されます。

次の例では、gce_instanceBARE_NAME 字句要素です。これは文字列リテラルに自動的に昇格されるため、テーブル名を構築する場合に便利です。

# Builds a table name in domain 'd' with the suffix 'm'.
def my_table(d, m) = gce_instance::$d '/instance/' $m;

# Table name under the given domain.
def my_compute_table(m) = @my_table('compute.googleapis.com', $m);

これをすべて 1 つにまとめると、次のクエリは以前に定義したマクロをすべて使用します。

fetch @my_compute_table('cpu/utilization')
| filter @my_filter(instance_name =~ 'gke.*')
| group_by @my_map(zone)

構文が正しいものであれば、マクロ引数を任意の式にすることもできます。たとえば、マクロ my_filter は、最初の引数として instance_name =~ 'gke.*' のようなブール式を取ることができます。

次のクエリが示すように、テーブル オペレーションの短縮も同様に便利です。

# Calculate the ratio between compute metrics 'm1' and 'm2'.
def my_compute_ratio m1, m2 =
  { fetch @my_compute_table($m1); fetch @my_compute_table($m2) }
  | join | div;

# Use the table op macro to calculate the ratio between CPU utilization and
# the number of reserved cores per zone.
@my_compute_ratio 'cpu/utilization', 'cpu/reserved_cores' | group_by [zone]

最後に、関数マクロは通常の関数と同じように動作します。つまり、入力テーブルの値列がマクロの最初の引数になる関数の昇格が可能になります。次の例は、関数マクロを使用する前述のクエリのバリアントを示しています。

# Simple arithmetic macro.
def my_add_two(x) = $x + 2;

# Similar to previous query, but now using the new arithmetic macro with
# function argument promotion.
fetch @my_compute_table('cpu/utilization')
| filter @my_filter(instance_name =~ 'gke.*')
| group_by @my_map(zone), [.sum.@my_add_two]

制限事項

MQL のマクロ機能は、以下をサポートしていません。

  • マクロ定義のネスト。別のマクロの本文にマクロを定義することはできません。
  • 再帰的に定義されたマクロ。マクロの本文は、まだ完全に定義されていないマクロ自体を含め、マクロを参照できません。
  • マクロ定義関数をテーブル オペレーションとして使用する。
  • マクロ引数を関数またはテーブル オペレーションの名前として使用する。
  • クエリが厳密な形式に変換されるときのマクロの保持。マクロの呼び出しは、対応する式に置き換えられ、マクロの定義は削除されます。