From 36a8e809253d95a84675700c6a62ffc912812383 Mon Sep 17 00:00:00 2001 From: brharrington Date: Tue, 26 Mar 2024 12:18:46 -0500 Subject: [PATCH] core: support chaining child queries (#1628) Update matcher to make it more convenient to chain together child queries to indicate a path. --- .../atlas/core/model/TraceVocabulary.scala | 8 ++++++- .../atlas/lwc/events/TraceMatcherSuite.scala | 22 ++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/atlas-core/src/main/scala/com/netflix/atlas/core/model/TraceVocabulary.scala b/atlas-core/src/main/scala/com/netflix/atlas/core/model/TraceVocabulary.scala index e0be14dbd..f4bf19fb9 100644 --- a/atlas-core/src/main/scala/com/netflix/atlas/core/model/TraceVocabulary.scala +++ b/atlas-core/src/main/scala/com/netflix/atlas/core/model/TraceVocabulary.scala @@ -86,12 +86,18 @@ object TraceVocabulary extends Vocabulary { override def name: String = "child" override protected def matcher: PartialFunction[List[Any], Boolean] = { - case (_: Query) :: (_: Query) :: _ => true + case (_: Query) :: (_: Query) :: _ => true + case (_: Query) :: (_: TraceQuery.Child) :: _ => true + case (_: Query) :: TraceQuery.SpanAnd(_, _: TraceQuery.Child) :: _ => true } override protected def executor: PartialFunction[List[Any], List[Any]] = { case (q2: Query) :: (q1: Query) :: stack => TraceQuery.Child(q1, q2) :: stack + case (q2: Query) :: (tq: TraceQuery.Child) :: stack => + TraceQuery.SpanAnd(tq, TraceQuery.Child(tq.q2, q2)) :: stack + case (q2: Query) :: (s @ TraceQuery.SpanAnd(_, tq: TraceQuery.Child)) :: stack => + TraceQuery.SpanAnd(s, TraceQuery.Child(tq.q2, q2)) :: stack } override def signature: String = "q1:TraceQuery q2:TraceQuery -- TraceQuery" diff --git a/atlas-lwc-events/src/test/scala/com/netflix/atlas/lwc/events/TraceMatcherSuite.scala b/atlas-lwc-events/src/test/scala/com/netflix/atlas/lwc/events/TraceMatcherSuite.scala index 268770591..32243e055 100644 --- a/atlas-lwc-events/src/test/scala/com/netflix/atlas/lwc/events/TraceMatcherSuite.scala +++ b/atlas-lwc-events/src/test/scala/com/netflix/atlas/lwc/events/TraceMatcherSuite.scala @@ -42,13 +42,20 @@ class TraceMatcherSuite extends FunSuite { ) } + /** + * a - b + * - c - e - g + * - f + * - d + */ private val sampleTrace = List( mkSpan("a", "1", null, 0L, 100L), mkSpan("b", "2", "1", 1L, 25L), mkSpan("c", "3", "1", 5L, 90L), mkSpan("d", "4", "1", 15L, 50L), mkSpan("e", "5", "3", 8L, 50L), - mkSpan("f", "6", "3", 55L, 20L) + mkSpan("f", "6", "3", 55L, 20L), + mkSpan("g", "7", "5", 4L, 5L) ) private def checkMatch(query: TraceQuery, shouldMatch: Boolean): Unit = { @@ -91,6 +98,19 @@ class TraceMatcherSuite extends FunSuite { val q3 = ExprUtils.parseTraceEventsQuery("app,a,:eq,app,e,:eq,:child").q checkMatch(q3, false) } + + test("transitive child") { + val q1 = ExprUtils.parseTraceEventsQuery("app,a,:eq,app,c,:eq,:child,app,e,:eq,:child").q + checkMatch(q1, true) + + val q2 = ExprUtils.parseTraceEventsQuery("app,a,:eq,app,b,:eq,:child,app,e,:eq,:child").q + checkMatch(q2, false) + + val q3 = ExprUtils + .parseTraceEventsQuery("app,a,:eq,app,c,:eq,:child,app,e,:eq,:child,app,g,:eq,:child") + .q + checkMatch(q1, true) + } } object TraceMatcherSuite {