cli: add --debug-http flag (#7192)

This makes it easier to help debug client issues.
This commit is contained in:
Ammar Bandukwala
2023-04-19 11:07:53 -05:00
committed by GitHub
parent f94ac55f02
commit 2b9d12828a
2 changed files with 46 additions and 0 deletions
+13
View File
@@ -364,6 +364,13 @@ func (r *RootCmd) Command(subcommands []*clibase.Cmd) (*clibase.Cmd, error) {
Value: clibase.BoolOf(&r.verbose),
Group: globalGroup,
},
{
Flag: "debug-http",
Description: "Debug codersdk HTTP requests.",
Value: clibase.BoolOf(&r.debugHTTP),
Group: globalGroup,
Hidden: true,
},
{
Flag: config.FlagName,
Env: "CODER_CONFIG_DIR",
@@ -412,6 +419,7 @@ type RootCmd struct {
forceTTY bool
noOpen bool
verbose bool
debugHTTP bool
noVersionCheck bool
noFeatureWarning bool
@@ -464,6 +472,11 @@ func (r *RootCmd) InitClient(client *codersdk.Client) clibase.MiddlewareFunc {
client.SetSessionToken(r.token)
if r.debugHTTP {
client.PlainLogger = os.Stderr
client.LogBodies = true
}
// We send these requests in parallel to minimize latency.
var (
versionErr = make(chan error)
+33
View File
@@ -10,6 +10,7 @@ import (
"mime"
"net"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"sync"
@@ -90,6 +91,10 @@ type Client struct {
// LogBodies can be enabled to print request and response bodies to the logger.
LogBodies bool
// PlainLogger may be set to log HTTP traffic in a human-readable form.
// It uses the LogBodies option.
PlainLogger io.Writer
// Trace can be enabled to propagate tracing spans to the Coder API.
// This is useful for tracking a request end-to-end.
Trace bool
@@ -109,6 +114,16 @@ func (c *Client) SetSessionToken(token string) {
c.sessionToken = token
}
func prefixLines(prefix, s []byte) []byte {
ss := bytes.NewBuffer(make([]byte, 0, len(s)*2))
for _, line := range bytes.Split(s, []byte("\n")) {
_, _ = ss.Write(prefix)
_, _ = ss.Write(line)
_ = ss.WriteByte('\n')
}
return ss.Bytes()
}
// Request performs a HTTP request with the body provided. The caller is
// responsible for closing the response body.
func (c *Client) Request(ctx context.Context, method, path string, body interface{}, opts ...RequestOption) (*http.Response, error) {
@@ -155,6 +170,15 @@ func (c *Client) Request(ctx context.Context, method, path string, body interfac
return nil, xerrors.Errorf("create request: %w", err)
}
if c.PlainLogger != nil {
out, err := httputil.DumpRequest(req, c.LogBodies)
if err != nil {
return nil, xerrors.Errorf("dump request: %w", err)
}
out = prefixLines([]byte("http --> "), out)
_, _ = c.PlainLogger.Write(out)
}
tokenHeader := c.SessionTokenHeader
if tokenHeader == "" {
tokenHeader = SessionTokenHeader
@@ -192,6 +216,15 @@ func (c *Client) Request(ctx context.Context, method, path string, body interfac
return nil, err
}
if c.PlainLogger != nil {
out, err := httputil.DumpResponse(resp, c.LogBodies)
if err != nil {
return nil, xerrors.Errorf("dump response: %w", err)
}
out = prefixLines([]byte("http <-- "), out)
_, _ = c.PlainLogger.Write(out)
}
span.SetAttributes(httpconv.ClientResponse(resp)...)
span.SetStatus(httpconv.ClientStatus(resp.StatusCode))