本文档包含一些示例查询,可用于查询日志和轨迹数据。
SQL 语言支持
Log Analytics 页面中使用的查询支持 GoogleSQL 函数,但有一些例外情况。
通过 Log Analytics 页面发出的 SQL 查询不支持以下 SQL 命令:
- DDL 和 DML 命令
- JavaScript 用户定义的函数
- BigQuery ML 函数
- SQL 变量
仅当您使用 BigQuery Studio 和 Looker 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)
准备工作
- 登录您的 Google Cloud 账号。如果您是 Google Cloud新手,请 创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
-
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 theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
-
启用 Observability API。
启用 API 所需的角色
如需启用 API,您需要拥有 Service Usage Admin IAM 角色 (
roles/serviceusage.serviceUsageAdmin),该角色包含serviceusage.services.enable权限。了解如何授予角色。 -
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 theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
-
启用 Observability API。
启用 API 所需的角色
如需启用 API,您需要拥有 Service Usage Admin IAM 角色 (
roles/serviceusage.serviceUsageAdmin),该角色包含serviceusage.services.enable权限。了解如何授予角色。 -
如需获得加载 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)。
如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限。
-
Observability View Accessor (
如何使用本页面上的查询
-
在 Google Cloud 控制台中,前往 manage_search Log Analytics 页面:
如果您使用搜索栏查找此页面,请选择子标题为 Logging 的结果。
在查询窗格中,点击 code 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,LOCATION和ANALYTICS_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 NULLJSON 载荷
-- Matches log entries that have a JSON payload. WHERE json_payload IS NOT NULLProto 载荷
-- 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。第二个子句用于测试是否存在状态字段。假设某个日志视图包含两个日志条目。对于一个日志条目,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 子句。您在此子句中使用的语法取决于字段的数据类型。本部分提供了多种不同数据类型的示例。
按字符串数据类型过滤
字段 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 的字段的一个示例。此字段存储一个数据结构,其成员标记为 code 和 message。
如需仅在
status.code字段的值为1时分析 span,请添加以下子句:-- Matches spans that have a status.code field that has a value of 1. WHERE status.code = 1status.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
按事件或链接过滤
events 和 links 字段以 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
统计具有与某种模式匹配的字段的日志条目数
如需返回与正则表达式匹配的子字符串,请使用函数 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。
在日志视图中进行基于 token 的搜索
以下查询仅保留字段与“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_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
查询多个视图
查询语句可扫描一个或多个表或表达式,并返回计算的结果行。例如,您可以使用查询语句以各种方式合并不同表或数据集中的 SELECT 语句的结果,然后从合并后的数据中选择列。
如需联接视图,请注意以下限制:
-
视图的位置满足以下条件之一:
- 所有视图都位于同一位置。
- 所有视图都位于
global或us位置。
-
当存储资源使用客户管理的加密密钥 (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 参考文档或其他示例,请参阅以下文档:
- 函数、运算符和条件表达式。
- 搜索函数。
- 查询语法。