Skip to content
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
457f436
Test case for queries containing array attributes
stoewer Jul 14, 2024
4edecba
SyncIterator tracks array values
stoewer Jul 14, 2024
349df5f
Move makeIterFn to definition of makeIterFunc
stoewer Jul 14, 2024
3740085
Extend makeIterFn with sync iterator options
stoewer Jul 14, 2024
d502c24
Set repetition level option for attribute iterators
stoewer Jul 14, 2024
f280fee
Entries in IteratorResult can have multiple values
stoewer Jul 15, 2024
2e40b7a
Efficient allocation of entry values in SyncIterator
stoewer Jul 15, 2024
1ec36fd
Change vp4 to work with multiple values in IteratorResults
stoewer Jul 15, 2024
1ee6db3
Change vp3 to work with multiple values in IteratorResults
stoewer Jul 15, 2024
e9ac07f
Change vp2 to work with multiple values in IteratorResults
stoewer Jul 15, 2024
c14397f
Support array operands in TraceQL engine for second pass filtering
stoewer Jul 16, 2024
5cc691b
Fix entry value access in mapEventAttr
stoewer Jul 16, 2024
69dfdfc
Static.AsAnyValue() supports arrays
stoewer Jul 16, 2024
5595d11
Fix linter warnings
stoewer Jul 16, 2024
efd8c10
Avoid allocations when adding entries to results
stoewer Jul 17, 2024
929bec4
Test for SyncIterator reading arrays
stoewer Jul 17, 2024
53451d6
Explain array collection in SyncIterator.next()
stoewer Jul 18, 2024
fd9afd3
Rename option to enable array collection in SyncIterator
stoewer Jul 18, 2024
a20a3d4
fix after rebease
electron0zero Jul 31, 2024
17b860c
it is fast but does it pass CI
electron0zero Aug 2, 2024
750073e
Add test for isMatchingOperand and isMatchingArrayElement
electron0zero Aug 7, 2024
c0865be
clean up and add benchmark blockID and path
electron0zero Aug 7, 2024
fd1de46
Add tests for arrys AsAnyValue
electron0zero Aug 13, 2024
a2791cd
fix lint
electron0zero Aug 14, 2024
5579b88
SyncIterator and IteratorResult changes
electron0zero Aug 15, 2024
b8053a3
SyncIterator and IteratorResult changes vparquet4
electron0zero Aug 15, 2024
2dd8005
revert SyncIterator back to pq.Value
electron0zero Aug 15, 2024
ab1821f
rename back to currValues
electron0zero Aug 15, 2024
4d14ab5
undo extra cosmatic changes
electron0zero Aug 16, 2024
f08b5a9
refactor arrays support in traceql
electron0zero Aug 19, 2024
7f3728e
make array support symmetric + tests
electron0zero Aug 20, 2024
3ea2d31
cleanup comments
electron0zero Aug 20, 2024
efe1244
undo extra changes
electron0zero Aug 20, 2024
c031af8
rework attribute collector keep group
electron0zero Aug 21, 2024
694c7df
make getelements use a VisitFunc
electron0zero Aug 21, 2024
1b10ebd
cleanup symmetric array support
electron0zero Aug 21, 2024
e39bafe
fix and expand StaticType tests
electron0zero Aug 21, 2024
2b3df1c
Update changelog and cleanup
electron0zero Aug 21, 2024
8edca29
Merge branch 'main' into traceql-collect-arrays
electron0zero Aug 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## main / unreleased

* [ENHANCEMENT] TraceQL: Attribute iterators collect matched array values [#3867](https://github.com/grafana/tempo/pull/3867) (@electron0zero, @stoewer)
* [CHANGE] **BREAKING CHANGE** Remove `autocomplete_filtering_enabled` feature flag [#3729](https://github.com/grafana/tempo/pull/3729) (@mapno)
* [CHANGE] Bump opentelemetry-collector to 0.102.1 [#3784](https://github.com/grafana/tempo/pull/3784) (@debasishbsws)
* [CHANGE] Bump Jaeger query docker image to 1.57.0 [#3652](https://github.com/grafana/tempo/issues/3652) (@iblancasa)
Expand Down
46 changes: 46 additions & 0 deletions pkg/traceql/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,52 @@ func (s Static) compare(o *Static) int {
}
}

type VisitFunc func(Static) bool // Return false to stop iteration

// GetElements turns arrays into slice of Static elements to iterate over.
func (s Static) GetElements(fn VisitFunc) error {
switch s.Type {
case TypeIntArray:
ints, _ := s.IntArray()
for _, n := range ints {
if !fn(NewStaticInt(n)) {
break // stop early if the callback returns false
}
}
return nil

case TypeFloatArray:
floats, _ := s.FloatArray()
for _, f := range floats {
if !fn(NewStaticFloat(f)) {
break
}
}
return nil

case TypeStringArray:
strs, _ := s.StringArray()
for _, str := range strs {
if !fn(NewStaticString(str)) {
break
}
}
return nil

case TypeBooleanArray:
bools, _ := s.BooleanArray()
for _, b := range bools {
if !fn(NewStaticBool(b)) {
break
}
}
return nil

default:
return fmt.Errorf("unsupported type")
}
}

func (s Static) Int() (int, bool) {
if s.Type != TypeInt {
return 0, false
Expand Down
51 changes: 50 additions & 1 deletion pkg/traceql/ast_execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ func (o *BinaryOperation) execute(span Span) (Static, error) {
}

// if both sides are integers then do integer math, otherwise we can drop to the
// catch all below
// catch-all below
if lhsT == TypeInt && rhsT == TypeInt {
lhsN, _ := lhs.Int()
rhsN, _ := rhs.Int()
Expand Down Expand Up @@ -422,6 +422,39 @@ func (o *BinaryOperation) execute(span Span) (Static, error) {
}
}

if lhsT.isMatchingArrayElement(rhsT) {
// we only support boolean op in the arrays
if !o.Op.isBoolean() {
return NewStaticNil(), errors.ErrUnsupported
}

elemOp := &BinaryOperation{Op: o.Op, LHS: lhs, RHS: rhs}
arraySide := lhs
// to support symmetric operations
if rhsT.isArray() {
// for regex operations, TraceQL makes an assumption that RHS is the regex, and compiles it.
// we can support symmetric array operations by flipping the sides and executing the binary operation.
elemOp = &BinaryOperation{Op: getFlippedOp(o.Op), LHS: rhs, RHS: lhs}
arraySide = rhs
}

var res Static
err := arraySide.GetElements(func(elem Static) bool {
elemOp.LHS = elem
res, err = elemOp.execute(span)
if err != nil {
return false // stop iteration early if there's an error
}
match, ok := res.Bool()
return !(ok && match) // stop if a match is found
})
if err != nil {
return NewStaticNil(), err
}

return res, err
}

switch o.Op {
case OpAdd:
return NewStaticFloat(lhs.Float() + rhs.Float()), nil
Expand Down Expand Up @@ -452,6 +485,22 @@ func (o *BinaryOperation) execute(span Span) (Static, error) {
}
}

// getFlippedOp will return the flipped op, used when flipping the LHS and RHS of a BinaryOperation
func getFlippedOp(op Operator) Operator {
switch op {
case OpGreater:
return OpLess
case OpGreaterEqual:
return OpLessEqual
case OpLess:
return OpGreater
case OpLessEqual:
return OpGreaterEqual
default:
return op
}
}

// why does this and the above exist?
func binOp(op Operator, lhs, rhs Static) (bool, error) {
lhsT := lhs.impliedType()
Expand Down
Loading