You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Cloud Go SDK启用HTTP日志遇gRPC兼容错误的解决方法

解决Google Cloud Go SDK Service Usage客户端的"WithHTTPClient incompatible"错误及日志方案

一、错误原因分析

Service Usage客户端默认采用gRPC传输协议,而WithHTTPClient选项仅适用于使用REST/HTTP1.1协议的客户端。两者底层传输机制不同,混用会直接触发"WithHTTPClient is incompatible with gRPC dial options"错误——即使你未手动设置gRPC选项,SDK也会默认启用gRPC相关配置。


二、错误解决办法

方案1:切换到REST版客户端使用自定义HTTP客户端

如果需要通过自定义HTTP客户端捕获日志,直接使用Service Usage的REST版本客户端即可,它天然支持WithHTTPClient选项:

import (
    "context"
    "net/http"
    "net/http/httputil"
    "google.golang.org/api/option"
    serviceusage "google.golang.org/api/serviceusage/v1"
)

// 自定义带请求响应日志的Transport
type loggingTransport struct {
    http.RoundTripper
}

func (t *loggingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    // 打印请求详情
    reqDump, _ := httputil.DumpRequestOut(req, true)
    println("=== HTTP Request ===\n", string(reqDump))

    // 发送请求并获取响应
    resp, err := t.RoundTripper.RoundTrip(req)
    if err != nil {
        return resp, err
    }

    // 打印响应详情
    respDump, _ := httputil.DumpResponse(resp, true)
    println("=== HTTP Response ===\n", string(respDump))
    return resp, nil
}

func main() {
    ctx := context.Background()

    // 构建带日志Transport的HTTP客户端
    customHTTPClient := &http.Client{
        Transport: &loggingTransport{RoundTripper: http.DefaultTransport},
    }

    // 创建REST版Service Usage客户端,传入自定义HTTP客户端
    svc, err := serviceusage.NewService(ctx, option.WithHTTPClient(customHTTPClient))
    if err != nil {
        panic(err)
    }

    // 调用API列出已启用服务
    result, err := svc.Services.List("projects/你的项目ID").Filter("state:ENABLED").Do()
    if err != nil {
        panic(err)
    }

    // 处理返回结果...
}

方案2:保留gRPC客户端,改用gRPC拦截器日志

如果要继续使用默认的gRPC客户端,不要用WithHTTPClient,而是通过gRPC的一元拦截器来捕获请求响应日志:

import (
    "context"
    "fmt"
    "google.golang.org/grpc"
    serviceusagepb "google.golang.org/genproto/googleapis/api/serviceusage/v1"
    serviceusage "google.golang.org/api/serviceusage/v1"
    "google.golang.org/api/option"
)

// gRPC一元拦截器:打印请求响应详情
func grpcLoggingInterceptor(
    ctx context.Context,
    method string,
    req interface{},
    reply interface{},
    cc *grpc.ClientConn,
    invoker grpc.UnaryInvoker,
    opts ...grpc.CallOption,
) error {
    fmt.Printf("=== gRPC Request ===\nMethod: %s\nBody: %+v\n", method, req)
    err := invoker(ctx, method, req, reply, cc, opts...)
    if err != nil {
        fmt.Printf("=== gRPC Error ===\nMethod: %s\nError: %v\n", method, err)
        return err
    }
    fmt.Printf("=== gRPC Response ===\nMethod: %s\nBody: %+v\n", method, reply)
    return nil
}

func main() {
    ctx := context.Background()

    // 创建带日志拦截器的gRPC客户端
    client, err := serviceusage.NewClient(ctx,
        option.WithGRPCDialOption(grpc.WithUnaryInterceptor(grpcLoggingInterceptor)),
        // 生产环境无需此配置,默认会使用安全凭证
        // option.WithGRPCDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
    )
    if err != nil {
        panic(err)
    }
    defer client.Close()

    // 调用API列出已启用服务
    resp, err := client.ListServices(ctx, &serviceusagepb.ListServicesRequest{
        Parent: "projects/你的项目ID",
        Filter: "state:ENABLED",
    })
    if err != nil {
        panic(err)
    }

    // 处理返回结果...
}

三、无需自定义Transport的日志启用方案

Google Cloud Go SDK内置了日志能力,无需自定义Transport或拦截器,直接通过环境变量或内置配置即可开启:

方法1:通过环境变量快速启用日志

  • REST/HTTP客户端:设置GOOGLE_API_GO_EXPERIMENTAL_LOGGING=1,SDK会自动打印HTTP请求响应的完整细节(包括URL、Headers、Body):
    export GOOGLE_API_GO_EXPERIMENTAL_LOGGING=1
    go run 你的程序.go
    
  • gRPC客户端:设置以下两个环境变量,开启gRPC级别的请求日志:
    export GRPC_GO_LOG_SEVERITY_LEVEL=info
    export GRPC_GO_LOG_VERBOSITY_LEVEL=2
    go run 你的程序.go
    

方法2:集成自定义日志库

如果需要将日志接入自己的日志系统(如Zap、Glog),可以通过option.WithLogger将SDK日志定向到自定义日志器:

import (
    "context"
    "go.uber.org/zap"
    serviceusage "google.golang.org/api/serviceusage/v1"
    "google.golang.org/api/option"
    "google.golang.org/api/support/logging"
)

func main() {
    ctx := context.Background()
    zapLogger, _ := zap.NewProduction()
    defer zapLogger.Sync()

    // 将SDK日志定向到Zap日志器
    client, err := serviceusage.NewClient(ctx,
        option.WithLogger(logging.NewGoogleLogger(zapLogger.Sugar())),
    )
    if err != nil {
        panic(err)
    }
    defer client.Close()

    // 调用API...
}

内容的提问来源于stack exchange,提问作者Radek Simko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 10:05:56