make line protocol round or parse precision as expected

pull/2770/head
Cory LaNou 2015-06-04 11:22:53 -06:00
parent a75591457c
commit 47d605b69a
2 changed files with 160 additions and 23 deletions

View File

@ -8,6 +8,8 @@ import (
"strconv"
"strings"
"time"
"github.com/davecgh/go-spew/spew"
)
// Point defines the values that will be written to the database
@ -52,6 +54,9 @@ type point struct {
// binary encoded field data
data []byte
// precision is set
precision string
}
var escapeCodes = map[byte][]byte{
@ -139,15 +144,16 @@ func parsePoint(buf []byte, defaultTime time.Time, precision string) (Point, err
}
pt := &point{
key: key,
fields: fields,
ts: ts,
key: key,
fields: fields,
ts: ts,
precision: precision,
}
if len(ts) == 0 {
pt.time = defaultTime
pt.SetPrecision()
}
pt.SetPrecision(precision)
return pt, nil
}
@ -505,7 +511,8 @@ func (p *point) Time() time.Time {
if err != nil {
return p.time
}
p.time = time.Unix(0, ts)
p.time = time.Unix(0, ts*p.GetPrecisionMultiplier())
spew.Dump(ts, p.precision, p.GetPrecisionMultiplier(), p.time.UTC())
}
return p.time
@ -574,22 +581,40 @@ func (p *point) AddField(name string, value interface{}) {
}
// SetPrecision will round a time to the specified precision
func (p *point) SetPrecision(precision string) {
switch precision {
func (p *point) SetPrecision() {
switch p.precision {
case "n":
case "u":
p.SetTime(p.Time().Round(time.Microsecond))
p.SetTime(p.Time().Truncate(time.Microsecond))
case "ms":
p.SetTime(p.Time().Round(time.Millisecond))
p.SetTime(p.Time().Truncate(time.Millisecond))
case "s":
p.SetTime(p.Time().Round(time.Second))
p.SetTime(p.Time().Truncate(time.Second))
case "m":
p.SetTime(p.Time().Round(time.Minute))
p.SetTime(p.Time().Truncate(time.Minute))
case "h":
p.SetTime(p.Time().Round(time.Hour))
p.SetTime(p.Time().Truncate(time.Hour))
}
}
// GetPrecisionMultiplier will return a multiplier for the precision specified
func (p *point) GetPrecisionMultiplier() int64 {
d := time.Nanosecond
switch p.precision {
case "u":
d = time.Microsecond
case "ms":
d = time.Millisecond
case "s":
d = time.Second
case "m":
d = time.Minute
case "h":
d = time.Hour
}
return int64(d)
}
func (p *point) String() string {
if p.Time().IsZero() {
return fmt.Sprintf("%s %s", p.Key(), string(p.fields))

View File

@ -451,19 +451,131 @@ func TestParsePointToString(t *testing.T) {
}
func TestParsePointsWithPrecision(t *testing.T) {
line := `cpu,host=serverA,region=us-east value=1.0 20000000000`
pts, err := ParsePointsWithPrecision([]byte(line), time.Now().UTC(), "m")
if err != nil {
t.Fatalf(`ParsePoints() failed. got %s`, err)
tests := []struct {
name string
line string
precision string
exp string
}{
{
name: "nanosecond by default",
line: `cpu,host=serverA,region=us-east value=1.0 946730096789012345`,
precision: "",
exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345",
},
{
name: "nanosecond",
line: `cpu,host=serverA,region=us-east value=1.0 946730096789012345`,
precision: "n",
exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345",
},
{
name: "microsecond",
line: `cpu,host=serverA,region=us-east value=1.0 946730096789012`,
precision: "u",
exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012000",
},
{
name: "millisecond",
line: `cpu,host=serverA,region=us-east value=1.0 946730096789`,
precision: "ms",
exp: "cpu,host=serverA,region=us-east value=1.0 946730096789000000",
},
{
name: "second",
line: `cpu,host=serverA,region=us-east value=1.0 946730096`,
precision: "s",
exp: "cpu,host=serverA,region=us-east value=1.0 946730096000000000",
},
{
name: "minute",
line: `cpu,host=serverA,region=us-east value=1.0 15778834`,
precision: "m",
exp: "cpu,host=serverA,region=us-east value=1.0 946730040000000000",
},
{
name: "hour",
line: `cpu,host=serverA,region=us-east value=1.0 262980`,
precision: "h",
exp: "cpu,host=serverA,region=us-east value=1.0 946728000000000000",
},
}
if exp := 1; len(pts) != exp {
t.Errorf("ParsePoint() len mismatch: got %v, exp %v", len(pts), exp)
}
pt := pts[0]
for _, test := range tests {
pts, err := ParsePointsWithPrecision([]byte(test.line), time.Now().UTC(), test.precision)
if err != nil {
t.Fatalf(`%s: ParsePoints() failed. got %s`, test.name, err)
}
if exp := 1; len(pts) != exp {
t.Errorf("%s: ParsePoint() len mismatch: got %v, exp %v", test.name, len(pts), exp)
}
pt := pts[0]
got := pt.String()
if exp := "cpu,host=serverA,region=us-east value=1.0 0"; got != exp {
t.Errorf("ParsePoint() to string mismatch:\n got %v\n exp %v", got, exp)
got := pt.String()
if got != test.exp {
t.Errorf("%s: ParsePoint() to string mismatch:\n got %v\n exp %v", test.name, got, test.exp)
}
}
}
func TestParsePointsWithPrecisionNoTime(t *testing.T) {
line := `cpu,host=serverA,region=us-east value=1.0`
tm, _ := time.Parse(time.RFC3339Nano, "2000-01-01T12:34:56.789012345Z")
tests := []struct {
name string
precision string
exp string
}{
{
name: "no precision",
precision: "",
exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345",
},
{
name: "nanosecond precision",
precision: "n",
exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012345",
},
{
name: "microsecond precision",
precision: "u",
exp: "cpu,host=serverA,region=us-east value=1.0 946730096789012000",
},
{
name: "millisecond precision",
precision: "ms",
exp: "cpu,host=serverA,region=us-east value=1.0 946730096789000000",
},
{
name: "second precision",
precision: "s",
exp: "cpu,host=serverA,region=us-east value=1.0 946730096000000000",
},
{
name: "minute precision",
precision: "m",
exp: "cpu,host=serverA,region=us-east value=1.0 946730040000000000",
},
{
name: "hour precision",
precision: "h",
exp: "cpu,host=serverA,region=us-east value=1.0 946728000000000000",
},
}
for _, test := range tests {
pts, err := ParsePointsWithPrecision([]byte(line), tm, test.precision)
if err != nil {
t.Fatalf(`%s: ParsePoints() failed. got %s`, test.name, err)
}
if exp := 1; len(pts) != exp {
t.Errorf("%s: ParsePoint() len mismatch: got %v, exp %v", test.name, len(pts), exp)
}
pt := pts[0]
got := pt.String()
if got != test.exp {
t.Errorf("%s: ParsePoint() to string mismatch:\n got %v\n exp %v", test.name, got, test.exp)
}
}
}