Skip to content

Commit 9b6c47c

Browse files
authored
docs: add a debug.md (#7220)
This is a doc that can grow overtime. It is meant to be a resource we can share with our users when they open issues and are trying to track down bugs.
1 parent 1026dc7 commit 9b6c47c

File tree

1 file changed

+162
-0
lines changed

1 file changed

+162
-0
lines changed

debug.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Debugging tips and tricks
2+
3+
While working with the Go Client libraries you may run into some situations
4+
where you need a deeper level of understanding about what is going on in order
5+
to solve your problem. Here are some tips and tricks that you can use in these
6+
cases. *Note* that many of the tips in this document will have a performance
7+
impact and are therefore not recommended for sustained production use. Use these
8+
tips locally or in production for a *limited time* to help get a better
9+
understanding of what is going on.
10+
11+
## HTTP based clients
12+
13+
All of our auto-generated clients have a constructor to create a client that
14+
uses HTTP/JSON instead of gRPC. Additionally a couple of our hand-written
15+
clients like Storage and Bigquery are also HTTP based. Here are some tips for
16+
debugging these clients.
17+
18+
### Try setting Go's HTTP debug variable
19+
20+
Try setting the following environment variable for verbose Go HTTP logging:
21+
GODEBUG=http2debug=1. To read more about this feature please see the godoc for
22+
[net/http](https://pkg.go.dev/net/http).
23+
24+
*WARNING*: Enabling this debug variable will log headers and payloads which may
25+
contain private information.
26+
27+
### Add in your own logging with an HTTP middleware
28+
29+
You may want to add in your own logging around HTTP requests. One way to do this
30+
is to register a custom HTTP client with a logging transport built in. Here is
31+
an example of how you would do this with the storage client.
32+
33+
*WARNING*: Adding this middleware will log headers and payloads which may
34+
contain private information.
35+
36+
```go
37+
package main
38+
39+
import (
40+
"context"
41+
"fmt"
42+
"log"
43+
"net/http"
44+
"net/http/httputil"
45+
46+
"cloud.google.com/go/storage"
47+
"google.golang.org/api/iterator"
48+
"google.golang.org/api/option"
49+
htransport "google.golang.org/api/transport/http"
50+
)
51+
52+
type loggingRoundTripper struct {
53+
rt http.RoundTripper
54+
}
55+
56+
func (d loggingRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
57+
// Will create a dump of the request and body.
58+
dump, err := httputil.DumpRequest(r, true)
59+
if err != nil {
60+
log.Println("error dumping request")
61+
}
62+
log.Printf("%s", dump)
63+
return d.rt.RoundTrip(r)
64+
}
65+
66+
func main() {
67+
ctx := context.Background()
68+
69+
// Create a transport with authentication built-in detected with
70+
// [ADC](https://google.aip.dev/auth/4110). Note you will have to pass any
71+
// required scoped for the client you are using.
72+
trans, err := htransport.NewTransport(ctx,
73+
http.DefaultTransport,
74+
option.WithScopes(storage.ScopeFullControl),
75+
)
76+
if err != nil {
77+
log.Fatal(err)
78+
}
79+
80+
// Embed customized transport into an HTTP client.
81+
hc := &http.Client{
82+
Transport: loggingRoundTripper{rt: trans},
83+
}
84+
85+
// Supply custom HTTP client for use by the library.
86+
client, err := storage.NewClient(ctx, option.WithHTTPClient(hc))
87+
if err != nil {
88+
log.Fatal(err)
89+
}
90+
defer client.Close()
91+
// Use the client
92+
}
93+
```
94+
95+
## gRPC based clients
96+
97+
### Try setting grpc-go's debug variables
98+
99+
Try setting the following environment variables for grpc-go:
100+
`GRPC_GO_LOG_VERBOSITY_LEVEL=99` `GRPC_GO_LOG_SEVERITY_LEVEL=info`. These are
101+
good for diagnosing connection level failures. For more information please see
102+
[grpc-go's debug documentation](https://pkg.go.dev/google.golang.org/grpc/examples/features/debugging#section-readme).
103+
104+
### Add in your own logging with a gRPC interceptors
105+
106+
You may want to add in your own logging around gRPC requests. One way to do this
107+
is to register a custom interceptor that adds logging. Here is
108+
an example of how you would do this with the secretmanager client. Note this
109+
example registers a UnaryClientInterceptor but you may want/need to register
110+
a StreamClientInterceptor instead-of/as-well depending on what kinds of
111+
RPCs you are calling.
112+
113+
*WARNING*: Adding this interceptor will log metadata and payloads which may
114+
contain private information.
115+
116+
```go
117+
package main
118+
119+
import (
120+
"context"
121+
"log"
122+
123+
secretmanager "cloud.google.com/go/secretmanager/apiv1"
124+
"google.golang.org/api/option"
125+
"google.golang.org/grpc"
126+
"google.golang.org/grpc/metadata"
127+
"google.golang.org/protobuf/encoding/protojson"
128+
"google.golang.org/protobuf/reflect/protoreflect"
129+
)
130+
131+
func loggingUnaryInterceptor() grpc.UnaryClientInterceptor {
132+
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
133+
err := invoker(ctx, method, req, reply, cc, opts...)
134+
log.Printf("Invoked method: %v", method)
135+
md, ok := metadata.FromOutgoingContext(ctx)
136+
if ok {
137+
log.Println("Metadata:")
138+
for k, v := range md {
139+
log.Printf("Key: %v, Value: %v", k, v)
140+
}
141+
}
142+
reqb, merr := protojson.Marshal(req.(protoreflect.ProtoMessage))
143+
if merr == nil {
144+
log.Printf("Request: %s", reqb)
145+
}
146+
return err
147+
}
148+
}
149+
150+
func main() {
151+
ctx := context.Background()
152+
// Supply custom gRPC interceptor for use by the client.
153+
client, err := secretmanager.NewClient(ctx,
154+
option.WithGRPCDialOption(grpc.WithUnaryInterceptor(loggingUnaryInterceptor())),
155+
)
156+
if err != nil {
157+
log.Fatal(err)
158+
}
159+
defer client.Close()
160+
// Use the client
161+
}
162+
```

0 commit comments

Comments
 (0)