From 9faf881efa5101cd2a6b0e9fc6e6cd8329b3501d Mon Sep 17 00:00:00 2001 From: Fendy Date: Tue, 28 Jul 2026 23:57:24 +0800 Subject: [PATCH] feat: HTTP debug logging in client.do() --- internal/provider/rainyun/client.go | 20 +++++++++++++++++++- internal/provider/rainyun/client_test.go | 4 ++-- internal/provider/rainyun/rainyun.go | 2 +- internal/provider/rainyun/server_test.go | 6 +++--- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/internal/provider/rainyun/client.go b/internal/provider/rainyun/client.go index 2f792c7..f3662d2 100644 --- a/internal/provider/rainyun/client.go +++ b/internal/provider/rainyun/client.go @@ -8,6 +8,7 @@ import ( "io" "net/http" "net/url" + "os" "time" ) @@ -17,9 +18,10 @@ type client struct { httpClient *http.Client baseURL string apiKey string + debug bool } -func newClient(endpoint, apiKey string) *client { +func newClient(endpoint, apiKey string, debug bool) *client { if endpoint == "" { endpoint = defaultEndpoint } @@ -27,6 +29,7 @@ func newClient(endpoint, apiKey string) *client { httpClient: &http.Client{Timeout: 30 * time.Second}, baseURL: endpoint, apiKey: apiKey, + debug: debug, } } @@ -85,14 +88,23 @@ func (c *client) do(ctx context.Context, method, path string, body, result any, } var bodyReader io.Reader + var bodyBytes []byte if body != nil { b, err := json.Marshal(body) if err != nil { return fmt.Errorf("marshal request: %w", err) } + bodyBytes = b bodyReader = bytes.NewReader(b) } + if c.debug { + fmt.Fprintf(os.Stderr, "[debug] > %s %s\n", method, u) + if bodyBytes != nil { + fmt.Fprintf(os.Stderr, "[debug] %s\n", bodyBytes) + } + } + req, err := http.NewRequestWithContext(ctx, method, u, bodyReader) if err != nil { return fmt.Errorf("create request: %w", err) @@ -101,6 +113,7 @@ func (c *client) do(ctx context.Context, method, path string, body, result any, req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") + start := time.Now() resp, err := c.httpClient.Do(req) if err != nil { return fmt.Errorf("request failed: %w", err) @@ -112,6 +125,11 @@ func (c *client) do(ctx context.Context, method, path string, body, result any, return fmt.Errorf("read response: %w", err) } + if c.debug { + fmt.Fprintf(os.Stderr, "[debug] < %d %s %s\n", resp.StatusCode, http.StatusText(resp.StatusCode), time.Since(start).Round(time.Millisecond)) + fmt.Fprintf(os.Stderr, "[debug] %s\n", respBody) + } + var apiResp apiResponse if err := json.Unmarshal(respBody, &apiResp); err == nil { // Rainyun uses code:200 and code:0 both as success indicators diff --git a/internal/provider/rainyun/client_test.go b/internal/provider/rainyun/client_test.go index 13ee17c..bf1e890 100644 --- a/internal/provider/rainyun/client_test.go +++ b/internal/provider/rainyun/client_test.go @@ -16,7 +16,7 @@ func TestClientAuthHeader(t *testing.T) { })) defer srv.Close() - c := newClient(srv.URL, "sk-test") + c := newClient(srv.URL, "sk-test", false) var result struct { ID int `json:"id"` Name string `json:"name"` @@ -40,7 +40,7 @@ func TestClientAPIError(t *testing.T) { })) defer srv.Close() - c := newClient(srv.URL, "sk-test") + c := newClient(srv.URL, "sk-test", false) var result any err := c.get(context.Background(), "/error", &result) if err == nil { diff --git a/internal/provider/rainyun/rainyun.go b/internal/provider/rainyun/rainyun.go index e827d20..f6563bc 100644 --- a/internal/provider/rainyun/rainyun.go +++ b/internal/provider/rainyun/rainyun.go @@ -21,7 +21,7 @@ type Rainyun struct { // New creates a Rainyun provider from config. func New(cfg provider.ProviderConfig) (provider.Provider, error) { - c := newClient(cfg.Endpoint, cfg.APIKey) + c := newClient(cfg.Endpoint, cfg.APIKey, cfg.Debug) r := &Rainyun{client: c} r.server = &ServerService{client: c} r.domain = &DomainService{client: c} diff --git a/internal/provider/rainyun/server_test.go b/internal/provider/rainyun/server_test.go index 0a45faa..3b7668a 100644 --- a/internal/provider/rainyun/server_test.go +++ b/internal/provider/rainyun/server_test.go @@ -36,7 +36,7 @@ func TestServerList(t *testing.T) { })) defer srv.Close() - rain := &Rainyun{client: newClient(srv.URL, "sk-test")} + rain := &Rainyun{client: newClient(srv.URL, "sk-test", false)} svc := rain.Server() servers, err := svc.List(context.Background()) if err != nil { @@ -66,7 +66,7 @@ func TestServerStart(t *testing.T) { })) defer srv.Close() - rain := &Rainyun{client: newClient(srv.URL, "sk-test")} + rain := &Rainyun{client: newClient(srv.URL, "sk-test", false)} err := rain.Server().Start(context.Background(), "12001") if err != nil { t.Fatalf("Start() error: %v", err) @@ -83,7 +83,7 @@ func TestServerVNC(t *testing.T) { })) defer srv.Close() - rain := &Rainyun{client: newClient(srv.URL, "sk-test")} + rain := &Rainyun{client: newClient(srv.URL, "sk-test", false)} url, err := rain.Server().GetVNC(context.Background(), "12001") if err != nil { t.Fatalf("GetVNC() error: %v", err)