GithubHelp home page GithubHelp logo

Comments (9)

Jakob3xD avatar Jakob3xD commented on August 17, 2024

Hey, thanks for opening the issue. The use of client.Perform() is not recommended as it skips all the error handling.
The correct way would be following:

func (logger *MyLogger) SendLogEvent(event *MyLogEvent) error {
	// Marshal the struct
	s, err := json.Marshal(event)
	if err != nil {
		return WrapError("failed to marshal log event", err)
	}

	// Do the request
	_, err := logger.client.Index(
		context.Background(),
		opensearchapi.IndexReq{
			Index: logger.logsIndexName,
			Body: bytes.NewReader(s),
		},
	)
	if err != nil {
		return err
	}
	// Success
	return nil
}

from opensearch-go.

merlinz01 avatar merlinz01 commented on August 17, 2024

OK, this morning I'm not getting the errors. We had terrible connectivity yesterday and I think that was causing it. (I think I had changed the settings, see my next comment)

I found where the error was being raised:
/usr/local/go/src/net/http/transfer.go line 391

                        ncopy, err = t.doBodyCopy(w, io.LimitReader(body, t.ContentLength))
			if err != nil {
				return err
			}
			var nextra int64
			nextra, err = t.doBodyCopy(io.Discard, body)
			ncopy += nextra
		}
		if err != nil {
			return err
		}
	}
...
	if !t.ResponseToHEAD && t.ContentLength != -1 && t.ContentLength != ncopy {
		return fmt.Errorf("http: ContentLength=%d with Body length %d",
			t.ContentLength, ncopy)
	}

Seems like not all of the request body was being written yet there were no I/O errors.

Thanks for the info on how to use the API. I have updated my code.

from opensearch-go.

dblock avatar dblock commented on August 17, 2024

@merlinz01 Glad this was helpful. Should we close this?

from opensearch-go.

merlinz01 avatar merlinz01 commented on August 17, 2024

Now I'm getting some of these errors again even though the connectivity has much improved. So far they only show up when I set CompressRequestBody to true. I wonder if there is a bug in the gzipping of the requests.

from opensearch-go.

merlinz01 avatar merlinz01 commented on August 17, 2024

OK, I'm getting it. So when it retries a failed attempt, the second time the request body is an empty bytes.Buffer reader. It seems like it tries to re-read the body on the second attempt, but as it was fully read the first time, the result is zero bytes. It passes this zero-byte buffer to the writer, which writes zero bytes and succeeds, and wonders why only zero bytes were written when the indicated Content-Length is XXX bytes.

if req.Body != nil && req.Body != http.NoBody {
if c.compressRequestBody {
buf, err := c.pooledGzipCompressor.compress(req.Body)
defer c.pooledGzipCompressor.collectBuffer(buf)
if err != nil {
return nil, fmt.Errorf("failed to compress request body: %w", err)
}
req.GetBody = func() (io.ReadCloser, error) {
return io.NopCloser(buf), nil
}
//nolint:errcheck // error is always nil
req.Body, _ = req.GetBody()
req.Header.Set("Content-Encoding", "gzip")
req.ContentLength = int64(buf.Len())
} else if req.GetBody == nil {
if !c.disableRetry || (c.logger != nil && c.logger.RequestBodyEnabled()) {
var buf bytes.Buffer
//nolint:errcheck // ignored as this is only for logging
buf.ReadFrom(req.Body)
req.GetBody = func() (io.ReadCloser, error) {
r := buf
return io.NopCloser(&r), nil
}
//nolint:errcheck // error is always nil
req.Body, _ = req.GetBody()
}
}
}

On line 248, an io.nopCloser for the exact same (possibly already consumed) bytes.Buffer is returned every time req.GetBody is called.

from opensearch-go.

merlinz01 avatar merlinz01 commented on August 17, 2024

Here's how I fixed it:

                        req.GetBody = func() (io.ReadCloser, error) {
				// We have to return a new reader each time so that retries don't read from an already-consumed body.
                                // This does not do any copying of the data.
				return io.NopCloser(bytes.NewReader(buf.Bytes())), nil
			}

The code for non-gzipped bodies (line 261) does a similar thing it by implicitly copying the buf by value before its internal state changes. I would say it is less clear what is happening so maybe we should update it to be similar to this fix.

I can open a PR if you want.

from opensearch-go.

dblock avatar dblock commented on August 17, 2024

I can open a PR if you want.

Most definitely, with tests please.

I think ideally the reader would be rewound only if retry is needed.

from opensearch-go.

merlinz01 avatar merlinz01 commented on August 17, 2024

We could implicitly copy the buffer like is done for non-gzipped bodies but IMHO it's better to be explicit. The second method below only makes two small struct allocations so it's not really a performance question.

                        req.GetBody = func() (io.ReadCloser, error) {
				b := *buf
				return io.NopCloser(&b), nil
			}

vs.

			req.GetBody = func() (io.ReadCloser, error) {
				reader := bytes.NewReader(buf.Bytes())
				return io.NopCloser(reader), nil
			}

from opensearch-go.

merlinz01 avatar merlinz01 commented on August 17, 2024

See #543.
(#542 can be ignored; I committed to the wrong branch.)

from opensearch-go.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.