mirror of
https://github.com/ClusterCockpit/cc-metric-store.git
synced 2024-11-10 05:07:25 +01:00
better JSON encoding (less allocs)
This commit is contained in:
parent
4a78a24034
commit
af38004a76
23
api.go
23
api.go
@ -8,6 +8,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -21,13 +22,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ApiMetricData struct {
|
type ApiMetricData struct {
|
||||||
Error *string `json:"error,omitempty"`
|
Error *string `json:"error,omitempty"`
|
||||||
From int64 `json:"from"`
|
From int64 `json:"from"`
|
||||||
To int64 `json:"to"`
|
To int64 `json:"to"`
|
||||||
Data []Float `json:"data,omitempty"`
|
Data FloatArray `json:"data,omitempty"`
|
||||||
Avg Float `json:"avg"`
|
Avg Float `json:"avg"`
|
||||||
Min Float `json:"min"`
|
Min Float `json:"min"`
|
||||||
Max Float `json:"max"`
|
Max Float `json:"max"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Optimize this, just like the stats endpoint!
|
// TODO: Optimize this, just like the stats endpoint!
|
||||||
@ -109,7 +110,13 @@ func handleWrite(rw http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dec := lineprotocol.NewDecoder(bufio.NewReader(r.Body))
|
bytes, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dec := lineprotocol.NewDecoderWithBytes(bytes)
|
||||||
if err := decodeLine(dec); err != nil {
|
if err := decodeLine(dec); err != nil {
|
||||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
58
float.go
Normal file
58
float.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Go's JSON encoder for floats does not support NaN (https://github.com/golang/go/issues/3480).
|
||||||
|
// This program uses NaN as a signal for missing data.
|
||||||
|
// For the HTTP JSON API to be able to handle NaN values,
|
||||||
|
// we have to use our own type which implements encoding/json.Marshaler itself.
|
||||||
|
type Float float32
|
||||||
|
|
||||||
|
var NaN Float = Float(math.NaN())
|
||||||
|
var nullAsBytes []byte = []byte("null")
|
||||||
|
|
||||||
|
func (f Float) IsNaN() bool {
|
||||||
|
return math.IsNaN(float64(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Float) MarshalJSON() ([]byte, error) {
|
||||||
|
if math.IsNaN(float64(f)) {
|
||||||
|
return nullAsBytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return strconv.AppendFloat(make([]byte, 0, 10), float64(f), 'f', 1, 32), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Float) UnmarshalJSON(input []byte) error {
|
||||||
|
if string(input) == "null" {
|
||||||
|
*f = NaN
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := strconv.ParseFloat(string(input), 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*f = Float(val)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as `[]Float`, but can be marshaled to JSON with less allocations.
|
||||||
|
type FloatArray []Float
|
||||||
|
|
||||||
|
func (fa FloatArray) MarshalJSON() ([]byte, error) {
|
||||||
|
buf := make([]byte, 0, 2+len(fa)*8)
|
||||||
|
buf = append(buf, '[')
|
||||||
|
if len(fa) > 0 {
|
||||||
|
buf = strconv.AppendFloat(buf, float64(fa[0]), 'f', 1, 32)
|
||||||
|
for i := 1; i < len(fa); i++ {
|
||||||
|
buf = append(buf, ',')
|
||||||
|
buf = strconv.AppendFloat(buf, float64(fa[i]), 'f', 1, 32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf = append(buf, ']')
|
||||||
|
return buf, nil
|
||||||
|
}
|
@ -4,8 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -13,41 +11,6 @@ import (
|
|||||||
"github.com/nats-io/nats.go"
|
"github.com/nats-io/nats.go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Go's JSON encoder for floats does not support NaN (https://github.com/golang/go/issues/3480).
|
|
||||||
// This program uses NaN as a signal for missing data.
|
|
||||||
// For the HTTP JSON API to be able to handle NaN values,
|
|
||||||
// we have to use our own type which implements encoding/json.Marshaler itself.
|
|
||||||
type Float float64
|
|
||||||
|
|
||||||
var NaN Float = Float(math.NaN())
|
|
||||||
|
|
||||||
func (f Float) IsNaN() bool {
|
|
||||||
return math.IsNaN(float64(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f Float) MarshalJSON() ([]byte, error) {
|
|
||||||
if math.IsNaN(float64(f)) {
|
|
||||||
return []byte("null"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return []byte(strconv.FormatFloat(float64(f), 'f', 2, 64)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Float) UnmarshalJSON(input []byte) error {
|
|
||||||
s := string(input)
|
|
||||||
if s == "null" {
|
|
||||||
*f = NaN
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
val, err := strconv.ParseFloat(s, 64)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*f = Float(val)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Metric struct {
|
type Metric struct {
|
||||||
Name string
|
Name string
|
||||||
minfo metricInfo
|
minfo metricInfo
|
||||||
|
Loading…
Reference in New Issue
Block a user