查询和查看日志

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

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

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

  • Grafana 面板:通过 Grafana 实例的“日志”面板深入了解项目的活动记录。借助此面板,您可以查询和精确定位特定日志,从而根据您的需求提供精细的数据可观测性。Grafana 提供了一个用户友好的界面,用于过滤和分析工作负载数据,并创建自定义信息中心和面板以进行全面可视化。
  • 日志查询 API:如需进行程序化访问,请直接从您的 项目的日志查询 API 查询日志。日志查询 API 是一种非 Kubernetes API,支持 HTTP 和 gRPC,并向您公开自己的端点。请遵循 标准 API 访问方法,仅在 Distributed Cloud 中的特定组织内访问此 API。

准备工作

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

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

如需详细了解这些角色,请参阅 准备 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. 在导航菜单中,依次选择 运维 > 日志记录
  3. 点击在 Grafana Loki 中查看全部

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

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

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

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

      • 运维日志:显示运维日志。
      • 审核日志:显示审核日志。
    • 多可用区宇宙:Grafana 可以连接到不同的可用区 并显示跨可用区数据。选择以下数据源之一,以显示宇宙中任何可用区的日志记录数据,无论您登录的是哪个可用区:

      • 运维日志 ZONE_NAME:显示 特定可用区中的运维日志。
      • 审核日志 ZONE_NAME:显示特定可用区中的审核日志 。

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

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

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

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

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

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

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

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

为日志选择时间范围

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

  1. 点击 Grafana 中的 Time Picker 菜单。

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

    • 选择相对时间范围选项,例如过去 30 分钟。
    • 通过从日历中选择特定日期和时间并点击 Apply time range ,设置自定义绝对时间范围。
  3. (可选)点击 Change time settings ,以从时间范围控件中更改 TimezoneFiscal year 设置。

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

日志查询 API

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

确定日志查询 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。例如,在 zone1 可用区中且在测试环境中的名为 org-1 的组织具有类似于 org-1.zone1.google.gdch.test 的域名。

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

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

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

发送查询

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

HTTP

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

使用 HTTP 客户端(例如 curlwget 或您创建和管理的 HTTP 客户端)查询日志查询 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 替换为您要从中查询日志的 日志查询 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:您要从中查询日志的 日志查询 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:您要从中查询日志的 日志查询 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:您要从中查询日志的 日志查询 API 端点
    • PROJECT_NAMESPACE:项目命名空间。
    • LABEL:您要查询日志的特定标签。
    • LABEL_VALUE:您要查询日志的标签值。

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

gRPC

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

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

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

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

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

  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:您要从中查询日志的 日志查询 API 端点

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

示例查询和标签

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

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

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

  • 选择服务器日志:

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

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