示例 SQL 查询

本文档包含针对存储在已升级为使用 Log Analytics 的日志存储分区中的日志条目的示例查询。您可以从 Google Cloud 控制台的 Log Analytics 页面中对这些存储分区运行 SQL 查询。如需查看更多示例,请参阅 logging-analytics-samplessecurity-analytics GitHub 代码库。

本文档不介绍 SQL 以及如何路由和存储日志条目。如需了解这些主题,请参阅后续步骤部分。

准备工作

  • 如需在 Log Analytics 页面上使用本文档中显示的查询,请将 TABLE 替换为与您要查询的视图对应的表的名称。表名称的格式为 project_ID.region.bucket_ID.view_ID。您可以在 Log Analytics 页面上找到视图的表名称;日志视图的默认查询会在 FROM 语句中列出表名称。如需了解如何访问默认查询,请参阅查询日志视图

  • 如需使用本文档的 BigQuery Studio 页面中显示的查询,请将 TABLE 替换为链接数据集中表的路径。例如,如需查询项目 myproject 中关联数据集 mydataset 的视图 _AllLogs,请将此字段设置为 myproject.mydataset._AllLogs

    在 Google Cloud 控制台中,转到 BigQuery 页面:

    前往 BigQuery Studio

    您也可以使用搜索栏查找此页面。

  • 如需打开 Log Analytics 页面,请执行以下操作:

    1. 在 Google Cloud 控制台中,前往 Log Analytics 页面:

      转到 Log Analytics

      如果您使用搜索栏查找此页面,请选择子标题为 Logging 的结果。

    2. 可选:如需确定日志视图的表架构,请在日志视图列表中找到该视图,然后选择该视图的名称。

    此时会显示表的架构。您可以使用过滤条件字段找到特定字段。您无法修改架构。

过滤日志

SQL 查询确定要处理表中的哪些行,然后将行分组并执行聚合操作。如果未列出分组和聚合操作,则查询结果包含过滤操作选择的行。本部分中的示例对过滤进行了说明。

按时间过滤

如需设置查询的时间范围,我们建议您使用时间范围选择器。如果查询未在 WHERE 子句中指定 timestamp 字段,系统会自动使用此选择器。例如,如需查看过去一周的数据,请从时间范围选择器中选择过去 7 天。您还可以使用时间范围选择器指定开始时间和结束时间、指定查看时段以及更改时区。

如果您在 WHERE 子句中添加 timestamp 字段,则不使用时间范围选择器设置。以下示例使用 TIMESTAMP_SUB 函数过滤数据,该函数允许您指定从当前时间开始的回溯期:

WHERE
  timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)

如需详细了解如何按时间过滤,请参阅时间函数时间戳函数

按资源过滤

如需按资源过滤,请添加 resource.type 限制。

例如,以下查询会读取最近一个小时的数据,然后保留资源类型与 gce_instance 匹配的行,接着对条目进行排序和显示最多 100 个条目:

SELECT
  timestamp, log_name, severity, json_payload, resource, labels
FROM
  `TABLE`
WHERE
  resource.type = "gce_instance"
ORDER BY timestamp ASC
LIMIT 100

按严重程度过滤

您可以使用 severity = 'ERROR' 等限制按特定严重性级别进行过滤。另一种方法是使用 IN 语句并指定一组有效值。

例如,以下查询会读取最近一个小时的数据,然后仅保留包含 severity 字段(其值为 'INFO''ERROR')的行:

SELECT
  timestamp, log_name, severity, json_payload, resource, labels
FROM
  `TABLE`
WHERE
  severity IS NOT NULL AND
  severity IN ('INFO', 'ERROR')
ORDER BY timestamp ASC
LIMIT 100

上一个查询按 severity 字段的值进行过滤。但是,您也可以编写按日志严重性的数值进行过滤的查询。例如,如果您将 severity 行替换为以下几行,则查询会返回严重级别至少为 NOTICE 的所有日志条目:

  severity_number IS NOT NULL AND
  severity_number > 200

如需了解枚举值,请参阅 LogSeverity

按日志名称过滤

如需按日志名称进行过滤,您可以为 log_namelog_id 字段的值添加限制。log_name 字段包含资源路径。也就是说,此字段包含类似 projects/myproject/logs/mylog 的值。log_id 字段仅存储日志名称,例如 mylog

例如,以下查询会读取最近一个小时的数据,然后保留 log_id 字段中值为 cloudaudit.googleapis.com/data_access 的行,然后对结果进行排序并显示结果:

SELECT
  timestamp, log_id, severity, json_payload, resource, labels
FROM
  `TABLE`
WHERE
  log_id = "cloudaudit.googleapis.com/data_access"
