diff --git a/atlas-core/src/main/scala/com/netflix/atlas/core/model/MathExpr.scala b/atlas-core/src/main/scala/com/netflix/atlas/core/model/MathExpr.scala index e56d04c40..287f7f232 100644 --- a/atlas-core/src/main/scala/com/netflix/atlas/core/model/MathExpr.scala +++ b/atlas-core/src/main/scala/com/netflix/atlas/core/model/MathExpr.scala @@ -872,9 +872,10 @@ object MathExpr { override def append(builder: java.lang.StringBuilder): Unit = { // Base expr - Interpreter.append(builder, expr.af.query) if (evalGroupKeys.nonEmpty) Interpreter.append(builder, expr.af.query, evalGroupKeys, ":by") + else + Interpreter.append(builder, expr.af.query) // Percentiles builder.append(",(,") diff --git a/atlas-core/src/test/scala/com/netflix/atlas/core/model/PercentilesSuite.scala b/atlas-core/src/test/scala/com/netflix/atlas/core/model/PercentilesSuite.scala index 9d3aa751c..f0bd71477 100644 --- a/atlas-core/src/test/scala/com/netflix/atlas/core/model/PercentilesSuite.scala +++ b/atlas-core/src/test/scala/com/netflix/atlas/core/model/PercentilesSuite.scala @@ -35,17 +35,25 @@ class PercentilesSuite extends FunSuite { private val step = 60000L private val context = EvalContext(start, start + step * 2, step) - def ts(bucket: String, values: Double*): TimeSeries = { + private def ts(bucket: String, values: Double*): TimeSeries = { val seq = new ArrayTimeSeq(DsType.Gauge, start, step, values.toArray) val mode = if (Integer.parseInt(bucket.substring(1), 16) % 2 == 0) "even" else "odd" TimeSeries(Map("name" -> "test", "mode" -> mode, "percentile" -> bucket), seq) } - def eval(str: String, input: List[TimeSeries]): List[TimeSeries] = { - val expr = interpreter.execute(str).stack match { + private def parseExpr(str: String): TimeSeriesExpr = { + interpreter.execute(str).stack match { case (v: TimeSeriesExpr) :: _ => v case _ => throw new IllegalArgumentException("invalid expr") } + } + + private def eval(str: String, input: List[TimeSeries]): List[TimeSeries] = { + val expr = parseExpr(str) + // Verify we can reparse the string representation and get an identical expression. + val e2 = parseExpr(expr.toString) + val e3 = parseExpr(e2.toString) + assertEquals(e2, e3) expr.eval(context, input).data } @@ -308,6 +316,19 @@ class PercentilesSuite extends FunSuite { } } + test("group by with math") { + val data = eval("name,test,:eq,(,mode,),:by,(,90,),:percentiles,1000,:mul", input100) + .sortWith(_.tags("mode") < _.tags("mode")) + + assertEquals(data.size, 2) + List("even", "odd").zip(data).foreach { + case (m, t) => + val estimate = t.data(0L) + assertEquals(t.tags, Map("name" -> "test", "mode" -> m, "percentile" -> " 90.0")) + assertEquals(t.label, f"(percentile((mode=$m), 90.0) * 1000.0)") + } + } + test("distribution summary empty") { val data = eval(":false,(,25,50,90,),:percentiles", input100) assertEquals(data.size, 0)