Repository: incubator-htrace Updated Branches: refs/heads/master 2e2757f83 -> 7c27517d0
HTRACE-285. htraced tool: fix query parsing and add query_test (cmccabe) Project: http://git-wip-us.apache.org/repos/asf/incubator-htrace/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-htrace/commit/7c27517d Tree: http://git-wip-us.apache.org/repos/asf/incubator-htrace/tree/7c27517d Diff: http://git-wip-us.apache.org/repos/asf/incubator-htrace/diff/7c27517d Branch: refs/heads/master Commit: 7c27517d0d2c858c1046a16a85cd50b685531eb3 Parents: 2e2757f Author: Colin P. Mccabe <[email protected]> Authored: Mon Nov 2 16:19:45 2015 -0800 Committer: Colin P. Mccabe <[email protected]> Committed: Mon Nov 2 16:19:45 2015 -0800 ---------------------------------------------------------------------- .../go/src/org/apache/htrace/htrace/cmd.go | 10 +-- .../go/src/org/apache/htrace/htrace/queries.go | 31 ++++--- .../src/org/apache/htrace/htrace/query_test.go | 88 ++++++++++++++++++++ 3 files changed, 114 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7c27517d/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go ---------------------------------------------------------------------- diff --git a/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go b/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go index f3668ea..14b7f73 100644 --- a/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go +++ b/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go @@ -43,7 +43,7 @@ var GIT_VERSION string const EXIT_SUCCESS = 0 const EXIT_FAILURE = 1 -var verbose *bool +var verbose bool const USAGE = `The Apache HTrace command-line tool. This tool retrieves and modifies settings and other data on a running htraced daemon. @@ -68,7 +68,7 @@ func main() { app.Flag("Dmy.key", "Set configuration key 'my.key' to 'my.value'. Replace 'my.key' "+ "with any key you want to set.").Default("my.value").String() addr := app.Flag("addr", "Server address.").String() - verbose = app.Flag("verbose", "Verbose.").Default("false").Bool() + verbose = *app.Flag("verbose", "Verbose.").Default("false").Bool() version := app.Command("version", "Print the version of this program.") serverInfo := app.Command("serverInfo", "Print information retrieved from an htraced server.") serverStats := app.Command("serverStats", "Print statistics retrieved from the htraced server.") @@ -100,7 +100,7 @@ func main() { queryArg := query.Arg("query", "The query string to send. Query strings have the format "+ "[TYPE] [OPERATOR] [CONST], joined by AND statements.").Required().String() rawQuery := app.Command("rawQuery", "Send a raw JSON query to htraced.") - rawQueryArg := query.Arg("json", "The query JSON to send.").Required().String() + rawQueryArg := rawQuery.Arg("json", "The query JSON to send.").Required().String() cmd := kingpin.MustParse(app.Parse(os.Args[1:])) // Add the command-line settings into the configuration. @@ -327,7 +327,7 @@ func doLoadSpans(hcl *htrace.Client, reader io.Reader) int { } spans = append(spans, &span) } - if *verbose { + if verbose { fmt.Printf("Writing ") prefix := "" for i := range spans { @@ -390,7 +390,7 @@ func doDumpAll(hcl *htrace.Client, outPath string, lim int) error { if err == nil { _, err = fmt.Fprintf(w, "%s\n", span.ToJson()) } - if *verbose { + if verbose { numSpans++ now := time.Now() if !now.Before(nextLogTime) { http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7c27517d/htrace-htraced/go/src/org/apache/htrace/htrace/queries.go ---------------------------------------------------------------------- diff --git a/htrace-htraced/go/src/org/apache/htrace/htrace/queries.go b/htrace-htraced/go/src/org/apache/htrace/htrace/queries.go index 4ff246c..442df4f 100644 --- a/htrace-htraced/go/src/org/apache/htrace/htrace/queries.go +++ b/htrace-htraced/go/src/org/apache/htrace/htrace/queries.go @@ -36,12 +36,12 @@ func tokenize(str string) []string { switch { case c == prevQuote: prevQuote = rune(0) - return false + return true case prevQuote != rune(0): return false case unicode.In(c, unicode.Quotation_Mark): prevQuote = c - return false + return true default: return unicode.IsSpace(c) } @@ -57,7 +57,7 @@ type predicateParser struct { } func (ps *predicateParser) Parse() (*common.Predicate, error) { - if ps.curToken > len(ps.tokens) { + if ps.curToken >= len(ps.tokens) { return nil, nil } if ps.curToken > 0 { @@ -72,7 +72,7 @@ func (ps *predicateParser) Parse() (*common.Predicate, error) { "token %d", ps.curToken)) } } - field := common.Field(ps.tokens[ps.curToken]) + field := common.Field(strings.ToLower(ps.tokens[ps.curToken])) if !field.IsValid() { return nil, errors.New(fmt.Sprintf("Invalid field specifier at token %d. "+ "Can't understand %s. Valid field specifiers are %v", ps.curToken, @@ -83,7 +83,7 @@ func (ps *predicateParser) Parse() (*common.Predicate, error) { return nil, errors.New(fmt.Sprintf("Nothing found after field specifier "+ "at token %d", ps.curToken)) } - op := common.Op(ps.tokens[ps.curToken]) + op := common.Op(strings.ToLower(ps.tokens[ps.curToken])) if !op.IsValid() { return nil, errors.New(fmt.Sprintf("Invalid operation specifier at token %d. "+ "Can't understand %s. Valid operation specifiers are %v", ps.curToken, @@ -95,20 +95,31 @@ func (ps *predicateParser) Parse() (*common.Predicate, error) { "at token %d", ps.curToken)) } val := ps.tokens[ps.curToken] + ps.curToken++ return &common.Predicate{Op: op, Field: field, Val: val}, nil } func parseQueryString(str string) ([]common.Predicate, error) { ps := predicateParser{tokens: tokenize(str)} + if verbose { + fmt.Printf("Running query [ ") + prefix := "" + for tokenIdx := range(ps.tokens) { + fmt.Printf("%s'%s'", prefix, ps.tokens[tokenIdx]) + prefix = ", " + } + fmt.Printf(" ]\n") + } preds := make([]common.Predicate, 0) for { pred, err := ps.Parse() - if pred == nil { - break - } if err != nil { return nil, err } + if pred == nil { + break + } + preds = append(preds, *pred) } if len(preds) == 0 { return nil, errors.New("Empty query string") @@ -140,7 +151,7 @@ func doRawQuery(hcl *htrace.Client, str string) error { // Send a query. func doQuery(hcl *htrace.Client, query *common.Query) error { - if *verbose { + if verbose { qbytes, err := json.Marshal(*query) if err != nil { qbytes = []byte("marshaling error: " + err.Error()) @@ -151,7 +162,7 @@ func doQuery(hcl *htrace.Client, query *common.Query) error { if err != nil { return err } - if *verbose { + if verbose { fmt.Printf("%d results...\n", len(spans)) } for i := range spans { http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/7c27517d/htrace-htraced/go/src/org/apache/htrace/htrace/query_test.go ---------------------------------------------------------------------- diff --git a/htrace-htraced/go/src/org/apache/htrace/htrace/query_test.go b/htrace-htraced/go/src/org/apache/htrace/htrace/query_test.go new file mode 100644 index 0000000..cab1e92 --- /dev/null +++ b/htrace-htraced/go/src/org/apache/htrace/htrace/query_test.go @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package main + +import ( + "encoding/json" + "org/apache/htrace/common" + "reflect" + "testing" +) + +func predsToStr(preds []common.Predicate) string { + b, err := json.MarshalIndent(preds, "", " ") + if err != nil { + return "JSON marshaling error: " + err.Error() + } + return string(b) +} + +func checkParseQueryString(t *testing.T, str string, epreds []common.Predicate) { + preds, err := parseQueryString(str) + if err != nil { + t.Fatalf("got unexpected parseQueryString error: %s\n", err.Error()) + } + if !reflect.DeepEqual(preds, epreds) { + t.Fatalf("Unexpected result from parseQueryString. " + + "Expected: %s, got: %s\n", predsToStr(epreds), predsToStr(preds)) + } +} + +func TestParseQueryString(t *testing.T) { + verbose = testing.Verbose() + checkParseQueryString(t, "description eq ls", []common.Predicate { + common.Predicate { + Op: common.EQUALS, + Field: common.DESCRIPTION, + Val: "ls", + }, + }) + checkParseQueryString(t, "begin gt 123 and end le 456", []common.Predicate { + common.Predicate { + Op: common.GREATER_THAN, + Field: common.BEGIN_TIME, + Val: "123", + }, + common.Predicate { + Op: common.LESS_THAN_OR_EQUALS, + Field: common.END_TIME, + Val: "456", + }, + }) + checkParseQueryString(t, `DESCRIPTION cn "Foo Bar" and ` + + `BEGIN ge "999" and SPANID eq "4565d8abc4f70ac1216a3f1834c6860b"`, + []common.Predicate { + common.Predicate { + Op: common.CONTAINS, + Field: common.DESCRIPTION, + Val: "Foo Bar", + }, + common.Predicate { + Op: common.GREATER_THAN_OR_EQUALS, + Field: common.BEGIN_TIME, + Val: "999", + }, + common.Predicate { + Op: common.EQUALS, + Field: common.SPAN_ID, + Val: "4565d8abc4f70ac1216a3f1834c6860b", + }, + }) +}
