Trace 的 SQL 查询示例

本文档包含一些示例查询,这些查询专门用于查询存储在 Google Cloud 项目中的轨迹数据。

SQL 语言支持

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

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

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

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

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

最佳做法

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

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

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. Enable the Observability API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the 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. Enable the Observability API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

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

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

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

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

如何使用本页面上的查询

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

    转到 Log Analytics

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

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

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

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

    FROM 子句包含以下字段:

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

如需在 BigQuery Studio 页面上使用本文档中显示的查询,或使用 bq 命令行工具,请修改 FROM 子句并输入关联数据集的路径。例如,如需查询项目 myproject 中名为 my_linked_dataset 的关联数据集上的 _AllSpans 视图,路径为 `myproject.my_linked_dataset._AllSpans`

常见使用场景

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

显示所有跟踪记录数据

如需查询 _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 子句。您在此子句中使用的语法取决于字段的数据类型。本部分提供了多种不同数据类型的示例。

按字符串数据类型过滤

字段 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%'
    

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

本部分说明了如何对 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

查询多个视图

查询语句可扫描一个或多个表或表达式,并返回计算的结果行。例如,您可以使用查询语句以各种方式合并不同表或数据集中的 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 联接轨迹数据和日志数据

以下查询使用 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 载荷的严重程度。

后续步骤

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