ORDER BY timestamp ASC
LIMIT 100

按资源标签过滤

大多数受监控的资源描述符都会定义用于识别特定资源的标签。例如,Compute Engine 实例的描述符包括地区、项目 ID 和实例 ID 的标签。写入日志条目时,系统会为每个字段分配值。以下是一个示例:

{
   type: "gce_instance"
   labels: {
      instance_id: "1234512345123451"
      project_id: "my-project"
      zone: "us-central1-f"
   }
}

由于 labels 字段的数据类型是 JSON,因此在查询结果中包含 resource.labels.zone = "us-centra1-f" 等限制会导致语法错误。如需获取数据类型为 JSON 的字段的值,请使用函数 JSON_VALUE

例如,以下查询会读取最新的数据,然后保留资源为位于 us-central1-f 地区的 Compute Engine 实例的行:

SELECT
  timestamp, log_name, severity, JSON_VALUE(resource.labels.zone) AS zone, json_payload, resource, labels
FROM
  `TABLE`
WHERE
  resource.type = "gce_instance" AND
  JSON_VALUE(resource.labels.zone) = "us-central1-f"
ORDER BY timestamp ASC
LIMIT 100

如需了解可以检索和转换 JSON 数据的所有函数,请参阅 JSON 函数

按 HTTP 请求过滤

如需过滤表以仅包含与 HTTP 请求或回复对应的行,请添加 http_request IS NOT NULL 限制:

SELECT
  timestamp, log_name, severity, http_request, resource, labels
FROM
  `TABLE`
WHERE
  http_request IS NOT NULL
ORDER BY timestamp
LIMIT 100

以下查询仅包含与 GETPOST 请求对应的行:

SELECT
  timestamp, log_name, severity, http_request, resource, labels
FROM
  `TABLE`
WHERE
  http_request IS NOT NULL AND
  http_request.request_method IN ('GET', 'POST')
ORDER BY timestamp ASC
LIMIT 100

按 HTTP 状态过滤

如需按 HTTP 状态过滤,请修改 WHERE 子句以要求定义 http_request.status 字段:

SELECT
  timestamp, log_name, http_request.status, http_request, resource, labels
FROM
  `TABLE`
WHERE
  http_request IS NOT NULL AND
  http_request.status IS NOT NULL
ORDER BY timestamp ASC
LIMIT 100

如需确定字段中存储的数据类型,请查看架构或显示该字段。上一个查询的结果表明,http_request.status 字段存储的是整数值。

按 JSON 类型的字段过滤

如需从数据类型为 JSON 的列中提取值,请使用函数 JSON_VALUE

请考虑以下查询:

SELECT
  json_payload
FROM
  `TABLE`
WHERE
  json_payload.status IS NOT NULL

SELECT
  json_payload
FROM
  `TABLE`
WHERE
  JSON_VALUE(json_payload.status) IS NOT NULL

上述查询测试的是 json_payload 列的值;此列的内容由日志条目的内容决定。这两项查询都会舍弃不含 json_payload 列的行。这两个查询之间的差异就是最后一行,它定义了要根据 NULL 测试的内容。现在,假设有一个包含两行的表。其中一行中的 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"
}

前面两行都满足限制 json_payload.status IS NOT NULL。也就是说,查询结果包含这两行。 但是,当限制为 JSON_VALUE(json_payload.status) IS NOT NULL 时,结果中仅包含第二行。

按正则表达式过滤

如需返回与正则表达式匹配的子字符串,请使用函数 REGEXP_EXTRACT。此函数的返回值类型为 STRINGBYTES

以下查询会显示最近收到的日志条目,使用 json_payload.jobName 字段保留这些条目,然后显示以 test 开头的名称部分:

SELECT
  timestamp, REGEXP_EXTRACT(JSON_VALUE(json_payload.jobName), r".*(test.*)$") AS name,
FROM
  `TABLE`
WHERE
  json_payload.jobName IS NOT NULL
ORDER BY timestamp DESC
LIMIT 20

如需查看更多示例,请参阅 REGEXP_EXTRACT 文档。如需查看您可以使用的其他正则表达式的示例,请参阅函数、运算符和条件

此示例中显示的查询效率低下。如需进行子字符串匹配(如图所示),请使用 CONTAINS_SUBSTR 函数。

对日志条目进行分组和汇总

本部分在前面的示例的基础上,说明了如何对表中的行进行分组和汇总。如果您未指定分组但指定了聚合,则系统会输出单个结果,因为 SQL 会将满足 WHERE 子句的所有行视为一个组。

每个 SELECT 表达式都必须包含在组字段中或者进行汇总。

按时间分组

