Trace 的 SQL 查询示例

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

SQL 语言支持

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

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

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

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

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

最佳做法

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

如果您在 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. 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. 如需获得加载 Observability Analytics 页面、编写、运行和保存跟踪记录数据的私有查询所需的权限,请让管理员为您授予以下 IAM 角色:

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

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

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

如何使用此页面上的查询

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

    前往 Observability Analytics

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

  2. Query 窗格中,点击  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

显示常见 span 信息

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

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 子句。在此子句中使用的语法取决于字段的数据类型。本部分提供了针对不同数据类型的多个示例。

按字符串数据类型过滤

字段 name 存储为 String

  • 如需仅分析指定了 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 枚举的每个值的 span 数量。同样,如果您将 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) 时, 以下条件之一为 true:

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

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

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

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

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

使用跟踪记录 ID 联接跟踪记录数据和日志数据

以下查询使用 span ID 和跟踪记录 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 参考文档或其他示例,请参阅以下文档: