查询和查看日志

本页详细介绍了如何使用 Grafana 界面和日志查询 API 查询和直观呈现日志,以便深入了解服务事件和活动。

从 Google Distributed Cloud (GDC) 空气隔离环境中已部署的工作负载和服务收集日志后,您就可以开始分析这些日志了。如需分析日志,您可以在信息丰富的 Grafana 面板上直观呈现和过滤日志,也可以通过 HTTP 或 gRPC 调用直接从日志查询 API 访问日志,以实现程序化访问。

您可以通过以下两种方法之一访问日志:

  • Grafana 面板:通过 Grafana 实例的“日志”面板深入了解项目的活动记录。借助此面板,您可以查询并精确定位特定日志,从而获得根据您的需求量身定制的精细数据观测能力。Grafana 提供了一个易于使用的界面,用于过滤和分析工作负载数据,创建自定义信息中心和面板以实现全面的可视化。
  • 日志查询 API:如需以编程方式访问,请直接从项目的日志查询 API 查询日志。日志查询 API 是一种非 Kubernetes API,支持 HTTP 和 gRPC,并向您公开自己的端点。按照标准 API 访问方法,仅在分布式云中的特定组织内访问此 API。

准备工作

如需获得在 Grafana 界面上查询和直观呈现日志所需的权限,请让您的组织 IAM 管理员或项目 IAM 管理员为您授予预定义的组织 Grafana 查看者或项目 Grafana 查看者角色。根据您需要的访问权限级别,您可以在组织或项目中获取 Grafana 角色。

或者,如需获得通过 Log Query API 查询日志所需的权限,请让您的项目 IAM 管理员在项目命名空间中向您授予 Log Query API Querier 角色。

如需详细了解这些角色,请参阅准备 IAM 权限

查询和过滤日志

选择以下方法之一,以构建查询并过滤项目工作负载中的日志:

Grafana 日志面板

本部分介绍如何使用 Grafana 中的“日志”面板访问日志。

确定 Grafana 端点

以下网址是您项目的 Grafana 实例的端点:

  https://GDC_URL/PROJECT_NAMESPACE/grafana

替换以下内容:

  • GDC_URL:您组织在 GDC 中的网址。
  • PROJECT_NAMESPACE:您的项目命名空间。

    例如,org-1 组织中 platform-obs 项目的 Grafana 端点为 https://org-1/platform-obs/grafana

在 Grafana 界面中查看日志

在 Grafana 界面中查询日志:

  1. 在 GDC 控制台中,选择您的项目。
  2. 在导航菜单中,依次选择操作 > Logging
  3. 点击 View all in Grafana Loki

    系统会打开一个新页面,其中显示 Grafana 端点和界面。

  4. 在界面上,依次点击导航菜单中的探索 探索,打开探索页面。

  5. 探索栏中的菜单中,根据您的数据宇宙类型选择要检索日志的数据源:

    • 单可用区数据宇宙:选择以下数据源之一,以显示数据宇宙中单个可用区的日志记录数据:

      • 运维日志:显示运维日志。
      • 审核日志:显示审核日志。
    • 多地区数据宇宙:Grafana 可以连接到不同地区并显示跨地区数据。选择以下任一数据源,即可显示您所在全球区域中任何可用区的日志记录数据,而无需考虑您登录的可用区:

      • 运维日志 ZONE_NAME:显示特定地区的运维日志。
      • 审核日志 ZONE_NAME:显示特定区域的审核日志。

      此外,如需在单个信息中心内实现跨可用区的数据可视化,并将多个可用区添加到查询中,请选择混合作为数据源。

  6. 使用 LogQL(日志查询语言)表达式在“日志”面板中输入查询内容,以搜索日志。您可以通过以下任一方式执行此步骤:

    • 使用交互式查询构建器界面。然后,点击运行查询
    • 直接在文本字段中输入查询,然后按 Shift+Enter 运行查询。

    该页面会显示与您的查询匹配的日志。查询日志后,您可以导出日志。点击导出,以纯文本或 CSV 格式下载日志。您还可以为日志选择时间范围

    在“探索”页面上选择“审核日志”选项以获取审核日志。

    图 1. 用于从 Grafana 用户界面查询审核日志的菜单选项。

    在图 1 中,审核日志选项会显示一个界面,您可以在其中通过 Grafana 构建查询来检索审核日志。

    如需查看用于查询不同日志的标签和值示例,请参阅查询和标签示例

为日志选择时间范围

如需查询某个时间范围内的日志,请按以下步骤操作:

  1. 在 Grafana 中,点击 Time Picker(时间选择器)菜单。

  2. 在菜单中,执行以下操作之一:

    • 选择相对时间范围选项,例如“过去 30 分钟”。
    • 如需设置自定义绝对时间范围,请从日历中选择具体日期和时间,然后点击应用时间范围
  3. (可选)点击更改时间设置,通过时间范围控件更改时区会计年度设置。

    时间设置是按信息中心保存的。如需详细了解时间范围查询,请参阅 https://grafana.com/docs/loki/latest/reference/api/#query-loki-over-a-range-of-time

日志查询 API

本部分介绍了如何使用日志查询 API 访问日志。

确定您的 Log Query API 端点

日志查询 API 会公开以下两个端点,用于查询审核日志和操作日志:

  • 审核日志端点

    audit-log-query-api.ORG_DOMAIN
    
  • 操作日志端点

    operational-log-query-api.ORG_DOMAIN
    

ORG_DOMAIN 替换为组织的域名。您可以使用 gdcloud config list 命令查看此属性。域名必须遵循 org-name.zone.google.gdch.com 语法。例如,一个名为 org-1 的组织位于 zone1 可用区,并且处于测试环境中,其网域可能为 org-1.zone1.google.gdch.test

日志查询 API 具有以下三个端点选项:

  • labels:列出项目的所有标签。
  • labels/labels/LABEL/values:列出项目的特定标签值。
  • 日志:列出特定项目的日志。

如需了解详情,请参阅 API 文档

发送查询

使用 HTTP 或 gRPC 客户端向 Log Query API 端点发送查询。

HTTP

按照说明使用 HTTP 客户端直接访问 API。 您可以依靠 kubectl 来管理身份验证,也可以自行处理身份验证。

使用 curlwget 等 HTTP 客户端或您创建和管理的 HTTP 客户端查询 Log Query API。以下示例使用 curl 工具查询 API,您可以使用类似的格式来执行 wget 命令:

  1. 对 c网址 请求进行身份验证:

    1. 下载并安装 gdcloud CLI
    2. 设置 gdcloud core/organization_console_url 属性:

      gdcloud config set core/organization_console_url https://GDC_URL
      

      GDC_URL 替换为 GDC 中组织的网址。

    3. 通过配置的身份提供方登录

      gdcloud auth login
      
    4. 使用您的用户名和密码进行身份验证并登录。

    5. 将指定账号的身份令牌导出到环境变量:

      export TOKEN="$($HOME/gdcloud auth print-identity-token --audiences=https://LOG_QUERY_API_ENDPOINT)"
      

      LOG_QUERY_API_ENDPOINT 替换为您要从中查询日志的 Log Query API 端点以及您要连接的网域。因此,audiences 标志的值可以是 https://operational-log-query-api.org-1.zone1.google.gdch.test 等。

      登录成功后,您可以通过 gdcloud auth print-identity-token 命令在 c网址 请求中使用授权标头。如需了解详情,请参阅 gdcloud auth print-identity-token

  2. 如果您想列出项目的所有标签,请发送以下查询:

    curl -H "Authorization: Bearer ${TOKEN}" \
    https://LOG_QUERY_API_ENDPOINT/v1/projects/PROJECT_NAMESPACE/labels \
    -H "Content-Type: application/json" -v
    

    替换以下内容:

    • LOG_QUERY_API_ENDPOINT:您要从中查询日志的 Log Query API 端点
    • PROJECT_NAMESPACE:您的项目命名空间。
  3. 如果您想列出项目的特定标签值,请发送以下查询:

    curl -H "Authorization: Bearer ${TOKEN}" \
    https://LOG_QUERY_API_ENDPOINT/v1/projects/PROJECT_NAMESPACE/labels/labels/LABEL/values \
    -H "Content-Type: application/json" -v
    

    替换以下内容:

    • LOG_QUERY_API_ENDPOINT:您要从中查询日志的 Log Query API 端点
    • PROJECT_NAMESPACE:您的项目命名空间。
    • LABEL:您要查询其值的特定标签。
  4. 如果您想查询特定项目的日志,请构建一个 logs_filter 查询并将其包含在请求正文中:

    curl -X GET -H "Authorization: Bearer ${TOKEN}" \
    https://LOG_QUERY_API_ENDPOINT/v1/projects/PROJECT_NAMESPACE/logs \
    -H "Content-Type: application/json" -d \
    '{"logs_filter": {"labels_equal": {"LABEL": "LABEL_VALUE"}}}' -v
    

    替换以下内容:

    • LOG_QUERY_API_ENDPOINT:您要从中查询日志的 Log Query API 端点
    • PROJECT_NAMESPACE:您的项目命名空间。
    • LABEL:您要查询日志的特定标签。
    • LABEL_VALUE:您要查询的日志的标签值。

    如需查看构建 logs_filter 查询的所有选项,请参阅 API 文档

gRPC

gRPC 广泛支持各种编程语言,与 HTTP 客户端相比,它提供了一种更高效的通信方法。

如需使用 gRPC 查询日志,您必须满足以下前提条件:

  • 基于 Google 提供的协议缓冲区创建您自己的客户端库。
  • 在客户端中实现身份验证。
  • 实现重试。

如需了解协议缓冲区,请参阅 API 文档

以下示例展示了如何使用未经身份验证的 gRPC 客户端从 Go 程序中查询日志。此示例假设您创建了一个包含 Bazel build 文件的 GoLang 软件包,用于导入代码依赖项:

  1. 将以下代码保存到名为 client.go 的 Go 程序中:

    package main
    import (
            "context"
            "crypto/tls"
            "flag"
            "fmt"
            "google.golang.org/grpc/credentials"
            "google.golang.org/grpc/metadata"
            pb "<import path to generated log query api protos>/pkg/apis/public/logging/v1/proto"
            "google.golang.org/grpc"
    )
    
    var serverAddr = flag.String("server", "localhost:8080", "server address")
    
    func main() {
            flag.Parse()
            tc := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
            conn, err := grpc.Dial(*serverAddr, grpc.WithTransportCredentials(tc))
    
            if err != nil {
                    panic(error.Error(fmt.Errorf("create client connection failed: %v", err)))
            }
            defer conn.Close()
    
            c := pb.NewLogsClient(conn)
            md := metadata.Pairs("clienttest", "test")
            ctx := metadata.NewOutgoingContext(context.Background(), md)
    
            err = listLabels(ctx, c, "project-foo")
            if err != nil {
                    panic(error.Error(err))
            }
    
            if err := listLabelValues(ctx, c, "project-foo", "resource-bar"); err != nil {
                    panic(error.Error(err))
            }
    
            if err := listLogs(ctx, c, "project-foo", &pb.ListLogsFilter{
                    LabelsEqual:    map[string]string{"resource-bar": "resource-bar-value"},
                    OrderAscending: true,
            }); err != nil {
                    panic(error.Error(err))
            }
    }
    
    // List all labels for a project.
    
    func listLabels(ctx context.Context, c pb.LogsClient, project string) error {
            lbr := &pb.ListLabelsRequest{
                    Parent:   project,
                    PageSize: 1000, // PageSize can be configured to limit the number of responses per page.
            }
            resp, err := c.ListLabels(ctx, lbr)
            if err != nil {
                    return fmt.Errorf("list labels: %v", err)
            }
            fmt.Printf("%v", resp)
            return nil
    }
    
    // List specific label values for a project.
    
    func listLabelValues(ctx context.Context, c pb.LogsClient, project string, label string) error {
            lbr := &pb.ListLabelValuesRequest{
                    Parent:   project,
                    Label:    label,
                    PageSize: 1000, // PageSize can be configured to limit the number of responses per page.
            }
            resp, err := c.ListLabelValues(ctx, lbr)
            if err != nil {
                    return fmt.Errorf("list label values: %v", err)
            }
            fmt.Printf("%v", resp)
            return nil
    }
    
    // List logs for a specific project.
    
    func listLogs(ctx context.Context, c pb.LogsClient, project string, lf *pb.ListLogsFilter) error {
            lbr := &pb.ListLogsRequest{
                    Parent:     project,
                    LogsFilter: lf,
                    PageSize:   5, // PageSize can be configured to limit the number of responses per page.
            }
            resp, err := c.ListLogs(ctx, lbr)
            if err != nil {
                    return fmt.Errorf("list logs: %v", err)
            }
            fmt.Printf("logs: %v", resp)
            return nil
    }
    
  2. 运行 Go 程序:

    go run PATH_TO_API/client.go -server=LOG_QUERY_API_ENDPOINT:443
    

    替换以下内容:

    • PATH_TO_API:API 文件的路径。
    • LOG_QUERY_API_ENDPOINT:您要从中查询日志的 Log Query API 端点

    如果未指定服务器标志,默认请求会到达 localhost

示例查询和标签

以下是一些可用于查询日志的默认标签:

  • cluster:集群的名称。
  • namespace:您的项目命名空间。
  • node:节点名称。
  • pod:Pod 名称。
  • container:容器名称。

以下代码示例展示了如何使用标签和值查询不同的日志:

  • 选择服务器日志:

    {cluster="admin", namespace="kube-system", resources="k8s_container", container="kube-apiserver"}
    
  • 选择集群审核日志:

    {cluster="admin", resources="k8s_audit"}