このドキュメントでは、ログ分析を使用するようにアップグレードされたログバケットに保存されているログエントリに対するサンプルクエリについて説明します。これらのバケットでは、 Google Cloud コンソールの [ログ分析] ページから SQL クエリを実行できます。その他のサンプルについては、logging-analytics-samples
と security-analytics
の GitHub リポジトリをご覧ください。
このドキュメントでは、SQL やログエントリのルーティングと保存の方法については説明しません。これらのトピックについては、次のステップをご覧ください。
このページの例では、ログビューに対してクエリを実行します。アナリティクス ビューをクエリするには、次のパス形式を使用します。
`analytics_view.PROJECT_ID.LOCATION.ANALYTICS_VIEW_ID`
。前の式で、PROJECT_ID
はプロジェクトの ID、LOCATION
と ANALYTICS_VIEW_ID
は分析ビューのロケーションと名前です。
SQL 言語のサポート
[ログ分析] ページで使用されるクエリは、一部の例外を除き、GoogleSQL 関数をサポートしています。
[ログ分析] ページを使用して発行された SQL クエリでは、次の SQL コマンドはサポートされていません。
- DDL コマンドと DML コマンド
- JavaScript ユーザー定義関数
- BigQuery ML 関数
- SQL 変数
以下は、[BigQuery Studio] ページ、[Looker Studio] ページ、または bq コマンドライン ツールを使用してリンク済みデータセットをクエリする場合にのみサポートされます。
- JavaScript ユーザー定義関数
- BigQuery ML 関数
- SQL 変数
ベスト プラクティス
クエリの期間を設定するには、期間セレクタを使用することをおすすめします。たとえば、過去 1 週間のデータを表示するには、期間セレクタで [過去 7 日間] を選択します。また、期間セレクタを使用して、開始時刻と終了時刻の指定、表示時間の指定、タイムゾーンの変更を行うこともできます。
WHERE
句に timestamp
フィールドを含めると、期間セレクタの設定は使用されません。次の例は、タイムスタンプでフィルタする方法を示しています。
-- Matches log entries whose timestamp is within the most recent 1 hour.
WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)
時間でフィルタする方法の詳細については、時間関数とタイムスタンプ関数をご覧ください。
始める前に
このセクションでは、ログ分析を使用する前に完了しておく必要のある手順について説明します。
ログバケットを構成する
ログ分析を使用できるようにログバケットがアップグレードされていることを確認します。
-
Google Cloud コンソールで、[ログストレージ] ページに移動します。
このページを検索バーで検索する場合は、小見出しが「Logging」の結果を選択します。
- クエリを実行するログビューを含む各ログバケットで、[Log Analytics を使用可能] 列に [開く] が表示されていることを確認します。[アップグレード] が表示されている場合は、[アップグレード] をクリックしてダイアログを完了します。
IAM のロールと権限を構成する
このセクションでは、ログ分析の使用に必要な IAM ロールまたは権限について説明します。
-
ログ分析の使用とログビューへのクエリ実行に必要な権限を取得するには、プロジェクトに対する次の IAM ロールを付与するよう管理者に依頼してください。
_Required
および_Default
のログバケットに対してクエリを実行する: ログ閲覧者(roles/logging.viewer
)- プロジェクトのすべてのログビューに対してクエリを実行する: ログ表示アクセス者(
roles/logging.viewAccessor
)
プリンシパルを特定のログビューに制限するには、プロジェクト レベルで付与されたログ表示アクセス者ロールに IAM 条件を追加するか、ログビューのポリシー ファイルに IAM バインディングを追加します。詳細については、ログビューへのアクセスを制御するをご覧ください。
これらの権限は、[ログ エクスプローラ] ページでログエントリを表示するために必要な権限と同じです。ユーザー定義バケットでのビューに対するクエリ実行、または
_Default
ログバケットの_AllLogs
ビューに対するクエリ実行に必要な追加ロールについて詳しくは、Cloud Logging のロールをご覧ください。 -
分析ビューへのクエリ実行に必要な権限を取得するには、プロジェクトに対する Observability Analytics ユーザー(
roles/observability.analyticsUser
)IAM ロールを付与するよう管理者に依頼してください。
このページのクエリの使用方法
-
Google Cloud コンソールで、[ログ分析] ページに移動します。
検索バーを使用してこのページを検索する場合は、小見出しが [Logging] の結果を選択します。
[クエリ] ペインで、[code SQL] をクリックし、クエリをコピーして SQL クエリ ペインに貼り付けます。
クエリをコピーする前に、
FROM
句で次のフィールドを置き換えます。- PROJECT_ID: プロジェクトの ID。
- LOCATION: ログビューまたは分析ビューのロケーション。
- BUCKET_ID: ログバケットの名前または ID。
- LOG_VIEW_ID: ログビューの ID。100 文字に制限され、英字、数字、アンダースコア、ハイフンのみを使用できます。
次に、ログビューの
FROM
句の形式を示します。FROM `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
このページのログサンプルは、ログビューをクエリします。アナリティクス ビューをクエリするには、次のパス形式を使用します。
`analytics_view.PROJECT_ID.LOCATION.ANALYTICS_VIEW_ID`
前の式で、PROJECT_ID
はプロジェクトの ID、LOCATION
とANALYTICS_VIEW_ID
は分析ビューのロケーションと名前です。
このドキュメントに示すクエリを [BigQuery Studio] ページで使用する場合や、bq コマンドライン ツールを使用する場合は、FROM
句を編集して、リンクされたデータセットへのパスを入力します。たとえば、プロジェクト myproject
にある mydataset
という名前のリンクされたデータセットで _AllLogs
ビューをクエリする場合、パスは myproject.mydataset._AllLogs
です。
一般的なユースケース
このセクションでは、カスタムクエリの作成に役立つ一般的なユースケースをいくつか紹介します。
デフォルトのログバケットにログエントリを表示する
_Default
バケットに対してクエリを実行するには、次のクエリを実行します。
SELECT
timestamp, severity, resource.type, log_name, text_payload, proto_payload, json_payload
FROM
`PROJECT_ID.LOCATION._Default._AllLogs`
-- Limit to 1000 entries
LIMIT 1000
正規表現でフィールド値を抽出する
正規表現を使用して文字列から値を抽出するには、関数 REGEXP_EXTRACT
を使用します。
SELECT
-- Display the timestamp, and the part of the name that begins with test.
timestamp, REGEXP_EXTRACT(JSON_VALUE(json_payload.jobName), r".*(test.*)$") AS name,
FROM
`PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
-- Get the value of jobName, which is a subfield in a JSON structure.
JSON_VALUE(json_payload.jobName) IS NOT NULL
ORDER BY timestamp DESC
LIMIT 20
詳細については、REGEXP_EXTRACT
のドキュメントをご覧ください。
前のクエリのような部分文字列の一致の場合、CONTAINS_SUBSTR
関数を使用すると、クエリの効率が向上します。
ログエントリのフィルタリング
クエリにフィルタを適用するには、WHERE
句を追加します。この句で使用する構文は、フィールドのデータ型によって異なります。このセクションでは、さまざまなデータ型の例をいくつか示します。
ログエントリをペイロード タイプでフィルタする
ログエントリには、3 種類のペイロード タイプのいずれかを含めることができます。ペイロード タイプでログエントリをフィルタするには、次のいずれかの句を使用します。
テキスト ペイロード
-- Matches log entries that have a text payload. WHERE text_payload IS NOT NULL
JSON ペイロード
-- Matches log entries that have a JSON payload. WHERE json_payload IS NOT NULL
proto ペイロード
-- Matches log entries that have a proto payload. -- Because proto_payload has a data type of RECORD, this statement tests -- whether a mandatory subfield exits. WHERE proto_payload.type IS NOT NULL
クエリ結果では、json_payload
フィールドと proto_payload
フィールドの両方が JSON でレンダリングされ、ナビゲートできます。
タイムスタンプでログデータをフィルタする
タイムスタンプでログエントリをフィルタリングするには、期間セレクタを使用することをおすすめします。ただし、WHERE
句で timestamp
を指定することもできます。
-- Matches log entries whose timestamp is within the most recent hour
WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)
時間でフィルタする方法の詳細については、時間関数とタイムスタンプ関数をご覧ください。
リソースでフィルタする
ログデータをリソースでフィルタするには、WHERE
句に resource.type
ステートメントを追加します。
-- Matches log entries whose resource type is gce_instance
WHERE resource.type = "gce_instance"
重大度でフィルタする
重大度でログデータをフィルタするには、WHERE
句に severity
ステートメントを追加します。
-- Matches log entries whose severity is INFO or ERROR
WHERE severity IS NOT NULL AND severity IN ('INFO', 'ERROR')
ログエントリは、整数である severity_number
でフィルタすることもできます。たとえば、次の句は、重大度が NOTICE
以上のすべてのログエントリに一致します。
-- Matches log entries whose severity level is at least NOTICE
WHERE severity_number IS NOT NULL AND severity_number > 200
列挙される値の詳細については、LogSeverity
をご覧ください。
ログ名でフィルタする
ログ名でログデータをフィルタするには、WHERE
句に log_name
ステートメントまたは log_id
ステートメントを追加します。
ログ名でリソースパスを指定します。
-- Matches log entries that have the following log ID. WHERE log_name="projects/cloud-logs-test-project/logs/cloudaudit.googleapis.com%2Factivity"
ログ ID にはリソースパスが含まれていません。
-- Matches log entries that have the following log id. WHERE log_id = "cloudaudit.googleapis.com/data_access"
ログエントリをリソースラベルでフィルタする
リソースラベルは JSON 構造として保存されます。JSON 構造内のフィールドの値でフィルタするには、関数 JSON_VALUE
を使用します。
SELECT
timestamp, JSON_VALUE(resource.labels.zone) AS zone, json_payload, resource, labels
FROM
`PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
-- Matches log entries whose resource type is gce_instance and whose zone is
-- us-central1-f. Because resource has data type JSON, you must use JSON_VALUE
-- to get the value for subfields, like zone.
resource.type = "gce_instance" AND
JSON_VALUE(resource.labels.zone) = "us-central1-f"
ORDER BY timestamp ASC
上記のクエリは、ログエントリに保存されているリソースラベルの形式に依存しています。リソース フィールドの例を次に示します。
{
type: "gce_instance"
labels: {
instance_id: "1234512345123451"
project_id: "my-project"
zone: "us-central1-f"
}
}
JSON データを取得して変換できるすべての関数の詳細については、JSON 関数をご覧ください。
HTTP リクエストでフィルタする
HTTP リクエスト フィールドを含むログエントリのみをクエリするには、次の句を使用します。
-- Matches log entries that have a HTTP request_method field.
-- Don't compare http_request to NULL. This field has a data type of RECORD.
WHERE http_request.request_method IS NOT NULL
また、IN
ステートメントを使用することもできます。
-- Matches log entries whose HTTP request_method is GET or POST.
WHERE http_request.request_method IN ('GET', 'POST')
HTTP ステータスでフィルタする
HTTP ステータスを含むログエントリのみをクエリするには、次の句を使用します。
-- Matches log entries that have an http_request.status field.
WHERE http_request.status IS NOT NULL
JSON データ型のフィールドでフィルタする
JSON データ型のフィールドのサブフィールドに特定の値がある場合にのみログエントリをクエリするには、関数 JSON_VALUE
を使用して値を抽出します。
-- Compare the value of the status field to NULL.
WHERE JSON_VALUE(json_payload.status) IS NOT NULL
上記の句は、次の句と微妙に異なります。
-- Compare the status field to NULL.
WHERE json_payload.status IS NOT NULL
最初の句は、ステータス フィールドの値が NULL
かどうかをテストします。2 番目の句は、ステータス フィールドが存在するかどうかをテストします。ログビューに 2 つのログエントリが含まれているとします。1 つのログエントリの場合、json_payload
フィールドの形式は次のとおりです。
{
status: {
measureTime: "1661517845"
}
}
他のログエントリでは、json_payload
フィールドの構造が異なります。
{
@type: "type.googleapis.com/google.cloud.scheduler.logging.AttemptFinished"
jobName: "projects/my-project/locations/us-central1/jobs/test1"
relativeUrl: "/food=cake"
status: "NOT_FOUND"
targetType: "APP_ENGINE_HTTP"
}
WHERE json_payload.status IS NOT NULL
句は両方のログエントリと一致します。ただし、WHERE JSON_VALUE(json_payload.status) IS NOT NULL
句は 2 番目のログエントリにのみ一致します。
ログエントリをグループ化して集計する
このセクションは、前述のサンプルに基づき、ログエントリをグループ化して集計する方法について説明します。グループ化を指定せずに集計を指定する場合は、SQL が WHERE
句を満たすすべての行を 1 つのグループとして扱うため、1 つの結果が出力されます。
すべての SELECT
式は、グループ フィールドに含めるか、集計する必要があります。
ログエントリをタイムスタンプでグループ化する
タイムスタンプでデータをグループ化するには、関数 TIMESTAMP_TRUNC
を使用します。この関数は、HOUR
のような指定した粒度までタイムスタンプを切り詰めます。
SELECT
-- Truncate the timestamp by hour.
TIMESTAMP_TRUNC(timestamp, HOUR) AS hour,
JSON_VALUE(json_payload.status) AS status,
-- Count the number log entries in each group.
COUNT(*) AS count
FROM
`PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
-- Matches log entries that have a status field whose value isn't NULL.
json_payload IS NOT NULL AND JSON_VALUE(json_payload.status) IS NOT NULL
GROUP BY
-- Group by hour and status
hour,status
ORDER BY hour ASC
詳細については、TIMESTAMP_TRUNC
のドキュメントと日時関数をご覧ください。
ログエントリをリソース別にグループ化する
次のクエリは、ログエントリをリソースタイプでグループ化し、各グループのログエントリ数をカウントする方法を示しています。
SELECT
-- Count the number of log entries for each resource type
resource.type, COUNT(*) AS count
FROM
`PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
GROUP BY resource.type
LIMIT 100
ログエントリを重大度でグループ化する
次のクエリは、ログエントリを重大度でグループ化し、各グループのログエントリ数をカウントする方法を示しています。
SELECT
-- Count the number of log entries for each severity.
severity, COUNT(*) AS count
FROM
`PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
severity IS NOT NULL
GROUP BY severity
ORDER BY severity
LIMIT 100
ログエントリを log_id
でグループ化する
次のクエリは、ログエントリをログ ID でグループ化し、各グループのログエントリ数をカウントする方法を示しています。
SELECT
-- Count the number of log entries for each log ID.
log_id, COUNT(*) AS count
FROM
`PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
GROUP BY log_id
ORDER BY count DESC
LIMIT 100
URL ごとの HTTP リクエストの平均レイテンシを計算する
次のクエリは、ログエントリを HTTP リクエスト URL とロケーションでグループ化し、各グループのログエントリ数をカウントする方法を示しています。
SELECT
-- Compute the average latency for each group. Because the labels field has a
-- data type of JSON, use JSON_VALUE to get the value of checker_location.
JSON_VALUE(labels.checker_location) AS location,
AVG(http_request.latency.seconds) AS secs, http_request.request_url
FROM
`PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
-- Matches log entries when the request_method field is GET.
http_request IS NOT NULL AND http_request.request_method IN ('GET')
GROUP BY
-- Group by request URL and location
http_request.request_url, location
ORDER BY location
LIMIT 100
サブネットワーク テストの平均送信バイト数を計算する
次のクエリは、リソースラベルで指定されたロケーションでログエントリをグループ化し、各グループのログエントリ数を計算する方法を示しています。
SELECT
-- Compute the average number of bytes sent per location. Because labels has
-- a data type of JSON, use JSON_VALUE to get the value of the location field.
-- bytes_sent is a string. Must cast to a FLOAT64 before computing average.
JSON_VALUE(resource.labels.location) AS location,
AVG(CAST(JSON_VALUE(json_payload.bytes_sent) AS FLOAT64)) AS bytes
FROM
`PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
resource.type = "gce_subnetwork" AND json_payload IS NOT NULL
GROUP BY
-- Group by location
location
LIMIT 100
パターンに一致するフィールドがあるログエントリをカウントする
正規表現と一致する部分文字列を返すには、関数 REGEXP_EXTRACT
を使用します。
SELECT
-- Extract the value that begins with test.
-- Count the number of log entries for each name.
REGEXP_EXTRACT(JSON_VALUE(json_payload.jobName), r".*(test.*)$") AS name,
COUNT(*) AS count
FROM
`PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
WHERE
json_payload.jobName IS NOT NULL
GROUP BY name
ORDER BY count
LIMIT 20
他の例については、REGEXP_EXTRACT
のドキュメントをご覧ください。
クロスカラム検索
このセクションでは、クエリを実行するビューの複数の列を検索するために使用できる 2 つの方法について説明します。
トークンベース検索: 検索場所と検索クエリを指定し、
SEARCH
関数を使用します。SEARCH
関数にはデータの検索方法に関する特定のルールがあるため、SEARCH
のドキュメントを一読することをおすすめします。部分文字列ベースの検索: 検索場所と文字列リテラルを指定し、
CONTAINS_SUBSTR
関数を使用します。システムは、大文字と小文字を区別しないテストを実行して、文字列リテラルが式に存在するかどうかを判断します。CONTAINS_SUBSTR
関数は、文字列リテラルが存在する場合はTRUE
を返し、それ以外の場合はFALSE
を返します。検索値はSTRING
リテラルである必要があり、リテラルNULL
ではありません。
ログビューでのトークンベースの検索
次のクエリは、「35.193.12.15」に完全に一致するフィールドを持つ行のみを保持します。
SELECT
timestamp, log_id, proto_payload, severity, resource.type, resource, labels
FROM
`PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID` AS t
WHERE
-- Search data access audit logs for the IP address that matches 35.193.12.15.
-- The use of backticks prevents the string from being tokenized.
proto_payload IS NOT NULL AND
log_id = "cloudaudit.googleapis.com/data_access" AND
SEARCH(t,"`35.193.12.15`")
ORDER BY timestamp ASC
LIMIT 20
クエリ文字列でバッククォートが省略されている場合、クエリ文字列は SEARCH
のドキュメントで定義されているルールに基づいて分割されます。たとえば、次のステートメントを実行すると、クエリ文字列は「35」、「193」、「12」、「15」の 4 つのトークンに分割されます。
SEARCH(t,"35.193.12.15")
上記の SEARCH
ステートメントでは、1 つのフィールドが 4 つのトークンすべてに一致する場合、行と一致します。トークンの順序は関係ありません。
クエリには、複数の SEARCH
ステートメントを含めることが可能です。たとえば、上記のクエリでは、ログ ID のフィルタを次のようなステートメントに置き換えることが可能です。
SEARCH(t,"`cloudaudit.googleapis.com/data_access`")
上記のステートメントはログビューのログエントリのすべてのフィールドを検索しますが、元のステートメントはログエントリの log_id
フィールドのみを検索します。
複数のフィールドに対して複数の検索を実行するには、個々の文字列をスペースで区切ります。たとえば、次のステートメントは、フィールドに「Hello World」、「happy」、「days」が含まれている行に一致します。
SEARCH(t,"`Hello World` happy days")
最後に、テーブル全体ではなく、特定のフィールドを検索することもできます。たとえば、次のステートメントは、text_payload
と json_payload
という名前の列のみを検索します。
SEARCH((text_payload, json_payload) ,"`35.222.132.245`")
SEARCH
関数のパラメータの処理方法については、BigQuery リファレンス ページの検索関数をご覧ください。
ログビューでの部分文字列検索
たとえば、次のクエリは、タイムスタンプが特定の時間範囲内にある特定の IP アドレスを持つすべてのデータアクセス監査ログエントリを取得します。最後に、クエリ結果を並べ替えて、古いものから 20 件の結果を表示します。
SELECT
timestamp, log_id, proto_payload, severity, resource.type, resource, labels
FROM
`PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID` AS t
WHERE
-- Search data access audit logs for the IP address that matches 35.193.12.15.
-- CONTAINS_SUBSTR performs a contains-test.
proto_payload IS NOT NULL AND
log_id = "cloudaudit.googleapis.com/data_access" AND
CONTAINS_SUBSTR(t,"35.193.12.15")
ORDER BY timestamp ASC
LIMIT 20
複数のビューをクエリする
クエリ ステートメントは、1 つ以上のテーブルまたは式をスキャンし、計算結果の行を返します。たとえば、クエリ ステートメントを使用して、さまざまなテーブルやデータセットの SELECT
ステートメントの結果をマージし、結合データから列を選択できます。
複数のビューをクエリする場合、これらのビューは同じロケーションに存在する必要があります。たとえば、2 つのビューが us-east1
ロケーションにある場合、1 つのクエリで両方のビューをクエリできます。us
マルチリージョンにある 2 つのビューをクエリすることもできます。ただし、ビューのロケーションが global
の場合、そのビューは任意の物理ロケーションに存在できます。したがって、ロケーションが global
の 2 つのビュー間の結合が失敗する可能性があります。
トレース ID で 2 つのログビューを結合する
2 つのテーブルの情報を組み合わせるには、いずれかの JOIN 演算子を使用します。
SELECT
-- Do an inner join on two tables by using the span ID and trace ID.
-- Don't join only by span ID, as this field isn't globally unique.
-- From the first view, show the timestamp, severity, and JSON payload.
-- From the second view, show the JSON payload.
a.timestamp, a.severity, a.json_payload, b.json_payload, a.span_id, a.trace
FROM `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_1` a
JOIN `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_2` b
ON
a.span_id = b.span_id AND
a.trace = b.trace
LIMIT 100
結合ステートメントを使用して 2 つのログビューをクエリする
2 つ以上の SELECT
ステートメントの結果を結合して重複行を破棄するには、UNION
演算子を使用します。重複した行を保持するには、UNION ALL
演算子を使用します。
SELECT
timestamp, log_name, severity, json_payload, resource, labels
-- Create a union of two log views
FROM(
SELECT * FROM `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_1`
UNION ALL
SELECT * FROM `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_2`
)
-- Sort the union by timestamp.
ORDER BY timestamp ASC
LIMIT 100
重複するログエントリを削除する
ログ分析では、クエリの実行前に重複するログエントリが削除されることはありません。これは、ログ エクスプローラを使用してログエントリをクエリする場合とは異なります。ログ エクスプローラでは、ログ名、タイムスタンプ、挿入 ID のフィールドを比較して重複エントリが削除されます。
行レベルの検証を使用して、重複するログエントリを削除できます。
詳細については、トラブルシューティング: ログ分析の結果に重複するログエントリがあるをご覧ください。
次のステップ
ログエントリを転送して保存する方法については、次のドキュメントをご覧ください。
SQL リファレンス ドキュメントについては、次のドキュメントをご覧ください。