diff --git a/api/examples_test.go b/api/examples_test.go index edbff240..01853c6d 100644 --- a/api/examples_test.go +++ b/api/examples_test.go @@ -11,6 +11,7 @@ import ( "time" "github.com/influxdata/influxdb-client-go/v2/api" + apiHttp "github.com/influxdata/influxdb-client-go/v2/api/http" "github.com/influxdata/influxdb-client-go/v2/api/write" "github.com/influxdata/influxdb-client-go/v2/domain" influxdb2 "github.com/influxdata/influxdb-client-go/v2/internal/examples" @@ -123,7 +124,7 @@ func ExampleWriteAPI_errors() { go func() { for err := range errorsCh { fmt.Printf("write error: %s\n", err.Error()) - fmt.Printf("trace-id: %s\n", err.(*write.Error).GetHeader("Trace-ID")) + fmt.Printf("trace-id: %s\n", err.(*apiHttp.Error).Header.Get("Trace-ID")) } }() // write some points diff --git a/api/write/error.go b/api/write/error.go deleted file mode 100644 index f8c11865..00000000 --- a/api/write/error.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2020-2024 InfluxData, Inc. All rights reserved. -// Use of this source code is governed by MIT -// license that can be found in the LICENSE file. - -package write - -import ( - "errors" - "fmt" - "github.com/influxdata/influxdb-client-go/v2/api/http" - iHttp "net/http" - "net/textproto" -) - -// Error wraps an error that may have occurred during a write call. Most often this will be an http.Error. -type Error struct { - origin error - message string -} - -// NewError returns a new created Error instance wrapping the original error. -func NewError(origin error, message string) *Error { - return &Error{ - origin: origin, - message: message, - } -} - -// Error fulfills the error interface -func (e *Error) Error() string { - return fmt.Sprintf("%s:\n %s", e.message, e.origin) -} - -func (e *Error) Unwrap() error { - return e.origin -} - -// HTTPHeader returns the Header of a wrapped http.Error. If the original error is not http.Error returns standard error. -func (e *Error) HTTPHeader() (iHttp.Header, error) { - var err *http.Error - ok := errors.As(e.origin, &err) - if ok { - return err.Header, nil - } - return nil, fmt.Errorf(fmt.Sprintf("Origin error: (%s) is not of type *http.Error.\n", e.origin.Error())) -} - -// GetHeaderValues returns the values from a Header key. If original error is not http.Error return standard error. -func (e *Error) GetHeaderValues(key string) ([]string, error) { - var err *http.Error - if errors.As(e.origin, &err) { - return err.Header.Values(textproto.CanonicalMIMEHeaderKey(key)), nil - } - return nil, fmt.Errorf(fmt.Sprintf("Origin error: (%s) is not of type http.Header.\n", e.origin.Error())) -} - -// GetHeader returns the first value from a header key. If origin is not http.Error or if no match is found returns "". -func (e *Error) GetHeader(key string) string { - var err *http.Error - if errors.As(e.origin, &err) { - return err.Header.Get(textproto.CanonicalMIMEHeaderKey(key)) - } - return "" -} diff --git a/api/write/error_test.go b/api/write/error_test.go deleted file mode 100644 index 6d433532..00000000 --- a/api/write/error_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2020-2024 InfluxData, Inc. All rights reserved. -// Use of this source code is governed by MIT -// license that can be found in the LICENSE file. - -package write - -import ( - "errors" - "fmt" - "github.com/influxdata/influxdb-client-go/v2/api/http" - "github.com/stretchr/testify/assert" - ihttp "net/http" - "testing" -) - -func TestNewErrorNotHttpError(t *testing.T) { - err := NewError(fmt.Errorf("origin error"), "error message") - var errTest *http.Error - assert.False(t, errors.As(err, &errTest)) - header, okh := err.HTTPHeader() - assert.Nil(t, header) - assert.Error(t, okh) - values, okv := err.GetHeaderValues("Date") - assert.Nil(t, values) - assert.Error(t, okv) - assert.Equal(t, "", err.GetHeader("Date")) - assert.Equal(t, "error message:\n origin error", err.Error()) -} - -func TestNewErrorHttpError(t *testing.T) { - header := ihttp.Header{ - "Date": []string{"2024-08-07T12:00:00.009"}, - "Content-Length": []string{"12"}, - "Content-Type": []string{"application/json", "encoding UTF-8"}, - "X-Test-Value1": []string{"SaturnV"}, - "X-Test-Value2": []string{"Apollo11"}, - "Retry-After": []string{"2044"}, - "Trace-Id": []string{"123456789ABCDEF0"}, - } - - err := NewError(&http.Error{ - StatusCode: ihttp.StatusBadRequest, - Code: "bad request", - Message: "this is just a test", - Err: nil, - RetryAfter: 2044, - Header: header, - }, "should be httpError") - - var errTest *http.Error - assert.True(t, errors.As(err.Unwrap(), &errTest)) - header, okh := err.HTTPHeader() - assert.NotNil(t, header) - assert.Nil(t, okh) - date, okd := err.GetHeaderValues("Date") - assert.Equal(t, []string{"2024-08-07T12:00:00.009"}, date) - assert.Nil(t, okd) - cType, okc := err.GetHeaderValues("Content-Type") - assert.Equal(t, []string{"application/json", "encoding UTF-8"}, cType) - assert.Nil(t, okc) - assert.Equal(t, "2024-08-07T12:00:00.009", err.GetHeader("Date")) - assert.Equal(t, "SaturnV", err.GetHeader("X-Test-Value1")) - assert.Equal(t, "Apollo11", err.GetHeader("X-Test-Value2")) - assert.Equal(t, "123456789ABCDEF0", err.GetHeader("Trace-Id")) - assert.Equal(t, "should be httpError:\n bad request: this is just a test", err.Error()) -} diff --git a/api/write_test.go b/api/write_test.go index 034a8f71..4fda86bd 100644 --- a/api/write_test.go +++ b/api/write_test.go @@ -294,15 +294,13 @@ func TestWriteApiErrorHeaders(t *testing.T) { for i := 0; i < 3; i++ { recErr = <-errCh assert.NotNil(t, recErr, "errCh should not run out of values") - header, okh := recErr.(*write.Error).HTTPHeader() - assert.Nil(t, okh) - assert.Len(t, header, 6) - assert.NotEqual(t, "", recErr.(*write.Error).GetHeader("Date")) - assert.NotEqual(t, "", recErr.(*write.Error).GetHeader("Content-Length")) - assert.NotEqual(t, "", recErr.(*write.Error).GetHeader("Content-Type")) - assert.Equal(t, strconv.Itoa(i+1), recErr.(*write.Error).GetHeader("X-Call-Count")) - assert.Equal(t, "Not All Correct", recErr.(*write.Error).GetHeader("X-Test-Val1")) - assert.Equal(t, "Atlas LV-3B", recErr.(*write.Error).GetHeader("X-Test-Val2")) + assert.Len(t, recErr.(*http.Error).Header, 6) + assert.NotEqual(t, "", recErr.(*http.Error).Header.Get("Date")) + assert.NotEqual(t, "", recErr.(*http.Error).Header.Get("Content-Length")) + assert.NotEqual(t, "", recErr.(*http.Error).Header.Get("Content-Type")) + assert.Equal(t, strconv.Itoa(i+1), recErr.(*http.Error).Header.Get("X-Call-Count")) + assert.Equal(t, "Not All Correct", recErr.(*http.Error).Header.Get("X-Test-Val1")) + assert.Equal(t, "Atlas LV-3B", recErr.(*http.Error).Header.Get("X-Test-Val2")) } wg.Done() }() diff --git a/internal/write/service.go b/internal/write/service.go index 4aa9b2ed..44ddf1c1 100644 --- a/internal/write/service.go +++ b/internal/write/service.go @@ -210,7 +210,10 @@ func (w *Service) HandleWrite(ctx context.Context, batch *Batch) error { } log.Error(logMessage) } - return write.NewError(perror, fmt.Sprintf("write failed (retry attempts %d)", batchToWrite.RetryAttempts)) + log.Errorf("Write failed (retry attempts %d): Status Code %d", + batchToWrite.RetryAttempts, + perror.StatusCode) + return perror } } diff --git a/internal/write/service_test.go b/internal/write/service_test.go index 8638c82f..d751339a 100644 --- a/internal/write/service_test.go +++ b/internal/write/service_test.go @@ -339,7 +339,7 @@ func TestMaxRetryTime(t *testing.T) { err = srv.HandleWrite(ctx, b) require.NotNil(t, err) // 1st Batch expires and writing 2nd trows error - assert.Equal(t, "write failed (retry attempts 1):\n Unexpected status code 429", err.Error()) + assert.Equal(t, "Unexpected status code 429", err.Error()) assert.Equal(t, 1, srv.retryQueue.list.Len()) //wait until remaining accumulated retryDelay has passed, because there hasn't been a successful write yet @@ -715,7 +715,7 @@ func TestHttpErrorHeaders(t *testing.T) { write.DefaultOptions()) err := svc.HandleWrite(context.Background(), NewBatch("1", 20)) assert.Error(t, err) - assert.Equal(t, "write failed (retry attempts 0):\n 400 Bad Request: { \"code\": \"bad request\", \"message\": \"test header\" }", err.Error()) - assert.Equal(t, "Not All Correct", err.(*write.Error).GetHeader("X-Test-Val1")) - assert.Equal(t, "Atlas LV-3B", err.(*write.Error).GetHeader("X-Test-Val2")) + assert.Equal(t, "400 Bad Request: { \"code\": \"bad request\", \"message\": \"test header\" }", err.Error()) + assert.Equal(t, "Not All Correct", err.(*http.Error).Header.Get("X-Test-Val1")) + assert.Equal(t, "Atlas LV-3B", err.(*http.Error).Header.Get("X-Test-Val2")) }