Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 36 additions & 15 deletions internal/requests/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,24 +216,22 @@ func (c *Client) Do(p *RequestParams) (*HTTPResponse, error) {
c.Logger.Info("############### THIS IS A DRY-RUN ###############")
c.Logger.Info("the request would have been sent to: %s", req.URL)

// Check the content type to determine what to log
contentType := req.Header.Get("Content-Type")
if strings.Contains(contentType, "multipart/form-data") {
// Log only the JSON fields for multipart/form-data
c.Logger.Info("this is the payload data that would be sent in a real run:")
for key, value := range jsonFields {
c.Logger.Info("Field: %s, Value: %+v", key, string(value.([]byte)))
}
} else if req.Body != nil {
// For non-multipart requests, log the full JSON body
reqBody, err := io.ReadAll(req.Body)
if err != nil {
return nil, fmt.Errorf("failed to read request body to %s : %v", req.URL, err)
}
c.Logger.Info("this is the payload that would be sent in a real run: \n %+v", string(reqBody))
// log the payload
err := c.PayloadOutput(req, jsonFields, "this is the payload that would be sent in a real run:")
if err != nil {
return nil, err
}
return nil, nil
} else {
if c.Debug && req.Body != nil {
// log the payload
c.Logger.Info("############### PAYLOAD ###############")
c.Logger.Info("payload sent to: %s", req.URL)
err := c.PayloadOutput(req, jsonFields, "this is the payload being sent:")
if err != nil {
c.Logger.Error("failed to log payload: %v \nContinuing with the request...", err)
}
}
resp, err := c.HttpClient.Do(req)
if err != nil {
// err from retryable client is detailed enough
Expand Down Expand Up @@ -279,3 +277,26 @@ func (c *Client) Do(p *RequestParams) (*HTTPResponse, error) {
return &HTTPResponse{string(body), resp}, nil
}
}

func (c *Client) PayloadOutput(req *http.Request, jsonFields map[string]interface{}, message string) error {
// Check the content type to determine what to log
contentType := req.Header.Get("Content-Type")
if strings.Contains(contentType, "multipart/form-data") {
// Log only the JSON fields for multipart/form-data
c.Logger.Info(message)
for key, value := range jsonFields {
c.Logger.Info("Field: %s, Value: %+v", key, string(value.([]byte)))
}
} else if req.Body != nil {
// For non-multipart requests, log the full JSON body
// Create a copy of the body to avoid consuming the original stream
bodyBytes, err := io.ReadAll(req.Body)
if err != nil {
return fmt.Errorf("failed to read request body to %s : %v", req.URL, err)
}
// Restore the body for the actual request
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
c.Logger.Info("%s \n %+v", message, string(bodyBytes))
}
return nil
}
57 changes: 57 additions & 0 deletions internal/requests/requests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,63 @@ func (suite *RequestsTestSuite) TestDo() {
}
}

func (suite *RequestsTestSuite) TestDebugPayloadOutput() {
for _, t := range []struct {
name string
params *RequestParams
wantError bool
expectedLog string
expectedErrorMsg string
expectedBody string
}{
{
name: "PUT request with debug logs payload",
params: &RequestParams{
Method: http.MethodPut,
URL: "http://localhost:8001/api/v2/environments/docs-cmd-test-user-shared",
DryRun: false,
Token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6ImNkNzg4OTg5In0.e8i_lA_QrEhFncb05Xw6E_tkCHU9QfcY4OLTVUCHffY",
Payload: struct {
Name string `json:"name"`
Type string `json:"type"`
Description string `json:"description"`
IncludeScaling bool `json:"include_scaling"`
RequireProvenance bool `json:"require_provenance"`
}{
Name: "test-environment",
Type: "K8S",
Description: "test-environment",
IncludeScaling: true,
RequireProvenance: true,
},
},
expectedLog: "############### PAYLOAD ###############\npayload sent to: http://localhost:8001/api/v2/environments/docs-cmd-test-user-shared\nthis is the payload being sent: \n {\n \"name\": \"test-environment\",\n \"type\": \"K8S\",\n \"description\": \"test-environment\",\n \"include_scaling\": true,\n \"require_provenance\": true\n}\n",
},
{
name: "GET request with debug does not log non-existent payload",
params: &RequestParams{
Method: http.MethodGet,
URL: "https://app.kosli.com/api/v2/environments/cyber-dojo",
DryRun: false,
},
},
} {
suite.Suite.Run(t.name, func() {
buf := new(bytes.Buffer)
client, err := NewKosliClient("", 1, true, logger.NewLogger(buf, buf, false))
require.NoError(suite.Suite.T(), err)
resp, err := client.Do(t.params)
require.NoError(suite.Suite.T(), err)

output := buf.String()
require.Equal(suite.Suite.T(), t.expectedLog, output)
if t.expectedBody != "" {
require.Equal(suite.Suite.T(), t.expectedBody, resp.Body)
}
})
}
}

func (suite *RequestsTestSuite) TestCreateMultipartRequestBody() {
for _, t := range []struct {
name string
Expand Down