如需按时间对数据进行分组,请使用 TIMESTAMP_TRUNC 函数,该函数会将时间戳截断到指定的粒度,例如 MINUTE。例如,当粒度设置为 MINUTE 时,时间戳 15:30:11(格式为 hours:minutes:seconds)将变为 15:30:00

以下查询会读取在时间范围选择器指定的间隔内接收的数据,然后保留 json_payload.status 字段的值不是 NULL 的行。该查询按小时截断每行的时间戳,然后按截断的时间戳和状态对行进行分组:

SELECT
  TIMESTAMP_TRUNC(timestamp, HOUR) AS hour,
  JSON_VALUE(json_payload.status) AS status,
  COUNT(*) AS count
FROM
  `TABLE`
WHERE
  json_payload IS NOT NULL AND
  JSON_VALUE(json_payload.status) IS NOT NULL
GROUP BY hour,status
ORDER BY hour ASC

如需查看其他示例,请参阅 TIMESTAMP_TRUNC 文档。如需了解其他基于时间的函数,请参阅日期时间函数

按资源分组

以下查询会读取最近一小时的数据,然后按资源类型对行进行分组。然后,它会计算每种类型的行数,并返回一个包含两列的表。第一列列出了资源类型,第二列是该资源类型的行数:

SELECT
   resource.type, COUNT(*) AS count
FROM
  `TABLE`
GROUP BY resource.type
LIMIT 100

按严重程度分组

以下查询会读取最近一个小时的数据,然后保留具有严重级别字段的行。然后,查询会按严重性对行进行分组,并计算每个组的行数:

SELECT
  severity, COUNT(*) AS count
FROM
  `TABLE`
WHERE
  severity IS NOT NULL
GROUP BY severity
ORDER BY severity
LIMIT 100

log_id分组

以下查询的结果是一个包含两列的表。第一列列出日志名称,第二列列出已写入日志的日志条目数。该查询会按条目数对结果进行排序:

SELECT
  log_id, COUNT(*) AS count
FROM
  `TABLE`
GROUP BY log_id
ORDER BY count DESC
LIMIT 100

计算 HTTP 请求的平均延迟时间

以下查询展示了如何按多个列分组以及计算平均值。该查询按 HTTP 请求中包含的网址和 labels.checker_location 字段的值对行进行分组。对行进行分组后,查询会计算每组的平均延迟时间:

SELECT
  JSON_VALUE(labels.checker_location) AS location,
  AVG(http_request.latency.seconds) AS secs, http_request.request_url
FROM
  `TABLE`
WHERE
  http_request IS NOT NULL AND
  http_request.request_method IN ('GET')
GROUP BY http_request.request_url, location
ORDER BY location
LIMIT 100

在前面的表达式中,由于 labels 的数据类型为 JSON,因此需要 JSON_VALUE 来提取 labels.checker_location 字段的值。但是,您不能使用此函数从 http_request.latency.seconds 字段中提取值,第二个字段的数据类型为整数。

计算为子网测试发送的平均字节数

以下查询说明了如何显示按位置发送的平均字节数。

查询会读取最近一个小时的数据,然后仅保留资源类型列为 gce_subnetworkjson_payload 列不为 NULL 的行。接下来,查询会按资源的位置对行进行分组。与前面以数值形式存储数据的示例不同,bytes_sent 字段的值是一个字符串,因此在计算平均值之前,您必须将该值转换为 FLOAT64

SELECT JSON_VALUE(resource.labels.location) AS location,
   AVG(CAST(JSON_VALUE(json_payload.bytes_sent) AS FLOAT64)) AS bytes
FROM
  `TABLE`
WHERE
  resource.type = "gce_subnetwork" AND
  json_payload IS NOT NULL
GROUP BY location
LIMIT 100

上一个查询的结果是一个表,表中的每一行都列出了一个位置以及为该位置发送的平均字节数。

如需了解可以检索和转换 JSON 数据的所有函数,请参阅 JSON 函数

如需了解 CAST 和其他转换函数,请参阅转换函数

统计包含与模式匹配的字段的日志条目数

如需返回与正则表达式匹配的子字符串,请使用函数 REGEXP_EXTRACT。此函数的返回值类型为 STRINGBYTES

以下查询将保留 json_payload.jobName 字段的值不是 NULL 的日志条目。然后,它会按以 test 开头的名称后缀对条目进行分组。最后,查询计算每组中的条目数:

SELECT
  REGEXP_EXTRACT(JSON_VALUE(json_payload.jobName), r".*(test.*)$") AS name,
  COUNT(*) AS count
FROM
  `TABLE`
WHERE
  json_payload.jobName IS NOT NULL
