示例 SQL 查询

本文档包含一些示例查询,可用于查询日志和轨迹数据。

SQL 语言支持

Log Analytics 页面中使用的查询支持 GoogleSQL 函数,但有一些例外情况。

通过 Log Analytics 页面发出的 SQL 查询不支持以下 SQL 命令:

  • DDL 和 DML 命令
  • JavaScript 用户定义的函数
  • BigQuery ML 函数
  • SQL 变量

仅当您使用 BigQuery StudioLooker Studio 页面或 bq 命令行工具查询关联的数据集时,系统才支持以下各项:

  • JavaScript 用户定义的函数
  • BigQuery ML 函数
  • SQL 变量

最佳做法

如需设置查询的时间范围,我们建议您使用时间范围选择器。例如,如需查看过去一周的数据,请从时间范围选择器中选择过去 7 天。您还可以使用时间范围选择器指定开始时间和结束时间、指定要查看的时间范围,以及更改时区。

日志数据

如果您在 WHERE 子句中添加 timestamp 字段,则不会使用时间范围选择器设置。以下示例说明了如何按时间戳过滤:

-- Matches log entries whose timestamp is within the most recent 1 hour.
WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)

跟踪记录数据

如果您在 WHERE 子句中添加 start_time 字段,则不会使用时间范围选择器设置。以下示例说明了如何按时间戳过滤:

-- Matches trace spans whose start_time is within the most recent 1 hour.
WHERE start_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)

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

准备工作

  1. 登录您的 Google Cloud 账号。如果您是 Google Cloud新手,请 创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. 启用 Observability API。

    启用 API 所需的角色

    如需启用 API,您需要拥有 Service Usage Admin IAM 角色 (roles/serviceusage.serviceUsageAdmin),该角色包含 serviceusage.services.enable 权限。了解如何授予角色

    启用 API

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  6. Verify that billing is enabled for your Google Cloud project.

  7. 启用 Observability API。

    启用 API 所需的角色

    如需启用 API,您需要拥有 Service Usage Admin IAM 角色 (roles/serviceusage.serviceUsageAdmin),该角色包含 serviceusage.services.enable 权限。了解如何授予角色

    启用 API

  8. 如需获得加载 Log Analytics 页面、在跟踪记录数据上撰写、运行和保存私密查询所需的权限,请让管理员为您授予以下 IAM 角色:

    • Observability View Accessor (roles/observability.viewAccessor) 在您要查询的可观测性视图上。此角色支持 IAM 条件,可让您将授予的权限限制为仅针对特定视图。如果您未为角色授予附加条件,则正文可以访问所有可观测性视图。可观测性视图目前为公开预览版。
    • 针对项目的 Observability Analytics User (roles/observability.analyticsUser)。此角色包含保存和运行专用查询以及运行共享查询所需的权限。
    • 项目的 Logs Viewer (roles/logging.viewer) 角色。
    • 存储您要查询的日志视图的项目的 Logs View Accessor (roles/logging.viewAccessor)。

    如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限

    您也可以通过自定义角色或其他预定义角色来获取所需的权限。

如何使用本页面上的查询

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

    转到 Log Analytics

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

  2. 查询窗格中,点击  SQL,然后将查询复制并粘贴到 SQL 查询窗格中。

    日志数据

    在复制查询之前,请在 FROM 子句中替换以下字段

    • PROJECT_ID:项目的标识符。
    • LOCATION:日志视图或分析视图的位置。
    • BUCKET_ID:日志存储桶的名称或 ID。
    • LOG_VIEW_ID:日志视图的标识符,长度不得超过 100 个字符,并且只能包含字母、数字、下划线和连字符。

    以下内容展示了日志视图FROM 子句的格式:

    FROM `PROJECT_ID.LOCATION.BUCKET_ID.LOG_VIEW_ID`
    

    本页上的日志示例会查询日志视图。如需查询分析视图,请使用以下路径格式:`analytics_view.PROJECT_ID.LOCATION.ANALYTICS_VIEW_ID`。 在上述表达式中,PROJECT_ID 是您的项目 ID,LOCATIONANALYTICS_VIEW_ID 分别是您的分析视图的位置和名称。

    跟踪记录数据

    以下内容展示了查询 _AllSpans 视图的 FROM 原因的格式:

    FROM `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
    

    FROM 子句包含以下字段:

    • PROJECT_ID:项目的标识符。
    • LOCATION:可观测性存储桶的位置
    • _Trace 是观测性存储桶的名称
    • Spans 是数据集的名称。
    • _AllSpans 是视图名称。

如需在 BigQuery Studio 页面上使用本文档中显示的查询,或使用 bq 命令行工具,请修改 FROM 子句并输入关联数据集的路径

日志数据

例如,如需查询项目 myproject 中名为 mydataset 的关联数据集上的 _AllLogs 视图,路径为 myproject.mydataset._AllLogs

跟踪记录数据

例如,如需查询项目 myproject 中名为 my_linked_dataset 的关联数据集上的 _AllSpans 视图,路径为 `myproject.my_linked_dataset._AllSpans`

常见使用场景

本部分列出了几个常见用例,可能有助于您创建自定义查询。

显示默认日志存储桶中的日志条目

如需查询 _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 函数可提高查询效率。

显示所有跟踪记录数据

如需查询 _AllSpans 视图,请运行以下查询:

-- Display all data.
SELECT *
FROM `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
-- Limit to 10 entries.
LIMIT 10

