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裏面就會出現:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章