func TestFilterMatchMultipleWildcards(t *testing.T) { p, err := graphite.NewParser([]string{ "*.* .wrong.measurement*", "servers.* .host.measurement*", // should match this "servers.localhost .wrong.measurement*", "*.localhost .wrong.measurement*", }, nil) if err != nil { t.Fatalf("unexpected error creating parser, got %v", err) } exp := tsdb.NewPoint("cpu_load", tsdb.Tags{"host": "server01"}, tsdb.Fields{"value": float64(11)}, time.Unix(1435077219, 0)) pt, err := p.Parse("servers.server01.cpu_load 11 1435077219") if err != nil { t.Fatalf("parse error: %v", err) } if exp.String() != pt.String() { t.Errorf("parse mismatch: got %v, exp %v", pt.String(), exp.String()) } }
func TestFilterMatchMostLongestFilter(t *testing.T) { p, err := graphite.NewParser([]string{ "*.* .wrong.measurement*", "servers.* .wrong.measurement*", "servers.localhost .wrong.measurement*", "servers.localhost.cpu .host.resource.measurement*", // should match this "*.localhost .wrong.measurement*", }, nil) if err != nil { t.Fatalf("unexpected error creating parser, got %v", err) } exp := models.NewPoint("cpu_load", models.Tags{"host": "localhost", "resource": "cpu"}, models.Fields{"value": float64(11)}, time.Unix(1435077219, 0)) pt, err := p.Parse("servers.localhost.cpu.cpu_load 11 1435077219") if err != nil { t.Fatalf("parse error: %v", err) } if exp.String() != pt.String() { t.Errorf("parse mismatch: got %v, exp %v", pt.String(), exp.String()) } }
// Given a template.config and graphite.timeseries, print out // what the Name of the points would be, and what the tags. func main() { template := readtemplate(*template) fmt.Println("Template: ") for _, l := range template { fmt.Println(" " + l) } fmt.Println() p, err := graphite.NewParser(template, nil) if err != nil { log.Fatal(err) } gts, err := os.Open(*series) if err != nil { log.Fatal(err) } scanner := bufio.NewScanner(gts) for scanner.Scan() { line := scanner.Text() pt, err := p.Parse(line) fmt.Println("in: ", line) if err != nil { log.Fatalf("Fail: %s\n", err) } fmt.Println("out:", string(pt.Key())+"\n") } }
func TestParseNaN(t *testing.T) { p, err := graphite.NewParser([]string{"measurement*"}, nil) if err != nil { t.Fatalf("unexpected error creating parser, got %v", err) } _, err = p.Parse("servers.localhost.cpu_load NaN 1435077219") if err == nil { t.Fatalf("expected error. got nil") } if _, ok := err.(*graphite.UnsupposedValueError); !ok { t.Fatalf("expected *graphite.ErrUnsupportedValue, got %v", reflect.TypeOf(err)) } }
func Test_DecodeNameAndTags(t *testing.T) { var tests = []struct { test string str string name string tags map[string]string position string separator string err string }{ {test: "metric only", str: "cpu", name: "cpu"}, {test: "metric with single series", str: "cpu.hostname.server01", name: "cpu", tags: map[string]string{"hostname": "server01"}}, {test: "metric with multiple series", str: "cpu.region.us-west.hostname.server01", name: "cpu", tags: map[string]string{"hostname": "server01", "region": "us-west"}}, {test: "no metric", tags: make(map[string]string), err: `no name specified for metric. ""`}, {test: "wrong metric format", str: "foo.cpu", tags: make(map[string]string), err: `received "foo.cpu" which doesn't conform to format of key.value.key.value.name or name`}, } for _, test := range tests { t.Logf("testing %q...", test.test) p := graphite.NewParser() if test.separator != "" { p.Separator = test.separator } name, tags, err := p.DecodeNameAndTags(test.str) if errstr(err) != test.err { t.Fatalf("err does not match. expected %v, got %v", test.err, err) } if name != test.name { t.Fatalf("name parse failer. expected %v, got %v", test.name, name) } if len(tags) != len(test.tags) { t.Fatalf("unexpected number of tags. expected %d, got %d", len(test.tags), len(tags)) } for k, v := range test.tags { if tags[k] != v { t.Fatalf("unexpected tag value for tags[%s]. expected %q, got %q", k, v, tags[k]) } } } }
func TestParseNoMatch(t *testing.T) { p, err := graphite.NewParser([]string{"servers.*.cpu .host.measurement.cpu.measurement"}, nil) if err != nil { t.Fatalf("unexpected error creating parser, got %v", err) } exp := tsdb.NewPoint("servers.localhost.memory.VmallocChunk", tsdb.Tags{}, tsdb.Fields{"value": float64(11)}, time.Unix(1435077219, 0)) pt, err := p.Parse("servers.localhost.memory.VmallocChunk 11 1435077219") if err != nil { t.Fatalf("parse error: %v", err) } if exp.String() != pt.String() { t.Errorf("parse mismatch: got %v, exp %v", pt.String(), exp.String()) } }
func TestFilterMatchSingle(t *testing.T) { p, err := graphite.NewParser([]string{"servers.localhost .host.measurement*"}, nil) if err != nil { t.Fatalf("unexpected error creating parser, got %v", err) } exp := tsdb.NewPoint("cpu_load", tsdb.Tags{"host": "localhost"}, tsdb.Fields{"value": float64(11)}, time.Unix(1435077219, 0)) pt, err := p.Parse("servers.localhost.cpu_load 11 1435077219") if err != nil { t.Fatalf("parse error: %v", err) } if exp.String() != pt.String() { t.Errorf("parse mismatch: got %v, exp %v", pt.String(), exp.String()) } }
func BenchmarkParse(b *testing.B) { p, err := graphite.NewParser([]string{ "*.* .wrong.measurement*", "servers.* .host.measurement*", "servers.localhost .host.measurement*", "*.localhost .host.measurement*", "*.*.cpu .host.measurement*", "a.b.c .host.measurement*", "influxd.*.foo .host.measurement*", "prod.*.mem .host.measurement*", }, nil) if err != nil { b.Fatalf("unexpected error creating parser, got %v", err) } for i := 0; i < b.N; i++ { p.Parse("servers.localhost.cpu.load 11 1435077219") } }
func TestParseTemplateWhitespace(t *testing.T) { p, err := graphite.NewParser([]string{"servers.localhost .host.measurement* zone=1c"}, tsdb.Tags{ "region": "us-east", "host": "should not set", }) if err != nil { t.Fatalf("unexpected error creating parser, got %v", err) } exp := tsdb.NewPoint("cpu_load", tsdb.Tags{"host": "localhost", "region": "us-east", "zone": "1c"}, tsdb.Fields{"value": float64(11)}, time.Unix(1435077219, 0)) pt, err := p.Parse("servers.localhost.cpu_load 11 1435077219") if err != nil { t.Fatalf("parse error: %v", err) } if exp.String() != pt.String() { t.Errorf("parse mismatch: got %v, exp %v", pt.String(), exp.String()) } }
func TestParseNaN(t *testing.T) { p, err := graphite.NewParser([]string{"measurement*"}, nil) if err != nil { t.Fatalf("unexpected error creating parser, got %v", err) } pt, err := p.Parse("servers.localhost.cpu_load NaN 1435077219") if err != nil { t.Fatalf("parse error: %v", err) } exp := models.NewPoint("servers.localhost.cpu_load", models.Tags{}, models.Fields{"value": math.NaN()}, time.Unix(1435077219, 0)) if exp.String() != pt.String() { t.Errorf("parse mismatch: got %v, exp %v", pt.String(), exp.String()) } if !math.IsNaN(pt.Fields()["value"].(float64)) { t.Errorf("parse value mismatch: expected NaN") } }
func TestParse(t *testing.T) { testTime := time.Now().Round(time.Second) epochTime := testTime.Unix() strTime := strconv.FormatInt(epochTime, 10) var tests = []struct { test string input string measurement string tags map[string]string value float64 time time.Time template string err string }{ { test: "normal case", input: `cpu.foo.bar 50 ` + strTime, template: "measurement.foo.bar", measurement: "cpu", tags: map[string]string{ "foo": "foo", "bar": "bar", }, value: 50, time: testTime, }, { test: "metric only with float value", input: `cpu 50.554 ` + strTime, measurement: "cpu", template: "measurement", value: 50.554, time: testTime, }, { test: "missing metric", input: `1419972457825`, template: "measurement", err: `received "1419972457825" which doesn't have required fields`, }, { test: "should error parsing invalid float", input: `cpu 50.554z 1419972457825`, template: "measurement", err: `field "cpu" value: strconv.ParseFloat: parsing "50.554z": invalid syntax`, }, { test: "should error parsing invalid int", input: `cpu 50z 1419972457825`, template: "measurement", err: `field "cpu" value: strconv.ParseFloat: parsing "50z": invalid syntax`, }, { test: "should error parsing invalid time", input: `cpu 50.554 14199724z57825`, template: "measurement", err: `field "cpu" time: strconv.ParseFloat: parsing "14199724z57825": invalid syntax`, }, } for _, test := range tests { p, err := graphite.NewParser([]string{test.template}, nil) if err != nil { t.Fatalf("unexpected error creating graphite parser: %v", err) } point, err := p.Parse(test.input) if errstr(err) != test.err { t.Fatalf("err does not match. expected %v, got %v", test.err, err) } if err != nil { // If we erred out,it was intended and the following tests won't work continue } if point.Name() != test.measurement { t.Fatalf("name parse failer. expected %v, got %v", test.measurement, point.Name()) } if len(point.Tags()) != len(test.tags) { t.Fatalf("tags len mismatch. expected %d, got %d", len(test.tags), len(point.Tags())) } f := point.Fields()["value"].(float64) if point.Fields()["value"] != f { t.Fatalf("floatValue value mismatch. expected %v, got %v", test.value, f) } if point.Time().UnixNano()/1000000 != test.time.UnixNano()/1000000 { t.Fatalf("time value mismatch. expected %v, got %v", test.time.UnixNano(), point.Time().UnixNano()) } } }
func TestParseMissingMeasurement(t *testing.T) { _, err := graphite.NewParser([]string{"a.b.c"}, nil) if err == nil { t.Fatalf("expected error creating parser, got nil") } }
func Test_DecodeMetric(t *testing.T) { testTime := time.Now().Round(time.Second) epochTime := testTime.Unix() strTime := strconv.FormatInt(epochTime, 10) var tests = []struct { test string line string name string tags map[string]string value float64 time time.Time position, separator string err string }{ { test: "position first by default", line: `cpu.foo.bar 50 ` + strTime, name: "cpu", tags: map[string]string{"foo": "bar"}, value: 50, time: testTime, }, { test: "position first if unable to determine", position: "foo", line: `cpu.foo.bar 50 ` + strTime, name: "cpu", tags: map[string]string{"foo": "bar"}, value: 50, time: testTime, }, { test: "position last if specified", position: "last", line: `foo.bar.cpu 50 ` + strTime, name: "cpu", tags: map[string]string{"foo": "bar"}, value: 50, time: testTime, }, { test: "position first if specified with no series", position: "first", line: `cpu 50 ` + strTime, name: "cpu", tags: map[string]string{}, value: 50, time: testTime, }, { test: "position last if specified with no series", position: "last", line: `cpu 50 ` + strTime, name: "cpu", tags: map[string]string{}, value: 50, time: testTime, }, { test: "separator is . by default", line: `cpu.foo.bar 50 ` + strTime, name: "cpu", tags: map[string]string{"foo": "bar"}, value: 50, time: testTime, }, { test: "separator is . if specified", separator: ".", line: `cpu.foo.bar 50 ` + strTime, name: "cpu", tags: map[string]string{"foo": "bar"}, value: 50, time: testTime, }, { test: "separator is - if specified", separator: "-", line: `cpu-foo-bar 50 ` + strTime, name: "cpu", tags: map[string]string{"foo": "bar"}, value: 50, time: testTime, }, { test: "separator is boo if specified", separator: "boo", line: `cpuboofooboobar 50 ` + strTime, name: "cpu", tags: map[string]string{"foo": "bar"}, value: 50, time: testTime, }, { test: "series + metric + integer value", line: `cpu.foo.bar 50 ` + strTime, name: "cpu", tags: map[string]string{"foo": "bar"}, value: 50, time: testTime, }, { test: "metric only with float value", line: `cpu 50.554 ` + strTime, name: "cpu", value: 50.554, time: testTime, }, { test: "missing metric", line: `50.554 1419972457825`, err: `received "50.554 1419972457825" which doesn't have three fields`, }, { test: "should error on invalid key", line: `foo.cpu 50.554 1419972457825`, err: `received "foo.cpu" which doesn't conform to format of key.value.key.value.name or name`, }, { test: "should error parsing invalid float", line: `cpu 50.554z 1419972457825`, err: `field "cpu" value: strconv.ParseFloat: parsing "50.554z": invalid syntax`, }, { test: "should error parsing invalid int", line: `cpu 50z 1419972457825`, err: `field "cpu" value: strconv.ParseFloat: parsing "50z": invalid syntax`, }, { test: "should error parsing invalid time", line: `cpu 50.554 14199724z57825`, err: `field "cpu" time: strconv.ParseFloat: parsing "14199724z57825": invalid syntax`, }, } for _, test := range tests { t.Logf("testing %q...", test.test) p := graphite.NewParser() if test.separator != "" { p.Separator = test.separator } p.LastEnabled = (test.position == "last") point, err := p.Parse(test.line) if errstr(err) != test.err { t.Fatalf("err does not match. expected %v, got %v", test.err, err) } if err != nil { // If we erred out,it was intended and the following tests won't work continue } if point.Name() != test.name { t.Fatalf("name parse failer. expected %v, got %v", test.name, point.Name()) } if len(point.Tags()) != len(test.tags) { t.Fatalf("tags len mismatch. expected %d, got %d", len(test.tags), len(point.Tags())) } f := point.Fields()["value"].(float64) if point.Fields()["value"] != f { t.Fatalf("floatValue value mismatch. expected %v, got %v", test.value, f) } if point.Time().UnixNano()/1000000 != test.time.UnixNano()/1000000 { t.Fatalf("time value mismatch. expected %v, got %v", test.time.UnixNano(), point.Time().UnixNano()) } } }