diff --git a/estransport/logger.go b/estransport/logger.go index 4f0af98a3a..fac880e5f0 100644 --- a/estransport/logger.go +++ b/estransport/logger.go @@ -8,6 +8,7 @@ import ( "bufio" "bytes" "encoding/json" + "errors" "fmt" "io" "io/ioutil" @@ -18,7 +19,12 @@ import ( "time" ) -var debugLogger DebuggingLogger +var ( + debugLogger DebuggingLogger + errRequestEmpty = errors.New("request is empty") + errRequestURLEmpty = errors.New("request URL is empty") + errResponseEmpty = errors.New("response is empty") +) // Logger defines an interface for logging request and response. // @@ -80,6 +86,12 @@ type debuggingLogger struct { // LogRoundTrip prints the information about request and response. // func (l *TextLogger) LogRoundTrip(req *http.Request, res *http.Response, err error, start time.Time, dur time.Duration) error { + if req == nil { + return errRequestEmpty + } + if req.URL == nil { + return errRequestURLEmpty + } fmt.Fprintf(l.Output, "%s %s %s [status:%d request:%s]\n", start.Format(time.RFC3339), req.Method, @@ -87,7 +99,7 @@ func (l *TextLogger) LogRoundTrip(req *http.Request, res *http.Response, err err resStatusCode(res), dur.Truncate(time.Millisecond), ) - if l.RequestBodyEnabled() && req != nil && req.Body != nil && req.Body != http.NoBody { + if l.RequestBodyEnabled() && req.Body != nil && req.Body != http.NoBody { var buf bytes.Buffer if req.GetBody != nil { b, _ := req.GetBody() @@ -118,6 +130,12 @@ func (l *TextLogger) ResponseBodyEnabled() bool { return l.EnableResponseBody } // LogRoundTrip prints the information about request and response. // func (l *ColorLogger) LogRoundTrip(req *http.Request, res *http.Response, err error, start time.Time, dur time.Duration) error { + if req == nil { + return errRequestEmpty + } + if req.URL == nil { + return errRequestURLEmpty + } query, _ := url.QueryUnescape(req.URL.RawQuery) if query != "" { query = "?" + query @@ -128,6 +146,9 @@ func (l *ColorLogger) LogRoundTrip(req *http.Request, res *http.Response, err er color string ) + if res == nil { + return errResponseEmpty + } status = res.Status switch { case res.StatusCode > 0 && res.StatusCode < 300: @@ -152,7 +173,7 @@ func (l *ColorLogger) LogRoundTrip(req *http.Request, res *http.Response, err er dur.Truncate(time.Millisecond), ) - if l.RequestBodyEnabled() && req != nil && req.Body != nil && req.Body != http.NoBody { + if l.RequestBodyEnabled() && req.Body != nil && req.Body != http.NoBody { var buf bytes.Buffer if req.GetBody != nil { b, _ := req.GetBody() @@ -165,7 +186,7 @@ func (l *ColorLogger) LogRoundTrip(req *http.Request, res *http.Response, err er fmt.Fprint(l.Output, "\x1b[0m") } - if l.ResponseBodyEnabled() && res != nil && res.Body != nil && res.Body != http.NoBody { + if l.ResponseBodyEnabled() && res.Body != nil && res.Body != http.NoBody { defer res.Body.Close() var buf bytes.Buffer buf.ReadFrom(res.Body) @@ -193,11 +214,19 @@ func (l *ColorLogger) ResponseBodyEnabled() bool { return l.EnableResponseBody } // LogRoundTrip prints the information about request and response. // func (l *CurlLogger) LogRoundTrip(req *http.Request, res *http.Response, err error, start time.Time, dur time.Duration) error { + if req == nil { + return errRequestEmpty + } + if req.URL == nil { + return errRequestURLEmpty + } + reqURL := req.URL + var b bytes.Buffer var query string qvalues := url.Values{} - for k, v := range req.URL.Query() { + for k, v := range reqURL.Query() { if k == "pretty" { continue } @@ -227,7 +256,7 @@ func (l *CurlLogger) LogRoundTrip(req *http.Request, res *http.Response, err err } b.WriteString(" 'http://localhost:9200") - b.WriteString(req.URL.Path) + b.WriteString(reqURL.Path) b.WriteString("?pretty") if query != "" { fmt.Fprintf(&b, "&%s", query) @@ -252,7 +281,9 @@ func (l *CurlLogger) LogRoundTrip(req *http.Request, res *http.Response, err err b.WriteRune('\n') var status string - status = res.Status + if res != nil { + status = res.Status + } fmt.Fprintf(&b, "# => %s [%s] %s\n", start.UTC().Format(time.RFC3339), status, dur.Truncate(time.Millisecond)) if l.ResponseBodyEnabled() && res != nil && res.Body != nil && res.Body != http.NoBody { @@ -309,6 +340,12 @@ func (l *JSONLogger) LogRoundTrip(req *http.Request, res *http.Response, err err b.Write(v) } + if req == nil { + return errRequestEmpty + } + if req.URL == nil { + return errRequestURLEmpty + } port := req.URL.Port() b.WriteRune('{') @@ -342,7 +379,7 @@ func (l *JSONLogger) LogRoundTrip(req *http.Request, res *http.Response, err err b.WriteString(`{"request":{`) b.WriteString(`"method":`) appendQuote(req.Method) - if l.RequestBodyEnabled() && req != nil && req.Body != nil && req.Body != http.NoBody { + if l.RequestBodyEnabled() && req.Body != nil && req.Body != http.NoBody { var buf bytes.Buffer if req.GetBody != nil { b, _ := req.GetBody() diff --git a/estransport/logger_internal_test.go b/estransport/logger_internal_test.go index cd60cfa7e0..0f020f8ad6 100644 --- a/estransport/logger_internal_test.go +++ b/estransport/logger_internal_test.go @@ -7,6 +7,7 @@ package estransport import ( + "bytes" "encoding/json" "errors" "fmt" @@ -430,6 +431,103 @@ func TestTransportLogger(t *testing.T) { }) } +func TestLoggers(t *testing.T) { + start := time.Now() + dur := time.Second + t.Run("TextLogger req == nil", func(t *testing.T) { + var buff bytes.Buffer + logger := TextLogger{Output: &buff} + err := logger.LogRoundTrip(nil, nil, nil, start, dur) + if !errors.Is(err, errRequestEmpty) { + t.Errorf("Expected error `%s`, got `%v`", errRequestEmpty, err) + } + }) + t.Run("TextLogger req.URL == nil", func(t *testing.T) { + var buff bytes.Buffer + logger := TextLogger{Output: &buff} + req := http.Request{ + Method: http.MethodGet, + } + + err := logger.LogRoundTrip(&req, nil, nil, start, dur) + if !errors.Is(err, errRequestURLEmpty) { + t.Errorf("Expected error `%s`, got `%v`", errRequestURLEmpty, err) + } + }) + t.Run("ColorLogger req == nil", func(t *testing.T) { + var buff bytes.Buffer + logger := ColorLogger{Output: &buff} + err := logger.LogRoundTrip(nil, nil, nil, start, dur) + if !errors.Is(err, errRequestEmpty) { + t.Errorf("Expected error `%s`, got `%v`", errRequestEmpty, err) + } + }) + t.Run("ColorLogger req.URL == nil", func(t *testing.T) { + var buff bytes.Buffer + logger := ColorLogger{Output: &buff} + req := http.Request{ + Method: http.MethodGet, + } + + err := logger.LogRoundTrip(&req, nil, nil, start, dur) + if !errors.Is(err, errRequestURLEmpty) { + t.Errorf("Expected error `%s`, got `%v`", errRequestURLEmpty, err) + } + }) + t.Run("ColorLogger res == nil", func(t *testing.T) { + var buff bytes.Buffer + logger := ColorLogger{Output: &buff} + req, err := http.NewRequest(http.MethodGet, "http:example.com", nil) + if err != nil { + t.Errorf("Unexpected error: %s", err) + } + err = logger.LogRoundTrip(req, nil, nil, start, dur) + if !errors.Is(err, errResponseEmpty) { + t.Errorf("Expected error `%s`, got `%v`", errResponseEmpty, err) + } + }) + t.Run("CurlLogger req == nil", func(t *testing.T) { + var buff bytes.Buffer + logger := CurlLogger{Output: &buff} + err := logger.LogRoundTrip(nil, nil, nil, start, dur) + if !errors.Is(err, errRequestEmpty) { + t.Errorf("Expected error `%s`, got `%v`", errRequestEmpty, err) + } + }) + t.Run("CurlLogger req.URL == nil", func(t *testing.T) { + var buff bytes.Buffer + logger := CurlLogger{Output: &buff} + req := http.Request{ + Method: http.MethodGet, + } + + err := logger.LogRoundTrip(&req, nil, nil, start, dur) + if !errors.Is(err, errRequestURLEmpty) { + t.Errorf("Expected error `%s`, got `%v`", errRequestURLEmpty, err) + } + }) + t.Run("JSONLogger req == nil", func(t *testing.T) { + var buff bytes.Buffer + logger := JSONLogger{Output: &buff} + err := logger.LogRoundTrip(nil, nil, nil, start, dur) + if !errors.Is(err, errRequestEmpty) { + t.Errorf("Expected error `%s`, got `%v`", errRequestEmpty, err) + } + }) + t.Run("JSONLogger req.URL == nil", func(t *testing.T) { + var buff bytes.Buffer + logger := JSONLogger{Output: &buff} + req := http.Request{ + Method: http.MethodGet, + } + + err := logger.LogRoundTrip(&req, nil, nil, start, dur) + if !errors.Is(err, errRequestURLEmpty) { + t.Errorf("Expected error `%s`, got `%v`", errRequestURLEmpty, err) + } + }) +} + func TestDebuggingLogger(t *testing.T) { logger := &debuggingLogger{Output: ioutil.Discard}