从数据流Docker GO SDK解码JSON

问题描述 投票:1回答:1

我想使用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发出新请求。

docker go
1个回答
4
投票

在您的情况下,您有多种选择:

  • 将结果映射到自定义结构上
  • 将结果映射到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秒后关闭流。

© www.soinside.com 2019 - 2024. All rights reserved.