Cloud Loggingのクエリ言語の構文を徹底解説

記事タイトルとURLをコピーする

G-gen の杉村です。Google Cloud のログ収集、保管、閲覧サービスである Cloud Logging のクエリ言語を徹底解説します。

クエリ言語

Logging クエリ言語とは

Google Cloud のログ収集、保管、閲覧サービスである Cloud Logging は、Google Cloud コンソールのログエクスプローラ画面で、Logging クエリ言語(Logging query language)という独自のクエリ言語を使ってログを自在にフィルタし、閲覧することができます。Logging クエリ言語は、ログエクスプローラのほか、gcloud コマンドや Cloud Logging API へのリクエストにも使うことができます。

Logging クエリ言語の構文(文法)は以下のドキュメントに記載されています。当記事では、重要な構文の書き方を解説します。

クエリ言語のその他の用途

Cloud Logging ではログルーター(シンク)を用いて、ログを任意のログバケットや BigQuery に転送、保管できます。ログルーターには、転送対象のログを指定するための含有フィルタや除外フィルタを記述します。

このフィルタの記述にも、Logging のクエリ言語が使われます。

また、Cloud Logging のログに基づいてメールなどを発報するためのログベースのアラートやログベースの指標などにおいても、対象のログを指定するために Logging クエリ言語が使われます。

このように、Logging クエリ言語は Cloud Logging に関わる多くの場面で使われます。

基本的な使い方

クエリの仕方

Logging クエリ言語は、Google Cloud コンソールの「ロギング」 > 「ログ エクスプローラ」の画面で使用します。

もしクエリを書き込む検索ボックスが表示されていない場合は、「クエリを表示(①)」を押下します。検索ボックス(②)にクエリを記載し、「クエリを実行(③)」を押下することで、検索が実行されます。

クエリ言語の使い方

例文

Logging クエリ言語を使ったクエリの例文を、いくつか紹介します。

Google Kubernetes Engine(GKE)クラスタのログで、重要度が ERROR のログ

resource.type="k8s_cluster"
AND severity="ERROR"

インスタンススケジュールによる Compute Engine VM の起動・停止ログ

(
 protoPayload.methodName="v1.compute.instances.stop"
 OR protoPayload.methodName="v1.compute.instances.start"
)
AND protoPayload.authenticationInfo.principalEmail="service-1234567890@compute-system.iam.gserviceaccount.com"

アカウント john.doe@g-gen.co.jp によって実行された BigQuery テーブル my_table へのクエリのログ

protoPayload.authenticationInfo.principalEmail="john.doe@g-gen.co.jp"
AND protoPayload.methodName="jobservice.insert"
AND protoPayload.serviceData.jobInsertResponse.resource.jobStatistics.referencedTables.tableId="my_table"

ログエクスプローラでの生成

Logging クエリ言語には、当記事で紹介するような多数の構文がありますが、ほとんど覚える必要がないともいえます。

ログエクスプローラで、検索したいログと類似のログを見つけたあと、対象のフィールドの値(①)をクリックして表示されたプルダウンメニューから「一致エントリを表示」または「一致エントリを非表示」を選択(②)すると、その値を検索するようなクエリが検索ボックス(③)に追加されます。

クエリ言語はコンソールで生成できる

このようにして追加されたクエリ言語を、部分的に修正して、目当てのログを探すためのクエリを作成することができます。

Logging クエリ言語の文法を詳細に覚えなくても、基本的な文法と概要を理解していれば、類似のログから検索クエリを生成して、目当てのログへたどり着くことができます。

ブール演算子

AND、OR

ANDOR は、Logging クエリ言語を使う上で最も重要な演算子です。ANDOR は、必ず大文字で書く必要があります。小文字で書くと、検索キーワードとして解釈され、後述のグローバル制限(グローバル検索)が行われてしまいます。

 protoPayload.methodName="v1.compute.instances.stop"
 OR protoPayload.methodName="v1.compute.instances.start"

上記のクエリでは、メソッド名が "v1.compute.instances.stop" または "v1.compute.instances.start" であるログを抽出しています。上記のようなクエリで、AND を使うことはありえません。メソッド名が "v1.compute.instances.stop" であり、かつ "v1.compute.instances.start" であるログはありえないからです。OR を使うことで、"v1.compute.instances.stop" または "v1.compute.instances.start" に当てはまるログがすべて抽出されます。

なお、AND は省略することができます。2つの以上のステートメント(個々のクエリの記述のこと)を記載したとき、結合方法は AND になります。以下の2つのクエリは、同じ意味を持ちます。

protoPayload.methodName="v1.compute.instances.stop"
AND resource.labels.instance_id="1234567890123456789"
protoPayload.methodName="v1.compute.instances.stop"
resource.labels.instance_id="1234567890123456789"

括弧

ORAND は括弧でくくることができます。以下のクエリでは、メソッド名が "v1.compute.instances.stop" であり、かつインスタンス ID が "1234567890123456789" または "0987654321098765432" であるログが抽出されます。

protoPayload.methodName="v1.compute.instances.stop"
AND (
  resource.labels.instance_id="1234567890123456789"
  OR resource.labels.instance_id="0987654321098765432"
)

NOT

NOT は、ANDOR の意味を反転します。以下のクエリでは、メソッド名が "v1.compute.instances.stop" であり、かつインスタンス ID が "1234567890123456789" ではないログが抽出されます。 NOT も、必ず大文字で書く必要があります。

protoPayload.methodName="v1.compute.instances.stop"
AND NOT resource.labels.instance_id="1234567890123456789"

また、NOT の代わりに -(マイナス記号)を使うこともできます。以下のクエリは、上記のクエリと同じ意味です。

protoPayload.methodName="v1.compute.instances.stop"
-resource.labels.instance_id="1234567890123456789"

比較演算子

=、!=(equal、not equal)

=!= はその見た目のとおり、一致していること、または一致していないことを指します。

以下の2つのクエリは同じ意味を持ちます。

protoPayload.methodName="v1.compute.instances.stop"
AND NOT resource.labels.instance_id="1234567890123456789"
protoPayload.methodName="v1.compute.instances.stop"
AND resource.labels.instance_id!="1234567890123456789"

=!= の前後には、スペースを入れても入れなくても構いません。

protoPayload.methodName = "v1.compute.instances.stop"
AND resource.labels.instance_id != "1234567890123456789"

:(has)

: は has と呼ばれ、指定した文字列を含むログを抽出します。

以下のログでは、protoPayload.authenticationInfo.principalEmail に "@g-gen.co.jp" という文字列が含まれているログを抽出します。

protoPayload.authenticationInfo.principalEmail : "@g-gen.co.jp"
AND protoPayload.methodName="jobservice.insert"

また、: では括弧を使って複数の条件を指定することができます。

protoPayload.authenticationInfo.principalEmail : ("@g-gen.co.jp" OR "@example.co.jp") 
AND protoPayload.methodName="jobservice.insert"

また、: を使ったクエリでは、大文字と小文字は区別されません。以下のクエリは、1つ前のクエリと同じ結果を返します。

protoPayload.authenticationInfo.principalEmail : ("@G-GEN.CO.JP" OR "@EXAMPLE.CO.JP") 
AND protoPayload.methodName="jobservice.insert"

フィールドの存在確認

:* を使うと、値を問わず、そのフィールドが存在しているログエントリを抽出できます。

protoPayload.serviceName="iap.googleapis.com"
protoPayload.authenticationInfo.principalEmail:*

正規表現

=~、!~(正規表現)

=~ は、正規表現を使うための比較演算子です。Logging クエリ言語では、RE2 と呼ばれる Google が定義する正規表現構文を使います。

以下のクエリでは、メソッド名が "v1.compute.instances." で始まるログを抽出します。

protoPayload.methodName=~"^v1\.compute\.instances\..+"

^ は文字列の先頭を意味します。. はそのままだと任意の文字列を意味するメタ文字なので、\ でエスケープします。末尾の .+ は、任意の文字列が1文字以上繰り返されることを意味します。

!~ は、=~ とは逆に、正規表現に一致しないログを抽出します。