显示常见跨度信息

如需显示常见的时间段信息(例如开始时间和时长),请运行以下查询:

SELECT
  start_time,
  -- Set the value of service name based on the first non-null value in the list.
  COALESCE(
    JSON_VALUE(resource.attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."g.co/gae/app/module"')) AS service_name,
  name AS span_name,
  duration_nano,
  status.code AS status,
  trace_id,
  span_id
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
LIMIT 10

如需了解详情,请参阅条件表达式

显示 span 延迟时间的第 50 百分位和第 99 百分位

如需显示每个 RPC 服务的第 50 和第 99 百分位延迟时间,请运行以下查询:

SELECT
  -- Compute 50th and 99th percentiles for each service
  STRING(attributes['rpc.service']) || '/' || STRING(attributes['rpc.method']) AS rpc_service_method,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(50)] AS duration_nano_p50,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(99)] AS duration_nano_p99
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
WHERE
  -- Matches spans whose kind field has a value of 2 (SPAN_KIND_SERVER).
  kind = 2
GROUP BY rpc_service_method

如需详细了解此枚举,请参阅 OpenTelemetry:SpanKind 文档。

如需以图形方式查看结果,您可以创建一个维度设置为 rpc_service_method 的图表。您可以添加两个指标,一个用于计算 duration_nano_p50 值的平均值,另一个用于计算 duration_nano_p99 字段的平均值。

过滤日志条目

如需对查询应用过滤条件,请添加 WHERE 子句。您在此子句中使用的语法取决于字段的数据类型。本部分提供了多种不同数据类型的示例。

按载荷类型过滤日志条目

日志条目可以具有以下三种载荷类型之一。如需按载荷类型过滤日志条目,请使用以下子句之一:

  • 文本载荷

    -- 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_payloadproto_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_namelog_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。第二个子句用于测试是否存在状态字段。假设某个日志视图包含两个日志条目。对于一个日志条目,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 仅与第二个日志条目匹配。

过滤轨迹条目

如需对查询应用过滤条件,请添加 WHERE 子句。您在此子句中使用的语法取决于字段的数据类型。本部分提供了多种不同数据类型的示例。

按字符串数据类型过滤

字段 nameString 的形式存储。

  • 如需仅分析指定了 name 的 span,请使用以下子句:

    -- Matches spans that have a name field.
    WHERE name IS NOT NULL
    
  • 如需仅分析 name 值为 "POST" 的 span,请使用以下子句:

    -- Matches spans whose name is POST.
    WHERE STRPOS(name, "POST") > 0
    
  • 如需仅分析 name 包含值 "POST" 的 span,请将 LIKE 运算符与通配符搭配使用:

    -- Matches spans whose name contains POST.
    WHERE name LIKE "%POST%"
    

按整数数据类型过滤

字段 kind 是一个整数,其值介于 0 到 5 之间:

  • 如需仅分析指定了 kind 的 span,请使用以下子句:

    -- Matches spans that have field named kind.
    WHERE kind IS NOT NULL
    
  • 如需分析 kind 值为 1 或 2 的 span,请使用以下子句:

    -- Matches spans whose kind value is 1 or 2.
    WHERE kind IN (1, 2)
    

按 RECORD 数据类型过滤

轨迹架构中的某些字段的数据类型为 RECORD。这些字段可以存储一个或多个数据结构,也可以存储相同数据结构的重复条目。

按状态或状态代码过滤

status 字段是数据类型为 RECORD 的字段的一个示例。此字段存储一个数据结构,其成员标记为 codemessage

  • 如需仅在 status.code 字段的值为 1 时分析 span,请添加以下子句:

    -- Matches spans that have a status.code field that has a value of 1.
    WHERE status.code = 1
    

    status.code 字段以整数形式存储。

  • 如需分析 status 字段不是 EMPTY 的 span,请添加以下子句:

    -- Matches spans that have status field. When the status field exists, it
    -- must contain a subfield named code.
    -- Don't compare status to NULL, because this field has a data type of RECORD.
    WHERE status.code IS NOT NULL
    

eventslinks 字段以 RECORD 的数据类型存储,但这些字段是重复字段。

  • 如需匹配至少包含一个事件的 span,请使用以下子句:

    -- Matches spans that have at least one event. Don't compare events to NULL.
    -- The events field has data type of RECORD and contains a repeated fields.
    WHERE ARRAY_LENGTH(events) > 0
    
  • 如需匹配具有 name 字段值为 message 的事件的 span,请使用以下子句:

    WHERE
      -- Exists is true when any event in the array has a name field with the
      -- value of message.
      EXISTS(
        SELECT 1
        FROM UNNEST(events) AS ev
        WHERE ev.name = 'message'
      )
    

按 JSON 数据类型过滤

attributes 字段的类型为 JSON。每个单独的属性都是一个键值对。

  • 如需仅分析指定了 attributes 的 span,请使用以下子句:

    -- Matches spans where at least one attribute is specified.
    WHERE attributes IS NOT NULL
    
  • 如需仅分析属性键名为 component 且值为 "proxy" 的 span,请使用以下子句:

    -- Matches spans that have an attribute named component with a value of proxy.
    WHERE attributes IS NOT NULL
          AND JSON_VALUE(attributes, '$.component') = 'proxy'
    

    您还可以将 LIKE 语句与通配符搭配使用,以执行包含测试:

    -- Matches spans that have an attribute named component whose value contains proxy.
    WHERE attributes IS NOT NULL
          AND JSON_VALUE(attributes, '$.component') LIKE '%proxy%'
    

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

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

每个 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

计算每个网址的 HTTP 请求的平均延迟时间

以下查询展示了如何按 HTTP 请求网址和位置对日志条目进行分组,然后统计每个组中的日志条目数:

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

如需了解详情,请参阅 JSON 函数转换函数

统计具有与某种模式匹配的字段的日志条目数

如需返回与正则表达式匹配的子字符串,请使用函数 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 文档

对轨迹数据进行分组和汇总

本部分说明了如何对 span 进行分组和汇总。如果您未指定分组,但指定了汇总,则系统会输出一个结果,因为 SQL 会将满足 WHERE 子句的所有条目视为一个组。

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

按开始时间对 span 进行分组

如需按开始时间对数据进行分组,请使用 TIMESTAMP_TRUNC 函数,该函数会将时间戳截断为指定的粒度,例如 HOUR

SELECT
  -- Truncate the start time to the hour. Count the number of spans per group.
  TIMESTAMP_TRUNC(start_time, HOUR) AS hour,
  status.code AS code,
  COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
WHERE
  -- Matches spans shows start time is within the previous 12 hours.
  start_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 12 HOUR)
GROUP BY
  -- Group by hour and status code.
  hour, code
ORDER BY hour DESC

如需了解详情,请参阅 TIMESTAMP_TRUNC 文档日期时间函数

按状态代码统计 span 数

如需显示具有特定状态代码的 span 的数量,请运行以下查询:

SELECT
  -- Count the number of spans for each status code.
  status.code,
  COUNT(*) AS count
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
WHERE status.code IS NOT NULL
GROUP BY status.code

如果您将 status.code 替换为 kind,则上一个查询会报告 kind 枚举的每个值的跨度数。同样,如果您将 status.code 替换为 name,则查询结果会列出每个 span 名称的条目数。

计算所有 span 的平均时长

如需显示按 span 名称对 span 数据分组后的平均时长,请运行以下查询:

SELECT
  -- Group by name, and then compute the average duration for each group.
  name,
  AVG(duration_nano) AS nanosecs,
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
GROUP BY name
ORDER BY nanosecs DESC

按服务名称计算平均时长和百分位数

以下查询会计算每个服务的 span 数量和各种统计信息:

