mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
client: Client.ContainerLogs: close reader on context cancellation
Use a cancelReadCloser to automatically close the reader when the context is cancelled. Consumers are still recommended to manually close the reader, but the cancelReadCloser makes the Close idempotent. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
@@ -30,6 +30,8 @@ type ContainerLogsResult interface {
|
||||
// ContainerLogs returns the logs generated by a container in an [io.ReadCloser].
|
||||
// It's up to the caller to close the stream.
|
||||
//
|
||||
// The underlying [io.ReadCloser] is automatically closed if the context is canceled,
|
||||
//
|
||||
// The stream format on the response uses one of two formats:
|
||||
//
|
||||
// - If the container is using a TTY, there is only a single stream (stdout)
|
||||
@@ -102,30 +104,15 @@ func (cli *Client) ContainerLogs(ctx context.Context, containerID string, option
|
||||
return nil, err
|
||||
}
|
||||
return &containerLogsResult{
|
||||
body: resp.Body,
|
||||
ReadCloser: newCancelReadCloser(ctx, resp.Body),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type containerLogsResult struct {
|
||||
// body must be closed to avoid a resource leak
|
||||
body io.ReadCloser
|
||||
io.ReadCloser
|
||||
}
|
||||
|
||||
var (
|
||||
_ io.ReadCloser = (*containerLogsResult)(nil)
|
||||
_ ContainerLogsResult = (*containerLogsResult)(nil)
|
||||
)
|
||||
|
||||
func (r *containerLogsResult) Read(p []byte) (int, error) {
|
||||
if r == nil || r.body == nil {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return r.body.Read(p)
|
||||
}
|
||||
|
||||
func (r *containerLogsResult) Close() error {
|
||||
if r == nil || r.body == nil {
|
||||
return nil
|
||||
}
|
||||
return r.body.Close()
|
||||
}
|
||||
|
||||
@@ -100,14 +100,14 @@ func TestNetworkLoopbackNat(t *testing.T) {
|
||||
|
||||
poll.WaitOn(t, container.IsStopped(ctx, apiClient, cID))
|
||||
|
||||
body, err := apiClient.ContainerLogs(ctx, cID, client.ContainerLogsOptions{
|
||||
logs, err := apiClient.ContainerLogs(ctx, cID, client.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
defer body.Close()
|
||||
defer logs.Close()
|
||||
|
||||
var b bytes.Buffer
|
||||
_, err = io.Copy(&b, body)
|
||||
_, err = io.Copy(&b, logs)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, is.Equal(msg, strings.TrimSpace(b.String())))
|
||||
|
||||
21
vendor/github.com/moby/moby/client/container_logs.go
generated
vendored
21
vendor/github.com/moby/moby/client/container_logs.go
generated
vendored
@@ -30,6 +30,8 @@ type ContainerLogsResult interface {
|
||||
// ContainerLogs returns the logs generated by a container in an [io.ReadCloser].
|
||||
// It's up to the caller to close the stream.
|
||||
//
|
||||
// The underlying [io.ReadCloser] is automatically closed if the context is canceled,
|
||||
//
|
||||
// The stream format on the response uses one of two formats:
|
||||
//
|
||||
// - If the container is using a TTY, there is only a single stream (stdout)
|
||||
@@ -102,30 +104,15 @@ func (cli *Client) ContainerLogs(ctx context.Context, containerID string, option
|
||||
return nil, err
|
||||
}
|
||||
return &containerLogsResult{
|
||||
body: resp.Body,
|
||||
ReadCloser: newCancelReadCloser(ctx, resp.Body),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type containerLogsResult struct {
|
||||
// body must be closed to avoid a resource leak
|
||||
body io.ReadCloser
|
||||
io.ReadCloser
|
||||
}
|
||||
|
||||
var (
|
||||
_ io.ReadCloser = (*containerLogsResult)(nil)
|
||||
_ ContainerLogsResult = (*containerLogsResult)(nil)
|
||||
)
|
||||
|
||||
func (r *containerLogsResult) Read(p []byte) (int, error) {
|
||||
if r == nil || r.body == nil {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return r.body.Read(p)
|
||||
}
|
||||
|
||||
func (r *containerLogsResult) Close() error {
|
||||
if r == nil || r.body == nil {
|
||||
return nil
|
||||
}
|
||||
return r.body.Close()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user