resource.labels.instance_id = "1234567890123456789"
AND protoPayload.methodName !~ "v1.compute.instances.get"

なお、正規表現では大文字と小文字は区別されます。以下の2つのクエリでは、結果が異なります。

protoPayload.methodName=~"^v1\.compute\.instances\..+"
protoPayload.methodName=~"^V1\.COMPUTE\.INSTANCES\..+"

正規表現の記述

正規表現はプログラマーにとっては使い慣れたツールですが、正規表現の文法に慣れていない人もいるでしょう。日本語で指示して Gemini アプリ(https://gemini.google.com)などの生成 AI に正規表現を記述させるのも有用です。

ただし、無償版 Google アカウントで利用する Gemini アプリに投入したプロンプトなどは、Google によってモデルの再トレーニングに利用される場合があることに注意してください。Google Workspace アカウントでログインした状態で Gemini アプリを使っている場合、データは保護されます(エンタープライズグレードのデータ保護)。

検索のスピード

以下の2つのクエリの意味はほとんど同じですが、: を使ったクエリよりも、=~ を使った正規表現によるクエリのほうが高速です。

protoPayload.authenticationInfo.principalEmail : "@g-gen.co.jp" 
protoPayload.authenticationInfo.principalEmail =~ ".+@g-gen\.co\.jp"

文字列の検索

グローバル制限(単純な検索)

以下のように単純に文字列をダブルクォーテーションで囲って検索ボックスに入力し、クエリすることで、その文字列を含むログを抽出できます。

"password authentication failed"

このような文字列による単純な検索を、グローバル制限(global restriction)またはグローバル検索といいます。グローバル制限は、以下のように ANDOR を使うことができます。

( "password authentication failed" AND ( "postgres" OR "mysql" ) )

グローバル制限による検索では、暗黙的に :(has)が使われています。グローバル制限による検索では、ログエントリのすべてのフィールドを : で検索するため、結果が返ってくるのが遅くなる可能性があります。

SEARCH 関数

前述のグローバル制限による単純な文字列検索では、結果が返ってくるまで時間がかかる場合があります。Logging クエリ言語の組み込み関数である SEARCH() 関数を使うと、検索対象のフィールドを指定できます。

SEARCH(textPayload, "password authentication failed")

SEARCH() 関数は、フィールドを指定しないで検索に使うこともできます。このとき、前述の単純な検索との違いは、検索時に文字列が「トークン化」されることです。

例えば、大文字と小文字が区別されなかったり、スペースで空けた複数の文字列は順序が区別されません。以下の2つのクエリは同じ結果を返します。

SEARCH("hello world")
SEARCH("World hello")

大文字と小文字や、文字列の順序を区別させたい場合は、文字列をバッククォートで囲みます。以下の2つのクエリは、返ってくる結果が異なります。

SEARCH("`hello world`")
SEARCH("`world hello`")

SEARCH() 関数では、部分的なテキストは区別されてしまいます。以下のクエリでは、world という単語が途中で切れているので、hello world という文字列は抽出されません。

SEARCH("`hello wor`")

なお、以下の1つ目のクエリのように文字列をダブルクォーテーションで囲わずに検索ボックスに入力してそのまま検索すると、SEARCH() 関数を使った検索になります。以下の2つのクエリは同じ意味です。

password authentication failed
SEARCH("password authentication failed")

時間の指定

ログエクスプローラでの指定

ログエクスプローラでは、ログの検索対象とする時間を指定できます。

できるだけ検索対象の時間帯を絞ることで、クエリの結果が返ってくるまでのスピードを向上させることができます。

ログエクスプローラで時間帯を指定

クエリ言語での指定

クエリ内で時間帯を指定することもできます。Cloud Logging のログエントリには以下のように timestamp フィールドが必ず含まれていますので、このフィールドを使ってログを絞り込みます。

timestamp >= "2025-02-24T09:40:00+09:00"
AND timestamp <= "2025-02-24T09:50:00+09:00"

タイムスタンプの末尾を +09:00 とすれば日本のタイムゾーンになります。末尾を Z とすれば UTC です。

コメント

-- で始まる行はコメントであり、無視されます。

-- このクエリは、Compute Engine VM に対するすべてのメソッドの実行を抽出します
protoPayload.methodName=~"^v1\.compute\.instances\..+"

高速な検索

インデックスの利用

Cloud Logging のログエントリには、インデックスが存在します。インデックスは、物理的な書籍でいう索引や、ページに貼られた付箋のようなものと理解することができます。フィールドにインデックスが作成されることによって、そのフィールドに対する検索が高速化します。

ログバケットに対して、ユーザーが任意のフィールドにカスタムインデックスを指定することもできるほか、すべてのログバケットで、デフォルトで以下のフィールドにインデックスが作成されています。

  • resource.type
  • resource.labels.*
  • logName
  • severity
  • timestamp
  • insertId
  • operation.id
  • trace
  • httpRequest.status
  • labels.*
  • split.uid

これらのフィールドに対して検索をかけると、高速な検索が可能です。

例えば、検索したいログの対象となっているインスタンス ID が分かっている場合は、ID を指定することで検索が高速になります。resource.labels.* にはデフォルトのインデックスが作成されているからです。

protoPayload.methodName="v1.compute.instances.stop"
AND resource.labels.instance_id="1234567890123456789"

また、logName フィールドは、ログエントリに必ず含まれており、デフォルトのインデックスが作成されていますので、検索対象のログを絞る際に有用です。

protoPayload.serviceName="cloudsql.googleapis.com"
AND logName="projects/sugimura/logs/cloudaudit.googleapis.com%2Factivity"

logName フィールドの値の例は、以下のとおりです。

ログの種類 説明
Cloud Audit Logs 管理アクティビティ監査ログ projects/(PROJECT_ID)/logs/cloudaudit.googleapis.com%2Factivity リソースに対する更新系操作
Cloud Audit Logs データアクセス監査ログ projects/(PROJECT_ID)/logs/cloudaudit.googleapis.com%2Fdata_access データに対する更新系・読取系操作
Cloud Audit Logs ポリシー拒否監査ログ projects/(PROJECT_ID)/logs/cloudaudit.googleapis.com%2Fpolicy VPC Service Controls のアクセス拒否
Cloud SQL for PostgreSQL データベースログ (postgres.log) projects/(PROJECT_ID)/logs/cloudsql.googleapis.com%2Fpostgres.log Cloud SQL for PostgreSQL のログ
Cloud Run 標準出力 (postgres.log) projects/(PROJECT_ID)/logs/run.googleapis.com%2Fstdout Cloud Run や Cloud Run functions の標準出力

時間帯を絞る

ログ検索対象の時間帯を可能な限り絞ることで、検索時間を速くすることができます。

ログエクスプローラ画面の UI を使って時間帯を絞ってもいいですし、クエリ文の中で timestamp フィールドを使って時間帯を絞っても構いません。

部分一致よりもイコール

検索対象の文字列が分かっている場合は、グローバル制限(グローバル検索)よりも :(has)のほうが、またそれよりも =~(正規表現)の方が高速です。しかし、最も高速なのは =(イコール)です。

-- グローバル検索だとすべてのフィールドが検索対象になる
"password authentication failed"
-- こちらのほうが高速
textPayload : "password authentication failed for user \"postgres\""
-- さらに高速
textPayload =~ ".* password authentication failed for user \"postgres\".*"
-- 最も高速
textPayload="2025-02-24 00:27:33.651 UTC [12345]: [1-1] db=postgres,user=postgres FATAL:  password authentication failed for user \"postgres\""

また、フィールドを指定した検索では SEARCH() 関数も有用です。正規表現を用いなくても、検索文字列がトークン化されて効率的な検索が可能です。ただし、単語が途中で切れていたりすると、望む結果が得られないことに注意してください(前述の「SEARCH 関数」の見出しを参照)。

SEARCH(textPayload, "password authentication failed")

杉村 勇馬 (記事一覧)

執行役員 CTO

元警察官という経歴を持つ IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 認定資格および Google Cloud 認定資格はすべて取得。X(旧 Twitter)では Google Cloud や Google Workspace のアップデート情報をつぶやいています。