mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-01-20 15:16:42 +00:00
wip
This commit is contained in:
parent
01fc253eb7
commit
d95b491809
3 changed files with 100 additions and 8 deletions
|
@ -11,6 +11,7 @@ import (
|
||||||
// Example LogsQL: `fieldName:range(minValue, maxValue]`
|
// Example LogsQL: `fieldName:range(minValue, maxValue]`
|
||||||
type filterRange struct {
|
type filterRange struct {
|
||||||
fieldName string
|
fieldName string
|
||||||
|
|
||||||
minValue float64
|
minValue float64
|
||||||
maxValue float64
|
maxValue float64
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ type filterRange struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fr *filterRange) String() string {
|
func (fr *filterRange) String() string {
|
||||||
return quoteFieldNameIfNeeded(fr.fieldName) + "range" + fr.stringRepr
|
return quoteFieldNameIfNeeded(fr.fieldName) + fr.stringRepr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fr *filterRange) updateNeededFields(neededFields fieldsSet) {
|
func (fr *filterRange) updateNeededFields(neededFields fieldsSet) {
|
||||||
|
|
|
@ -406,6 +406,10 @@ func parseGenericFilter(lex *lexer, fieldName string) (filter, error) {
|
||||||
return nil, fmt.Errorf("missing whitespace before the search word %q", lex.prevToken)
|
return nil, fmt.Errorf("missing whitespace before the search word %q", lex.prevToken)
|
||||||
}
|
}
|
||||||
return parseParensFilter(lex, fieldName)
|
return parseParensFilter(lex, fieldName)
|
||||||
|
case lex.isKeyword(">"):
|
||||||
|
return parseFilterGT(lex, fieldName)
|
||||||
|
case lex.isKeyword("<"):
|
||||||
|
return parseFilterLT(lex, fieldName)
|
||||||
case lex.isKeyword("not", "!"):
|
case lex.isKeyword("not", "!"):
|
||||||
return parseFilterNot(lex, fieldName)
|
return parseFilterNot(lex, fieldName)
|
||||||
case lex.isKeyword("exact"):
|
case lex.isKeyword("exact"):
|
||||||
|
@ -754,6 +758,70 @@ func parseFilterRegexp(lex *lexer, fieldName string) (filter, error) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseFilterGT(lex *lexer, fieldName string) (filter, error) {
|
||||||
|
if fieldName == "" {
|
||||||
|
return nil, fmt.Errorf("'>' and '>=' must be prefixed with the field name")
|
||||||
|
}
|
||||||
|
lex.nextToken()
|
||||||
|
|
||||||
|
includeMinValue := false
|
||||||
|
op := ">"
|
||||||
|
if lex.isKeyword("=") {
|
||||||
|
lex.nextToken()
|
||||||
|
includeMinValue = true
|
||||||
|
op = ">="
|
||||||
|
}
|
||||||
|
|
||||||
|
minValue, fStr, err := parseFloat64(lex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot parse number after '%s': %w", op, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !includeMinValue {
|
||||||
|
minValue = nextafter(minValue, inf)
|
||||||
|
}
|
||||||
|
fr := &filterRange{
|
||||||
|
fieldName: fieldName,
|
||||||
|
minValue: minValue,
|
||||||
|
maxValue: inf,
|
||||||
|
|
||||||
|
stringRepr: op + fStr,
|
||||||
|
}
|
||||||
|
return fr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFilterLT(lex *lexer, fieldName string) (filter, error) {
|
||||||
|
if fieldName == "" {
|
||||||
|
return nil, fmt.Errorf("'<' and '<=' must be prefixed with the field name")
|
||||||
|
}
|
||||||
|
lex.nextToken()
|
||||||
|
|
||||||
|
includeMaxValue := false
|
||||||
|
op := "<"
|
||||||
|
if lex.isKeyword("=") {
|
||||||
|
lex.nextToken()
|
||||||
|
includeMaxValue = true
|
||||||
|
op = "<="
|
||||||
|
}
|
||||||
|
|
||||||
|
maxValue, fStr, err := parseFloat64(lex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot parse number after '%s': %w", op, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !includeMaxValue {
|
||||||
|
maxValue = nextafter(maxValue, -inf)
|
||||||
|
}
|
||||||
|
fr := &filterRange{
|
||||||
|
fieldName: fieldName,
|
||||||
|
minValue: -inf,
|
||||||
|
maxValue: maxValue,
|
||||||
|
|
||||||
|
stringRepr: op + fStr,
|
||||||
|
}
|
||||||
|
return fr, nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseFilterRange(lex *lexer, fieldName string) (filter, error) {
|
func parseFilterRange(lex *lexer, fieldName string) (filter, error) {
|
||||||
funcName := lex.token
|
funcName := lex.token
|
||||||
lex.nextToken()
|
lex.nextToken()
|
||||||
|
@ -801,19 +869,19 @@ func parseFilterRange(lex *lexer, fieldName string) (filter, error) {
|
||||||
}
|
}
|
||||||
lex.nextToken()
|
lex.nextToken()
|
||||||
|
|
||||||
stringRepr := ""
|
stringRepr := "range"
|
||||||
if includeMinValue {
|
if includeMinValue {
|
||||||
stringRepr += "["
|
stringRepr += "["
|
||||||
} else {
|
} else {
|
||||||
stringRepr += "("
|
stringRepr += "("
|
||||||
minValue = math.Nextafter(minValue, inf)
|
minValue = nextafter(minValue, inf)
|
||||||
}
|
}
|
||||||
stringRepr += minValueStr + ", " + maxValueStr
|
stringRepr += minValueStr + ", " + maxValueStr
|
||||||
if includeMaxValue {
|
if includeMaxValue {
|
||||||
stringRepr += "]"
|
stringRepr += "]"
|
||||||
} else {
|
} else {
|
||||||
stringRepr += ")"
|
stringRepr += ")"
|
||||||
maxValue = math.Nextafter(maxValue, -inf)
|
maxValue = nextafter(maxValue, -inf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fr := &filterRange{
|
fr := &filterRange{
|
||||||
|
@ -1216,3 +1284,10 @@ func parseInt(s string) (int64, error) {
|
||||||
}
|
}
|
||||||
return nn, nil
|
return nn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func nextafter(f, xInf float64) float64 {
|
||||||
|
if math.IsInf(f, 0) {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
return math.Nextafter(f, xInf)
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package logstorage
|
package logstorage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -492,15 +491,25 @@ func TestParseRangeFilter(t *testing.T) {
|
||||||
f(`range:range["-1.234e5", "-2e-5"]`, `range`, -1.234e5, -2e-5)
|
f(`range:range["-1.234e5", "-2e-5"]`, `range`, -1.234e5, -2e-5)
|
||||||
|
|
||||||
f(`_msg:range[1, 2]`, `_msg`, 1, 2)
|
f(`_msg:range[1, 2]`, `_msg`, 1, 2)
|
||||||
f(`:range(1, 2)`, ``, math.Nextafter(1, inf), math.Nextafter(2, -inf))
|
f(`:range(1, 2)`, ``, nextafter(1, inf), nextafter(2, -inf))
|
||||||
f(`range[1, 2)`, ``, 1, math.Nextafter(2, -inf))
|
f(`range[1, 2)`, ``, 1, nextafter(2, -inf))
|
||||||
f(`range("1", 2]`, ``, math.Nextafter(1, inf), 2)
|
f(`range("1", 2]`, ``, nextafter(1, inf), 2)
|
||||||
|
|
||||||
f(`response_size:range[1KB, 10MiB]`, `response_size`, 1_000, 10*(1<<20))
|
f(`response_size:range[1KB, 10MiB]`, `response_size`, 1_000, 10*(1<<20))
|
||||||
f(`response_size:range[1G, 10Ti]`, `response_size`, 1_000_000_000, 10*(1<<40))
|
f(`response_size:range[1G, 10Ti]`, `response_size`, 1_000_000_000, 10*(1<<40))
|
||||||
f(`response_size:range[10, inf]`, `response_size`, 10, inf)
|
f(`response_size:range[10, inf]`, `response_size`, 10, inf)
|
||||||
|
|
||||||
f(`duration:range[100ns, 1y2w2.5m3s5ms]`, `duration`, 100, 1*nsecsPerYear+2*nsecsPerWeek+2.5*nsecsPerMinute+3*nsecsPerSecond+5*nsecsPerMillisecond)
|
f(`duration:range[100ns, 1y2w2.5m3s5ms]`, `duration`, 100, 1*nsecsPerYear+2*nsecsPerWeek+2.5*nsecsPerMinute+3*nsecsPerSecond+5*nsecsPerMillisecond)
|
||||||
|
|
||||||
|
f(`foo:>10.43`, `foo`, nextafter(10.43, inf), inf)
|
||||||
|
f(`foo: > -10.43`, `foo`, nextafter(-10.43, inf), inf)
|
||||||
|
f(`foo:>=10.43`, `foo`, 10.43, inf)
|
||||||
|
f(`foo: >= -10.43`, `foo`, -10.43, inf)
|
||||||
|
|
||||||
|
f(`foo:<10.43`, `foo`, -inf, nextafter(10.43, -inf))
|
||||||
|
f(`foo: < -10.43`, `foo`, -inf, nextafter(-10.43, -inf))
|
||||||
|
f(`foo:<=10.43`, `foo`, -inf, 10.43)
|
||||||
|
f(`foo: <= 10.43`, `foo`, -inf, 10.43)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseQuerySuccess(t *testing.T) {
|
func TestParseQuerySuccess(t *testing.T) {
|
||||||
|
@ -723,6 +732,13 @@ func TestParseQuerySuccess(t *testing.T) {
|
||||||
f(`range(0x1ff, inf)`, `range(0x1ff, inf)`)
|
f(`range(0x1ff, inf)`, `range(0x1ff, inf)`)
|
||||||
f(`range(-INF,+inF)`, `range(-INF, +inF)`)
|
f(`range(-INF,+inF)`, `range(-INF, +inF)`)
|
||||||
f(`range(1.5K, 22.5GiB)`, `range(1.5K, 22.5GiB)`)
|
f(`range(1.5K, 22.5GiB)`, `range(1.5K, 22.5GiB)`)
|
||||||
|
f(`foo:range(5,inf)`, `foo:range(5, inf)`)
|
||||||
|
|
||||||
|
// >, >=, < and <= filter
|
||||||
|
f(`foo: > 10.5M`, `foo:>10.5M`)
|
||||||
|
f(`foo: >= 10.5M`, `foo:>=10.5M`)
|
||||||
|
f(`foo: < 10.5M`, `foo:<10.5M`)
|
||||||
|
f(`foo: <= 10.5M`, `foo:<=10.5M`)
|
||||||
|
|
||||||
// re filter
|
// re filter
|
||||||
f("re('foo|ba(r.+)')", `re("foo|ba(r.+)")`)
|
f("re('foo|ba(r.+)')", `re("foo|ba(r.+)")`)
|
||||||
|
|
Loading…
Reference in a new issue