golang处理[]interface

在使用prometheus的query_range接口查询metrics的时候,prometheus返回的数据格式如下

{
   "status" : "success",
   "data" : {
      "resultType" : "matrix",
      "result" : [
         {
            "metric" : {
               "__name__" : "up",
               "job" : "prometheus",
               "instance" : "localhost:9090"
            },
            "values" : [
               [ 1435781430.781, "1" ],
               [ 1435781445.781, "1" ],
               [ 1435781460.781, "1" ]
            ]
         },
         {
            "metric" : {
               "__name__" : "up",
               "job" : "node",
               "instance" : "localhost:9091"
            },
            "values" : [
               [ 1435781430.781, "0" ],
               [ 1435781445.781, "0" ],
               [ 1435781460.781, "1" ]
            ]
         }
      ]
   }
}

其他字段的处理都很好办,但是到了values字段的时候就有点难搞了。
 

首先定义结构体接收原始数据。

我把values字段定义成了[][]interface,方便后续的处理。

type RawMetrics struct {
	Status string `json:"status"`
	Data Data `json:"data"`
}

type Data struct {
	ResultType string `json:"resultType"`
	Result []Result `json:"result"`
}

type Result struct {
	Metric Metric `json:"metric"`
	Values [][]interface{} `json:"values"`
}

type Metric struct {
	Name string `json:"__name__"`
	Endpoint string `json:"endpoint"`
	Instance string `json:"instance"`
	Job string `json:"job"`
	Namespace string `json:"namespace"`
	Pod string `json:"pod"`
	Service string `json:"service"`
}

单元测试

func TestQueryMetrics(t *testing.T)  {
	url := "http://10.10.13.27:30900/api/v1/query_range?query=up&step=1&start=1584928541&end=1584928542"
	resp, err := http.Get(url)
	assert.Equal(t, nil, err)
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	assert.Equal(t, nil, err)
	assert.Equal(t, resp.StatusCode, http.StatusOK)
	var dst RawMetrics
	err = ParseJsonFromBytes(data, &dst)
	assert.Equal(t, nil, err)
}


func ParseJsonFromBytes(b []byte, result interface{}) error {
	return jsoniter.Unmarshal(b, result)
}

将原始数据转换成需要的字段,其实主要是对values字段的处理。当需要得到values字段里面的每个数据时,就需要使用断言进行处理。

type Metrics struct {
	Name string `json:"name"`
	Endpoint string `json:"endpoint"`
	Instance string `json:"instance"`
	Job string `json:"job"`
	Namespace string `json:"namespace"`
	Pod string `json:"pod"`
	Service string `json:"service"`
	Values []Value `json:"values"`
}
type Value struct {
	Timestamp float64 `json:"timestamp"`
	Value string `json:"value"`
}

完整代码

func TestQueryMetrics(t *testing.T)  {
	url := "http://10.10.13.27:30900/api/v1/query_range?query=up&step=1&start=1584928541&end=1584928542"
	resp, err := http.Get(url)
	assert.Equal(t, nil, err)
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	assert.Equal(t, nil, err)
	assert.Equal(t, resp.StatusCode, http.StatusOK)
	var dst RawMetrics
	err = ParseJsonFromBytes(data, &dst)
	assert.Equal(t, nil, err)
    // 以上是获取原始数据的操作

    // 对原始数据进行转换
	var metrics []Metrics
	for _, result := range dst.Data.Result {
		var metric Metrics
		metric.Name = result.Metric.Name
		metric.Namespace = result.Metric.Namespace
		metric.Pod = result.Metric.Pod
		metric.Endpoint = result.Metric.Endpoint
		metric.Job = result.Metric.Job
		metric.Instance = result.Metric.Instance
		metric.Service = result.Metric.Service
		for _, rawValue := range result.Values {
            // 注意value必须在这里定义,否则后面会出现timestamp为0时value不为空的情况
			var value Value
			for _, raw := range rawValue {
				switch raw.(type) {
				case float64:
					ts := raw.(float64)
					value.Timestamp = ts
				case string:
					v := raw.(string)
					value.Value = v
				}
			}
			metric.Values = append(metric.Values, value)
		}
		metrics = append(metrics, metric)
	}
	fmt.Println("metrics >> ",Obj2Json(metrics))
}

如果var value Value位置放的不对,放在了for _, raw := range rawValue里面就会出现:

猜你喜欢

转载自blog.csdn.net/u010918487/article/details/105047057