Skip to content

Commit

Permalink
Support duration prefixes (#8109)
Browse files Browse the repository at this point in the history
## Summary
Typing the duration in nanoseconds is burdensome on the user. Support
using time suffixes to search numbers.

Supported suffixes:
```
h
m
s
ms
us
ns
```


https://www.loom.com/share/7c85288923864082bb9ce183fb39660b?sid=1a242ffd-02f6-467a-9354-6bb08191d45d

## How did you test this change?
1) Visit the traces page (`/traces`)
2) Ensure duration is displayed on the table
3) Search using the numerical operators -> `>`, `>=`, `<`, `<=`, 
- [ ] Correctly applies operator

## Are there any deployment considerations?
N/A

## Does this work require review from our design team?
N/A
  • Loading branch information
SpennyNDaJets committed Mar 27, 2024
1 parent 19e1e60 commit a53d972
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 17 deletions.
69 changes: 53 additions & 16 deletions backend/parser/listener/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package listener
import (
"fmt"
"regexp"
"strconv"
"strings"

"github.com/antlr4-go/antlr/v4"
Expand Down Expand Up @@ -361,71 +362,75 @@ func (s *searchListener[T]) appendRules(value string) {
}
}
} else if s.currentOp == ">" {
numValue := numericValue(value)
if traceAttributeKey {
s.rules = append(s.rules, s.sb.Var(sqlbuilder.Buildf("toFloat64OrNull("+s.attributesColumn+"[%s]) > %s", s.currentKey, value)))
s.rules = append(s.rules, s.sb.Var(sqlbuilder.Buildf("toFloat64OrNull("+s.attributesColumn+"[%s]) > %s", s.currentKey, numValue)))
s.ops = append(s.ops, &FilterOperation{
Key: s.currentKey,
Column: s.attributesColumn,
Operator: OperatorGreaterThan,
Values: []string{value},
Values: []string{numValue},
})
} else {
s.rules = append(s.rules, s.sb.GreaterThan(filterKey, value))
s.rules = append(s.rules, s.sb.GreaterThan(filterKey, numValue))
s.ops = append(s.ops, &FilterOperation{
Key: filterKey,
Operator: OperatorGreaterThan,
Values: []string{value},
Values: []string{numValue},
})
}
} else if s.currentOp == ">=" {
numValue := numericValue(value)
if traceAttributeKey {
s.rules = append(s.rules, s.sb.Var(sqlbuilder.Buildf("toFloat64OrNull("+s.attributesColumn+"[%s]) >= %s", s.currentKey, value)))
s.rules = append(s.rules, s.sb.Var(sqlbuilder.Buildf("toFloat64OrNull("+s.attributesColumn+"[%s]) >= %s", s.currentKey, numValue)))
s.ops = append(s.ops, &FilterOperation{
Key: s.currentKey,
Column: s.attributesColumn,
Operator: OperatorGreaterThanOrEqualTo,
Values: []string{value},
Values: []string{numValue},
})
} else {
s.rules = append(s.rules, s.sb.GreaterEqualThan(filterKey, value))
s.rules = append(s.rules, s.sb.GreaterEqualThan(filterKey, numValue))
s.ops = append(s.ops, &FilterOperation{
Key: filterKey,
Operator: OperatorGreaterThanOrEqualTo,
Values: []string{value},
Values: []string{numValue},
})
}
} else if s.currentOp == "<" {
numValue := numericValue(value)
if traceAttributeKey {
s.rules = append(s.rules, s.sb.Var(sqlbuilder.Buildf("toFloat64OrNull("+s.attributesColumn+"[%s]) < %s", s.currentKey, value)))
s.rules = append(s.rules, s.sb.Var(sqlbuilder.Buildf("toFloat64OrNull("+s.attributesColumn+"[%s]) < %s", s.currentKey, numValue)))
s.ops = append(s.ops, &FilterOperation{
Key: s.currentKey,
Column: s.attributesColumn,
Operator: OperatorLessThan,
Values: []string{value},
Values: []string{numValue},
})
} else {
s.rules = append(s.rules, s.sb.LessThan(filterKey, value))
s.rules = append(s.rules, s.sb.LessThan(filterKey, numValue))
s.ops = append(s.ops, &FilterOperation{
Key: filterKey,
Operator: OperatorLessThan,
Values: []string{value},
Values: []string{numValue},
})
}
} else if s.currentOp == "<=" {
numValue := numericValue(value)
if traceAttributeKey {
s.rules = append(s.rules, s.sb.Var(sqlbuilder.Buildf("toFloat64OrNull("+s.attributesColumn+"[%s]) <= %s", s.currentKey, value)))
s.rules = append(s.rules, s.sb.Var(sqlbuilder.Buildf("toFloat64OrNull("+s.attributesColumn+"[%s]) <= %s", s.currentKey, numValue)))
s.ops = append(s.ops, &FilterOperation{
Key: s.currentKey,
Column: s.attributesColumn,
Operator: OperatorLessThanOrEqualTo,
Values: []string{value},
Values: []string{numValue},
})
} else {
s.rules = append(s.rules, s.sb.LessEqualThan(filterKey, value))
s.rules = append(s.rules, s.sb.LessEqualThan(filterKey, numValue))
s.ops = append(s.ops, &FilterOperation{
Key: filterKey,
Operator: OperatorLessThanOrEqualTo,
Values: []string{value},
Values: []string{numValue},
})
}
} else {
Expand All @@ -445,3 +450,35 @@ func wildcardValue(value string) string {

return value
}

var suffixToNumeric = map[string]int64{
"h": 1e9 * 60 * 60,
"m": 1e9 * 60,
"s": 1e9,
"ms": 1e6,
"us": 1e3,
"ns": 1,
}

func numericValue(value string) string {
re := regexp.MustCompile(`^(\d+)([a-zA-Z]+)$`)
matches := re.FindStringSubmatch(value)
if len(matches) != 3 {
return value
}

numString := matches[1]
unit := matches[2]

nanoMultiplier := suffixToNumeric[strings.ToLower(unit)]
if nanoMultiplier == 0 {
return numString
}

num, err := strconv.ParseInt(numString, 10, 64)
if err != nil {
return numString
}

return strconv.FormatInt(num*nanoMultiplier, 10)
}
2 changes: 1 addition & 1 deletion backend/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestBasicSqlForSearch(t *testing.T) {
}

func TestComplexSqlForSearch(t *testing.T) {
sql, _ := buildSqlForQuery("span_name=\"Chris Schmitz\" duration>1000 level:info source=(backend OR frontend) OR (service_name!=private-graph span_name=gorm.Query span_name!=(testing OR testing2)) AND (\"body query\" asdf)")
sql, _ := buildSqlForQuery("span_name=\"Chris Schmitz\" duration>1us level:info source=(backend OR frontend) OR (service_name!=private-graph span_name=gorm.Query span_name!=(testing OR testing2)) AND (\"body query\" asdf)")

assert.Equal(
t,
Expand Down

0 comments on commit a53d972

Please sign in to comment.