繁体   English   中英

关于Golang的JSON - Unmarshal Graphite数据

[英]JSON on Golang - Unmarshal Graphite Data

我正在使用Golang和JSON尝试使用从Graphite API中提取的数据进行一些计算。

为简单起见,Graphite发送的数据片段为:

[
{
    "target": "server1.loadavg.1min",
    "datapoints": [
        [
            0.16,
            1422770850
        ],
        [
            0.16,
            1422770880
        ],
        [
            null,
            1422771120
        ]
    ]
},
{
    "target": "server2.loadavg.1min",
    "datapoints": [
        [
            0.19,
            1422770850
        ],
        [
            null,
            1422771390
        ],
        [
            0.14,
            1422771420
        ]
    ]
}
]

我一直在阅读关于如何使用通用接口{}获取JSON任意数据的go json教程 ,但我正在努力解决该过程的某些方面。

我试图定义一个结构来保存这些数据,读取文件内容并将其解组为此结构:

type Graphite struct {
  Metric struct {
    Target     string      `json:"target"`
    Datapoints [][]float64 `json:"datapoints"`
  }
}

var results []Graphite
err = json.Unmarshal(d, &r)
if err != nil {
    panic(err)
}
fmt.Printf("%v\n", r)

但结果是:

[{{ []}} {{ []}}]

我当然可以使用通用接口{}但我想知道我在这里缺少什么。

请你帮助我好吗?

谢谢!

我喜欢从最简单的类型开始,然后继续努力。 首先,您需要表示您的数据点。

type DataPoint []float64

然后,度量标准只是一个目标和一系列数据点。

type Metric struct {
    Target string      `json:"target"`
    Points []DataPoint `json:"datapoints"`
}

您不需要Graphite结构。 您的JSON只是Metric的JSON数组。

var results []Metric
err := json.Unmarshal([]byte(data), &results)

这是一个带有完整示例的游乐场链接。

上述答案的问题是它将零点转换为值为0的点,这是不正确的。 Null表示“未知”。 有些人建议使用指针浮点数,因此nil指针意味着“没有价值”,但这有很大的开销(例如大多数64位平台上的8字节,更不用说内存解除引用开销)。

最好使用golang的数学NaN支持来标记空值,这不需要额外的数据,因为它内置在float表示中。 您可以使用自定义Unmarshal函数执行此操作,如下所示:

type Metric struct {
    Target     string
    Datapoints []Point
}

type Point struct {
    Val float64
    Ts  uint32
}

var errInvalidFormat = errors.New("invalid format")

func (p *Point) UnmarshalJSON(data []byte) error {
    if len(data) < 2 {
        return errInvalidFormat
    }
    // find first digit or 'n' for "null"
    for (data[0] < 48 || data[0] > 57) && data[0] != 110 {
        if len(data) == 1 {
            return errInvalidFormat
        }
        data = data[1:]
    }
    // find comma
    var i int
    for i = 0; i < len(data); i++ {
        if data[i] == 44 {
            break
        }
    }
    if i == 0 {
        return errInvalidFormat
    }

    if bytes.HasPrefix(data[:i], []byte("null")) {
        p.Val = math.NaN()
    } else {
        fl, err := strconv.ParseFloat(string(data[:i]), 64)
        if err != nil {
            return err
        }
        p.Val = fl
    }
    data = data[i:]
    if len(data) < 2 {
        return errInvalidFormat
    }

    // find first digit
    for (data[0] < 48 || data[0] > 57) && data[0] != 110 {
        if len(data) == 1 {
            return errInvalidFormat
        }
        data = data[1:]
    }
    // find last digit
    for i = 0; data[i] >= 48 && data[i] <= 57 && i < len(data); i++ {
    }
    if i == 0 {
        return errInvalidFormat
    }

    ts, err := strconv.ParseUint(string(data[:i]), 10, 32)
    if err != nil {
        return err
    }
    p.Ts = uint32(ts)
    return nil
}

完整示例程序: 在操场上

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM