Skip to content

Commit

Permalink
Serialize query AST to JSON. (#11123)
Browse files Browse the repository at this point in the history
**What this PR does / why we need it**:
This introduces the visitor pattern to serialize the LogQL AST to JSON.
We've chose this pattern because it will be more flexible one the AST is
encoded into Protobuf and an actual queryplan.

**Checklist**
- [ ] Reviewed the
[`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md)
guide (**required**)
- [ ] Documentation added
- [x] Tests updated
- [ ] `CHANGELOG.md` updated
- [ ] If the change is worth mentioning in the release notes, add
`add-to-release-notes` label
- [ ] Changes that require user attention or interaction to upgrade are
documented in `docs/sources/setup/upgrade/_index.md`
- [ ] For Helm chart changes bump the Helm chart version in
`production/helm/loki/Chart.yaml` and update
`production/helm/loki/CHANGELOG.md` and
`production/helm/loki/README.md`. [Example
PR](d10549e)
- [ ] If the change is deprecating or removing a configuration option,
update the `deprecated-config.yaml` and `deleted-config.yaml` files
respectively in the `tools/deprecated-config-checker` directory.
[Example
PR](0d4416a)
  • Loading branch information
jeschkies authored Nov 14, 2023
1 parent 32e9ee8 commit 3a7b5d2
Show file tree
Hide file tree
Showing 7 changed files with 3,632 additions and 2,434 deletions.
30 changes: 16 additions & 14 deletions pkg/logql/log/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,39 +78,41 @@ func (f *IPLineFilter) filterTy(line []byte, ty labels.MatchType) bool {

type IPLabelFilter struct {
ip *ipFilter
ty LabelFilterType
Ty LabelFilterType

// if used as label matcher, this holds the identifier label name.
// if used as Label matcher, this holds the identifier Label name.
// e.g: (|remote_addr = ip("xxx")). Here labelName is `remote_addr`
label string
Label string

// patError records if given pattern is invalid.
patError error

// local copy of pattern to display it in errors, even though pattern matcher fails because of invalid pattern.
pattern string
// local copy of Pattern to display it in errors, even though Pattern matcher fails because of invalid Pattern.
Pattern string
}

// NewIPLabelFilter is used to construct ip filter as label filter for the given `label`.
func NewIPLabelFilter(pattern string, label string, ty LabelFilterType) *IPLabelFilter {
func NewIPLabelFilter(pattern, label string, ty LabelFilterType) *IPLabelFilter {
ip, err := newIPFilter(pattern)
return &IPLabelFilter{
ip: ip,
label: label,
ty: ty,
Label: label,
Ty: ty,
patError: err,
pattern: pattern,
Pattern: pattern,
}
}

// `Process` implements `Stage` interface
func (f *IPLabelFilter) Process(_ int64, line []byte, lbs *LabelsBuilder) ([]byte, bool) {
return line, f.filterTy(line, f.ty, lbs)
return line, f.filterTy(line, f.Ty, lbs)
}

func (f *IPLabelFilter) isLabelFilterer() {}

// `RequiredLabelNames` implements `Stage` interface
func (f *IPLabelFilter) RequiredLabelNames() []string {
return []string{f.label}
return []string{f.Label}
}

// PatternError will be used `labelFilter.Stage()` method so that, if the given pattern is wrong
Expand All @@ -124,7 +126,7 @@ func (f *IPLabelFilter) filterTy(_ []byte, ty LabelFilterType, lbs *LabelsBuilde
// why `true`?. if there's an error only the string matchers can filter out.
return true
}
input, ok := lbs.Get(f.label)
input, ok := lbs.Get(f.Label)
if !ok {
// we have not found the label.
return false
Expand All @@ -146,11 +148,11 @@ func (f *IPLabelFilter) filterTy(_ []byte, ty LabelFilterType, lbs *LabelsBuilde
// `String` implements fmt.Stringer inteface, by which also implements `LabelFilterer` inteface.
func (f *IPLabelFilter) String() string {
eq := "=" // LabelFilterEqual -> "==", we don't want in string representation of ip label filter.
if f.ty == LabelFilterNotEqual {
if f.Ty == LabelFilterNotEqual {
eq = LabelFilterNotEqual.String()
}

return fmt.Sprintf("%s%sip(%q)", f.label, eq, f.pattern) // label filter
return fmt.Sprintf("%s%sip(%q)", f.Label, eq, f.Pattern) // label filter
}

// ipFilter search for IP addresses of given `pattern` in the given `line`.
Expand Down
44 changes: 32 additions & 12 deletions pkg/logql/log/label_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,28 @@ func (f LabelFilterType) String() string {
}

// LabelFilterer can filter extracted labels.
//
//sumtype:decl
type LabelFilterer interface {
Stage
fmt.Stringer

// Seal trait
isLabelFilterer()
}

type BinaryLabelFilter struct {
Left LabelFilterer
Right LabelFilterer
and bool
And bool
}

// NewAndLabelFilter creates a new LabelFilterer from a and binary operation of two LabelFilterer.
func NewAndLabelFilter(left LabelFilterer, right LabelFilterer) *BinaryLabelFilter {
return &BinaryLabelFilter{
Left: left,
Right: right,
and: true,
And: true,
}
}

Expand All @@ -84,16 +89,18 @@ func NewOrLabelFilter(left LabelFilterer, right LabelFilterer) *BinaryLabelFilte

func (b *BinaryLabelFilter) Process(ts int64, line []byte, lbs *LabelsBuilder) ([]byte, bool) {
line, lok := b.Left.Process(ts, line, lbs)
if !b.and && lok {
if !b.And && lok {
return line, true
}
line, rok := b.Right.Process(ts, line, lbs)
if !b.and {
if !b.And {
return line, lok || rok
}
return line, lok && rok
}

func (b *BinaryLabelFilter) isLabelFilterer() {}

func (b *BinaryLabelFilter) RequiredLabelNames() []string {
var names []string
names = append(names, b.Left.RequiredLabelNames()...)
Expand All @@ -105,7 +112,7 @@ func (b *BinaryLabelFilter) String() string {
var sb strings.Builder
sb.WriteString("( ")
sb.WriteString(b.Left.String())
if b.and {
if b.And {
sb.WriteString(" , ")
} else {
sb.WriteString(" or ")
Expand All @@ -122,6 +129,9 @@ type NoopLabelFilter struct {
func (NoopLabelFilter) Process(_ int64, line []byte, _ *LabelsBuilder) ([]byte, bool) {
return line, true
}

func (NoopLabelFilter) isLabelFilterer() {}

func (NoopLabelFilter) RequiredLabelNames() []string { return []string{} }

func (f NoopLabelFilter) String() string {
Expand Down Expand Up @@ -197,6 +207,8 @@ func (d *BytesLabelFilter) Process(_ int64, line []byte, lbs *LabelsBuilder) ([]
}
}

func (d *BytesLabelFilter) isLabelFilterer() {}

func (d *BytesLabelFilter) RequiredLabelNames() []string {
return []string{d.Name}
}
Expand All @@ -207,7 +219,7 @@ func (d *BytesLabelFilter) String() string {
return -1
}
return r
}, humanize.Bytes(d.Value))
}, humanize.Bytes(d.Value)) // TODO: discuss whether this should just be bytes, B, to be more accurate.
return fmt.Sprintf("%s%s%s", d.Name, d.Type, b)
}

Expand Down Expand Up @@ -262,6 +274,8 @@ func (d *DurationLabelFilter) Process(_ int64, line []byte, lbs *LabelsBuilder)
}
}

func (d *DurationLabelFilter) isLabelFilterer() {}

func (d *DurationLabelFilter) RequiredLabelNames() []string {
return []string{d.Name}
}
Expand Down Expand Up @@ -323,6 +337,8 @@ func (n *NumericLabelFilter) Process(_ int64, line []byte, lbs *LabelsBuilder) (

}

func (n *NumericLabelFilter) isLabelFilterer() {}

func (n *NumericLabelFilter) RequiredLabelNames() []string {
return []string{n.Name}
}
Expand All @@ -348,7 +364,7 @@ func NewStringLabelFilter(m *labels.Matcher) LabelFilterer {
return &NoopLabelFilter{m}
}

return &lineFilterLabelFilter{
return &LineFilterLabelFilter{
Matcher: m,
filter: f,
}
Expand All @@ -358,18 +374,20 @@ func (s *StringLabelFilter) Process(_ int64, line []byte, lbs *LabelsBuilder) ([
return line, s.Matches(labelValue(s.Name, lbs))
}

func (s *StringLabelFilter) isLabelFilterer() {}

func (s *StringLabelFilter) RequiredLabelNames() []string {
return []string{s.Name}
}

// lineFilterLabelFilter filters the desired label using an optimized line filter
type lineFilterLabelFilter struct {
// LineFilterLabelFilter filters the desired label using an optimized line filter
type LineFilterLabelFilter struct {
*labels.Matcher
filter Filterer
}

// overrides the matcher.String() function in case there is a regexpFilter
func (s *lineFilterLabelFilter) String() string {
func (s *LineFilterLabelFilter) String() string {
if unwrappedFilter, ok := s.filter.(regexpFilter); ok {
rStr := unwrappedFilter.String()
str := fmt.Sprintf("%s%s`%s`", s.Matcher.Name, s.Matcher.Type, rStr)
Expand All @@ -378,12 +396,14 @@ func (s *lineFilterLabelFilter) String() string {
return s.Matcher.String()
}

func (s *lineFilterLabelFilter) Process(_ int64, line []byte, lbs *LabelsBuilder) ([]byte, bool) {
func (s *LineFilterLabelFilter) Process(_ int64, line []byte, lbs *LabelsBuilder) ([]byte, bool) {
v := labelValue(s.Name, lbs)
return line, s.filter.Filter(unsafeGetBytes(v))
}

func (s *lineFilterLabelFilter) RequiredLabelNames() []string {
func (s *LineFilterLabelFilter) isLabelFilterer() {}

func (s *LineFilterLabelFilter) RequiredLabelNames() []string {
return []string{s.Name}
}

Expand Down
Loading

0 comments on commit 3a7b5d2

Please sign in to comment.