SELECT
  -- Set the service name by the first non-null value.
  COALESCE(
    JSON_VALUE(resource.attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."service.name"'),
    JSON_VALUE(attributes, '$."g.co/gae/app/module"')) AS service_name,

  -- Count the number spans for each service name. Also compute statistics.
  COUNT(*) AS span_count,
  AVG(duration_nano) AS avg_duration_nano,
  MIN(duration_nano) AS min_duration_nano,
  MAX(duration_nano) AS max_duration_nano,

  -- Calculate percentiles for duration
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(50)] AS p50_duration_nano,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(95)] AS p95_duration_nano,
  APPROX_QUANTILES(duration_nano, 100)[OFFSET(99)] AS p99_duration_nano,

  -- Count the number of unique trace IDs. Also, collect up to 5 unique
  -- span names and status codes.
  COUNT(DISTINCT trace_id) AS distinct_trace_count,
  ARRAY_AGG(DISTINCT name IGNORE NULLS LIMIT 5) AS sample_span_names,
  ARRAY_AGG(DISTINCT status.code IGNORE NULLS LIMIT 5) AS sample_status_codes
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans`
GROUP BY service_name
ORDER BY span_count DESC

本部分介绍了可用于搜索所查询视图的多个列的两种方法:

  • 基于词元的搜索:您需要指定搜索位置、搜索查询,然后使用 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 文档中定义的规则拆分查询字符串。例如,运行以下语句时,查询字符串会被拆分为四个token:“35”“193”“12”和“15”:

  SEARCH(t,"35.193.12.15")

当单个字段匹配所有四个token时,前面的 SEARCH 语句会匹配一行。token 的顺序无关紧要。

您可以在一个查询中添加多个 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 参考页面搜索函数

例如,以下查询会提取具有特定 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

查询多个视图

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

如需联接视图,请注意以下限制:

  1. 视图的位置满足以下条件之一:

    • 所有视图都位于同一位置。
    • 所有视图都位于 globalus 位置。
  2. 当存储资源使用客户管理的加密密钥 (CMEK) 时,必须满足以下条件之一:

    • 使用 CMEK 的存储资源使用相同的 Cloud KMS 密钥。
    • 使用 CMEK 的存储资源具有共同的祖先,该祖先指定了与存储资源位于同一位置的默认 Cloud KMS 密钥。

    当一个或多个存储资源使用 CMEK 时,系统会使用通用 Cloud KMS 密钥或祖先的默认 Cloud KMS 密钥来加密联接生成的临时数据。

例如,假设您有两个位于同一位置的视图。然后,在满足以下任一条件时,您可以联接这些视图:

  • 存储资源不使用 CMEK。
  • 一个存储资源使用 CMEK,另一个不使用。
  • 这两个存储资源都使用 CMEK,并且都使用相同的 Cloud KMS 密钥。
  • 两个存储资源都使用 CMEK,但使用的密钥不同。不过,这些资源共用一个祖先,该祖先指定了一个与存储资源位于同一位置的默认 Cloud KMS 密钥。

    例如,假设日志存储桶和可观测性存储桶的资源层次结构包含同一组织。当您为相应组织配置了Cloud Logging 的默认资源设置可观测性存储分区,并为存储位置设置了相同的默认 Cloud KMS 密钥时,您可以联接这些存储分区中的视图。

按跟踪记录 ID 联接两个日志视图

如需合并两个表中的信息,请使用以下联接运算符之一: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

使用并集语句查询两个日志视图

如需合并两个或更多 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 联接轨迹数据和日志数据

以下查询使用 span ID 和 trace ID 联接日志数据和跟踪记录数据:

SELECT
  T.trace_id,
  T.span_id,
  T.name,
  T.start_time,
  T.duration_nano,
  L.log_name,
  L.severity,
  L.json_payload
FROM
  `PROJECT_ID.LOCATION._Trace.Spans._AllSpans` AS T
JOIN
  `PROJECT_ID.LOCATION._Default._AllLogs` AS L
ON
  -- Join log and trace data by both the span ID and trace ID.
  -- Don't join only on span ID, this field isn't globally unique.
  T.span_id = L.span_id
  -- A regular expression is required because the storage format of the trace ID
  -- differs between a log view and a trace view.
  AND T.trace_id = REGEXP_EXTRACT(L.trace, r'/([^/]+)$')
WHERE T.duration_nano > 1000000
LIMIT 10

查询的响应会列出轨迹 ID 和 span ID,您可以单独查询这些 ID 以收集更多信息。此外,结果还会列出日志条目和 JSON 载荷的严重程度。

移除重复的日志条目

在运行查询之前,Log Analytics 不会移除重复的日志条目。 这种行为与使用Logs Explorer查询日志条目时不同,后者会通过比较日志名称、时间戳和插入 ID 字段来移除重复条目。

您可以使用行级验证来移除重复的日志条目。

如需了解详情,请参阅问题排查:我的 Log Analytics 结果中存在重复的日志条目

后续步骤

如需查看 SQL 参考文档或其他示例,请参阅以下文档: