我想使用Client.ContainerStats(ctx context.Context, containerID string, stream bool)方法获取容器的流式统计信息。
根据我的理解,如果我将true
传递给stream
参数,Docker将不会关闭连接并定期发送包含容器统计信息的JSON。但是,我不知道如何解码JSON,因为我不知道JSON数据的起点和终点。
我现在正在使用的是我不使用流选项,只是定期获取数据,然后像这样解码它。
stats, err := dockerClient.ContainerStats(ctx, container.ContainerID, false)
msgBytes, _ := ioutil.ReadAll(stats.Body)
var containerStats ContainerStats
err = json.Unmarshal(msgBytes, &containerStats)
我正在寻找的是一个函数,当我调用它时阻塞,然后当它接收到JSON数据时(我的意思是完整的JSON数据可以解码)它将返回包含从JSON解码的数据的结构然后我可以调用它再次运行以获取下一个stat,而无需向Docker发出新请求。
在您的情况下,您有多种选择:
map[string]interface{}
如果要使用自定义结构进行映射,可以执行以下操作:
type myStruct struct {
Id string `json:"id"`
Read string `json:"read"`
Preread string `json:"preread"`
}
// perform actions to retrieve logs in stats
//...
var containerStats myStruct
json.NewDecoder(stats.Body).Decode(&containerStats)
fmt.Println(containerStats.Id)
使用此解决方案,您必须确定要映射的字段。
但是,如果您不想指定字段,则可以执行以下操作:
//Perform actions to retrieve logs in stats
//...
var containerStats map[string]interface{}
json.NewDecoder(stats.Body).Decode(&containerStats)
fmt.Println(containerStats["id"])
总之,如果您必须操纵数据,我建议您使用自定义结构来使用第一个解决方案。
编辑:处理流
通过将stream
参数传递给true
,docker api将返回一个将更新的io.ReadCloser
。然后,由呼叫者关闭返回的io.ReadCloser
。
您需要做的是定期读取缓冲区值。
type myStruct struct {
Id string `json:"id"`
Read string `json:"read"`
Preread string `json:"preread"`
CpuStats cpu `json:"cpu_stats"`
}
type cpu struct {
Usage cpuUsage `json:"cpu_usage"`
}
type cpuUsage struct {
Total float64 `json:"total_usage"`
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
cli, e := client.NewEnvClient()
if e != nil {
panic(e)
}
stats, e := cli.ContainerStats(ctx, "container_id", true)
if e != nil {
fmt.Errorf("%s", e.Error())
}
decoder := json.NewDecoder(stats.Body)
var containerStats myStruct
for {
select {
case <-ctx.Done():
stats.Body.Close()
fmt.Println("Stop logging")
return
default:
if err := decoder.Decode(&containerStats); err == io.EOF {
return
} else if err != nil {
cancel()
}
fmt.Println(containerStats.CpuStats.Usage.Total)
}
}
}
在这个例子中,我们在新数据到达时解码stats.Body
ReadCloser,打印总CPU使用率,并在5秒后关闭流。