Skip to content

Commit

Permalink
core: support query matching using tags function (#1743)
Browse files Browse the repository at this point in the history
Add `Query.matches` overload that takes a function to supply
the tags. This can be used for cases like `LwcEvent` to do
matching where the data structure for the tags may not be
known.
  • Loading branch information
brharrington authored Jan 27, 2025
1 parent 27eaaa7 commit da8f0c6
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 0 deletions.
20 changes: 20 additions & 0 deletions atlas-core/src/main/scala/com/netflix/atlas/core/model/Query.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import com.netflix.spectator.impl.PatternMatcher

sealed trait Query extends Expr {

/** Returns true if the query expression matches the tags provided by the function. */
def matches(tags: String => String): Boolean

/** Returns true if the query expression matches the tags. */
def matches(tags: Map[String, String]): Boolean

Expand Down Expand Up @@ -238,6 +241,8 @@ object Query {

case object True extends Query {

def matches(tags: String => String): Boolean = true

def matches(tags: Map[String, String]): Boolean = true

def matchesAny(tags: Map[String, List[String]]): Boolean = true
Expand All @@ -259,6 +264,8 @@ object Query {

case object False extends Query {

def matches(tags: String => String): Boolean = false

def matches(tags: Map[String, String]): Boolean = false

def matchesAny(tags: Map[String, List[String]]): Boolean = false
Expand Down Expand Up @@ -287,6 +294,11 @@ object Query {

def check(s: String): Boolean

def matches(tags: String => String): Boolean = {
val v = tags(k)
v != null && check(v)
}

def matches(tags: Map[String, String]): Boolean = {
tags match {
case ts: SortedTagMap =>
Expand Down Expand Up @@ -314,6 +326,8 @@ object Query {

case class HasKey(k: String) extends KeyQuery {

def matches(tags: String => String): Boolean = tags(k) != null

def matches(tags: Map[String, String]): Boolean = tags.contains(k)

def matchesAny(tags: Map[String, List[String]]): Boolean = tags.contains(k)
Expand Down Expand Up @@ -436,6 +450,8 @@ object Query {

case class And(q1: Query, q2: Query) extends Query {

def matches(tags: String => String): Boolean = q1.matches(tags) && q2.matches(tags)

def matches(tags: Map[String, String]): Boolean = q1.matches(tags) && q2.matches(tags)

def matchesAny(tags: Map[String, List[String]]): Boolean =
Expand All @@ -452,6 +468,8 @@ object Query {

case class Or(q1: Query, q2: Query) extends Query {

def matches(tags: String => String): Boolean = q1.matches(tags) || q2.matches(tags)

def matches(tags: Map[String, String]): Boolean = q1.matches(tags) || q2.matches(tags)

def matchesAny(tags: Map[String, List[String]]): Boolean =
Expand All @@ -468,6 +486,8 @@ object Query {

case class Not(q: Query) extends Query {

def matches(tags: String => String): Boolean = !q.matches(tags)

def matches(tags: Map[String, String]): Boolean = !q.matches(tags)

def matchesAny(tags: Map[String, List[String]]): Boolean = !q.matchesAny(tags)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class QuerySuite extends FunSuite {
def matches(q: Query, tags: Map[String, String]): Boolean = {
val result = q.matches(tags)
assertEquals(result, q.matches(SortedTagMap(tags)))
assertEquals(result, q.matches(SortedTagMap(tags).getOrNull _))
result
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.netflix.atlas.lwc.events

import com.netflix.atlas.core.model.Query
import com.netflix.atlas.core.util.SortedTagMap
import com.netflix.atlas.json.Json
import com.netflix.spectator.api.Clock
Expand Down Expand Up @@ -218,6 +219,13 @@ class LwcEventClientSuite extends FunSuite {
assert(vs.forall(_.contains(""""tags":{"value":"duration"}""")))
assert(vs.forall(_.contains(""""value":8.4""")))
}

test("check if event matches query") {
val matching = Query.And(Query.Equal("app", "www"), Query.Equal("node", "i-123"))
val nonMatching = Query.And(Query.Equal("app", "www"), Query.Equal("node", "i-124"))
assert(matching.matches(sampleLwcEvent.tagValue _))
assert(!nonMatching.matches(sampleLwcEvent.tagValue _))
}
}

object LwcEventClientSuite {
Expand Down

0 comments on commit da8f0c6

Please sign in to comment.