Repository: moby/moby
File: client/container_stats.go (Go)

Code before:
// If streaming is disabled, the stream contains a single record.
//
// The OSType field reports the daemon's operating system, allowing platform-specific
// handling of the response.
type ContainerStatsResult struct {
	Body   io.ReadCloser
	OSType string // TODO(thaJeztah): consider moving OSType into [container.StatsResponse].
}

// ContainerStats retrieves live resource usage statistics for the specified
// container. The caller must close the [io.ReadCloser] in the returned result
// to release associated resources.
//
// If the stream ends or the context is canceled, the underlying [io.ReadCloser]
// is automatically closed.
func (cli *Client) ContainerStats(ctx context.Context, containerID string, options ContainerStatsOptions) (ContainerStatsResult, error) {
	containerID, err := trimID("container", containerID)
	if err != nil {
		return ContainerStatsResult{}, err
	}

	query := url.Values{}
	if options.Stream {
		query.Set("stream", "true")
	} else {
		// Note: daemons may return an error if both set: "cannot have stream=true and one-shot=true"
		//
		// TODO(thaJeztah): consider making "stream=false" the default for the API as well, or using Accept Header to switch.
		query.Set("stream", "false")
		if !options.IncludePreviousSample {
			query.Set("one-shot", "true")
		}
	}

	resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil)
	if err != nil {
		return ContainerStatsResult{}, err
	}

	return ContainerStatsResult{
		Body:   resp.Body,
		OSType: resp.Header.Get("Ostype"),
	}, nil
}


Review comment (suggestion):
Shouldn't we still pass it to the daemon so that it can return an error (or actually handle it when it supports it)?

Otherwise passing both `Stream = true and IncludePreviousSample = true` will still be silently accepted even though it's not a valid setting.

Code after:
// If streaming is disabled, the stream contains a single record.
//
// The OSType field reports the daemon's operating system, allowing platform-specific
// handling of the response.
type ContainerStatsResult struct {
	Body   io.ReadCloser
	OSType string // TODO(thaJeztah): consider moving OSType into [container.StatsResponse].
}

// ContainerStats retrieves live resource usage statistics for the specified
// container. The caller must close the [io.ReadCloser] in the returned result
// to release associated resources.
func (cli *Client) ContainerStats(ctx context.Context, containerID string, options ContainerStatsOptions) (ContainerStatsResult, error) {
	containerID, err := trimID("container", containerID)
	if err != nil {
		return ContainerStatsResult{}, err
	}

	query := url.Values{}
	if options.Stream {
		query.Set("stream", "true")
	} else {
		// Note: daemons before v29.0 return an error if both set: "cannot have stream=true and one-shot=true"
		//
		// TODO(thaJeztah): consider making "stream=false" the default for the API as well, or using Accept Header to switch.
		query.Set("stream", "false")
		if !options.IncludePreviousSample {
			query.Set("one-shot", "true")
		}
	}

	resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil)
	if err != nil {
		return ContainerStatsResult{}, err
	}

	return ContainerStatsResult{
		Body:   resp.Body,
		OSType: resp.Header.Get("Ostype"),
	}, nil
}