GROUP BY name
ORDER BY count
LIMIT 20

如需查看更多示例,请参阅 REGEXP_EXTRACT 文档。如需查看您可以使用的其他正则表达式的示例,请参阅函数、运算符和条件

本部分介绍了可用于搜索表的多个列的两种不同方法。

如需在表中搜索与一组搜索字词匹配的条目,请使用函数 SEARCH。此函数需要两个参数:搜索地点和搜索查询。由于 SEARCH 函数对数据搜索方式有特定的规则,因此我们建议您阅读 SEARCH 文档

以下查询仅保留具有与“35.193.12.15”完全匹配的字段的那些行:

SELECT
  timestamp, log_id, proto_payload, severity, resource.type, resource, labels
FROM
  `TABLE` AS t
WHERE
  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 函数搜索字段值与反引号之间的值之间的完全匹配。

如果查询字符串中省略反引号,则系统会根据 SEARCH 文档中定义的规则拆分查询字符串。例如,当运行以下语句时,查询字符串会被拆分为四个词元:“35”“193”“12”和“15”:

  SEARCH(t,"35.193.12.15")

如果一个字段与所有四个令牌匹配,则前面的 SEARCH 语句将匹配一行。令牌的顺序无关紧要。

您可以在一个查询中包含多个 SEARCH 语句。例如,在上一个查询中,您可以将日志 ID 的过滤条件替换为如下所示的语句:

  SEARCH(t,"`cloudaudit.googleapis.com/data_access`")

前面的语句搜索整个表,而原始语句仅搜索 log_id 列。

如需对列执行多次搜索,请使用空格分隔各个字符串。例如,以下语句将匹配字段包含“Hello World”“happy”和“days”的行:

  SEARCH(t,"`Hello World` happy days")

最后,您可以搜索表的特定列,而不是搜索整个表。例如,以下语句仅搜索名为 text_payloadjson_payload 的列:

   SEARCH((text_payload, json_payload) ,"`35.222.132.245`")

如需了解如何处理 SEARCH 函数的参数,请参阅 BigQuery 参考页面搜索功能

如需执行不区分大小写的测试来确定表达式中是否存在某个值,请使用函数 CONTAINS_SUBSTR。当该值存在时,此函数返回 TRUE,否则返回 FALSE。搜索值必须是 STRING 字面量,而不是字面量 NULL

例如,以下查询会提取时间戳在特定时间范围内的特定 IP 地址的所有数据访问审核日志条目。最后,查询会对结果进行排序,然后显示时间最早的 20 条结果:

SELECT
  timestamp, log_id, proto_payload, severity, resource.type, resource, labels
FROM
  `TABLE` AS t
WHERE
  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

上一个查询会执行子字符串测试。因此,包含“35.193.12.152”的行将匹配 CONTAINS_SUBSTR 语句。

合并多个来源的数据

查询语句可扫描一个或多个表或表达式,并返回计算的结果行。例如,您可以使用查询语句以各种方式合并不同表或数据集的 SELECT 语句的结果,然后从合并的数据中选择列。

使用联接合并两个表中的数据

要合并两个表中的信息,请使用join运算符之一。您使用的联接类型和条件子句决定了行的组合和舍弃方式。

以下查询为您提供两个不同表中由同一跟踪记录 span 写入的行的 json_payload 字段。该查询对两个表中的 span_idtrace 列值匹配的行执行内部 JOIN。然后,查询会选择来自 TABLE_1timestampseverityjson_payload 字段、TABLE_2 中的 json_payload 字段以及联接这两个表的 span_idtrace 字段的值,并返回最多 100 行:

SELECT
  a.timestamp, a.severity, a.json_payload, b.json_payload, a.span_id, a.trace
FROM `TABLE_1` a
JOIN `TABLE_2` b
ON
  a.span_id = b.span_id AND
  a.trace = b.trace
LIMIT 100

使用并集结合多项选择

如需合并两个或更多 SELECT 语句的结果并舍弃重复的行,请使用 UNION 运算符。要保留重复的行,请使用 UNION ALL 运算符。

以下查询从 TABLE_1 中读取最近一小时的数据,将结果与 TABLE_2 中最近一小时的数据合并,按时间戳递增对合并的数据进行排序,然后显示时间最早的 100 个条目:

SELECT
  timestamp, log_name, severity, json_payload, resource, labels
FROM(
  SELECT * FROM `TABLE_1`
  UNION ALL
  SELECT * FROM `TABLE_2`
)
ORDER BY timestamp ASC
LIMIT 100

后续步骤

如需了解如何路由和存储日志条目,请参阅以下文档:

如需查看 SQL 参考文档,请参阅以下文档: