Skip to content

Commit

Permalink
Implemented new logging system for resty migration
Browse files Browse the repository at this point in the history
  • Loading branch information
ezilber-akamai committed Jul 30, 2024
1 parent a9e3be2 commit 7088c6c
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 0 deletions.
42 changes: 42 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,19 @@ func (c *httpClient) doRequest(ctx context.Context, method, url string, params R
if params.Body != nil {
buf := new(bytes.Buffer)
if err := json.NewEncoder(buf).Encode(params.Body); err != nil {
if c.debug && c.logger != nil {
c.logger.Errorf("failed to encode body: %v", err)
}
return fmt.Errorf("failed to encode body: %w", err)
}
bodyReader = buf
}

req, err := http.NewRequestWithContext(ctx, method, url, bodyReader)
if err != nil {
if c.debug && c.logger != nil {
c.logger.Errorf("failed to create request: %v", err)
}
return fmt.Errorf("failed to create request: %w", err)
}

Expand All @@ -147,26 +153,48 @@ func (c *httpClient) doRequest(ctx context.Context, method, url string, params R
// Apply mutators
for _, mutate := range mutators {
if err := mutate(req); err != nil {
if c.debug && c.logger != nil {
c.logger.Errorf("failed to mutate request: %v", err)
}
return fmt.Errorf("failed to mutate request: %w", err)
}
}

// Log the request if in debug mode
if c.debug && c.logger != nil {
c.logger.Debugf("sending request: %s %s", method, url)
}

// Send the request
resp, err := c.httpClient.Do(req)
if err != nil {
if c.debug && c.logger != nil {
c.logger.Errorf("failed to send request: %v", err)
}
return fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()

// Check for HTTP errors
resp, err = coupleAPIErrorsHTTP(resp, err)
if err != nil {
if c.debug && c.logger != nil {
c.logger.Errorf("received HTTP error: %v", err)
}
return err
}

// Log the response if in debug mode
if c.debug && c.logger != nil {
c.logger.Debugf("received response: %s %s, status: %d", method, url, resp.StatusCode)
}

// Decode the response body
if params.Response != nil {
if err := json.NewDecoder(resp.Body).Decode(params.Response); err != nil {
if c.debug && c.logger != nil {
c.logger.Errorf("failed to decode response: %v", err)
}
return fmt.Errorf("failed to decode response: %w", err)
}
}
Expand Down Expand Up @@ -199,6 +227,20 @@ func (c *Client) SetLogger(logger Logger) *Client {
return c
}

//nolint:unused
func (c *httpClient) httpSetDebug(debug bool) *httpClient {
c.debug = debug

return c
}

//nolint:unused
func (c *httpClient) httpSetLogger(logger httpLogger) *httpClient {
c.logger = logger

return c
}

// OnBeforeRequest adds a handler to the request body to run before the request is sent
func (c *Client) OnBeforeRequest(m func(request *Request) error) {
c.resty.OnBeforeRequest(func(_ *resty.Client, req *resty.Request) error {
Expand Down
2 changes: 2 additions & 0 deletions client_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ type httpClient struct {
cachedEntries map[string]clientCacheEntry
//nolint:unused
cachedEntryLock *sync.RWMutex
//nolint:unused
logger httpLogger
}
72 changes: 72 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,75 @@ func TestDoRequest_MutatorError(t *testing.T) {
t.Fatalf("expected error %q, got: %v", expectedErr, err)
}
}

func TestDoRequestLogging_Success(t *testing.T) {
var logBuffer bytes.Buffer
logger := createLogger()
logger.l.SetOutput(&logBuffer) // Redirect log output to buffer

client := &httpClient{
httpClient: http.DefaultClient,
debug: true,
logger: logger,
}

handler := func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"message":"success"}`))
}
server := httptest.NewServer(http.HandlerFunc(handler))
defer server.Close()

params := RequestParams{
Response: &map[string]string{},
}

err := client.doRequest(context.Background(), http.MethodGet, server.URL, params)
if err != nil {
t.Fatal(cmp.Diff(nil, err))
}

logInfo := logBuffer.String()
expectedLogs := []string{
"DEBUG RESTY sending request: GET " + server.URL,
"DEBUG RESTY received response: GET " + server.URL + ", status: 200",
}

for _, expectedLog := range expectedLogs {
if !strings.Contains(logInfo, expectedLog) {
t.Fatalf("expected log %q not found in logs", expectedLog)
}
}
}

func TestDoRequestLogging_Error(t *testing.T) {
var logBuffer bytes.Buffer
logger := createLogger()
logger.l.SetOutput(&logBuffer) // Redirect log output to buffer

client := &httpClient{
httpClient: http.DefaultClient,
debug: true,
logger: logger,
}

params := RequestParams{
Body: map[string]interface{}{
"invalid": func() {},
},
}

err := client.doRequest(context.Background(), http.MethodPost, "http://example.com", params)
expectedErr := "failed to encode body"
if err == nil || !strings.Contains(err.Error(), expectedErr) {
t.Fatalf("expected error %q, got: %v", expectedErr, err)
}

logInfo := logBuffer.String()
expectedLog := "ERROR RESTY failed to encode body"

if !strings.Contains(logInfo, expectedLog) {
t.Fatalf("expected log %q not found in logs", expectedLog)
}
}
51 changes: 51 additions & 0 deletions logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package linodego

import (
"log"
"os"
)

//nolint:unused
type httpLogger interface {
Errorf(format string, v ...interface{})
Warnf(format string, v ...interface{})
Debugf(format string, v ...interface{})
}

//nolint:unused
type logger struct {
l *log.Logger
}

//nolint:unused
func createLogger() *logger {
l := &logger{l: log.New(os.Stderr, "", log.Ldate|log.Lmicroseconds)}
return l
}

//nolint:unused
var _ httpLogger = (*logger)(nil)

//nolint:unused
func (l *logger) Errorf(format string, v ...interface{}) {
l.output("ERROR RESTY "+format, v...)
}

//nolint:unused
func (l *logger) Warnf(format string, v ...interface{}) {
l.output("WARN RESTY "+format, v...)
}

//nolint:unused
func (l *logger) Debugf(format string, v ...interface{}) {
l.output("DEBUG RESTY "+format, v...)
}

//nolint:unused
func (l *logger) output(format string, v ...interface{}) { //nolint:goprintffuncname
if len(v) == 0 {
l.l.Print(format)
return
}
l.l.Printf(format, v...)
}

0 comments on commit 7088c6c

Please sign in to comment.