From 9edf0ed7a7bd56852ca1ff8581a5375ae8ecc549 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Fri, 31 May 2024 11:16:06 -0500 Subject: [PATCH 01/22] lexer first --- pkg/traceql/expr.y | 7 +- pkg/traceql/expr.y.go | 484 ++++++++++---------- pkg/traceql/lexer.go | 7 +- pkg/traceql/lexer_test.go | 7 + pkg/traceql/parse_test.go | 1 + pkg/traceql/test_examples.yaml | 2 +- tempodb/encoding/vparquet4/block_traceql.go | 7 + 7 files changed, 271 insertions(+), 244 deletions(-) diff --git a/pkg/traceql/expr.y b/pkg/traceql/expr.y index d9c39c63650..8a2e15ebe1f 100644 --- a/pkg/traceql/expr.y +++ b/pkg/traceql/expr.y @@ -94,7 +94,7 @@ import ( KIND_UNSPECIFIED KIND_INTERNAL KIND_SERVER KIND_CLIENT KIND_PRODUCER KIND_CONSUMER IDURATION CHILDCOUNT NAME STATUS STATUS_MESSAGE PARENT KIND ROOTNAME ROOTSERVICENAME ROOTSERVICE TRACEDURATION NESTEDSETLEFT NESTEDSETRIGHT NESTEDSETPARENT ID TRACE_ID SPAN_ID - PARENT_DOT RESOURCE_DOT SPAN_DOT TRACE_COLON SPAN_COLON EVENT_COLON LINK_COLON + PARENT_DOT RESOURCE_DOT SPAN_DOT TRACE_COLON SPAN_COLON EVENT_COLON EVENT_DOT LINK_COLON COUNT AVG MAX MIN SUM BY COALESCE SELECT END_ATTRIBUTE @@ -405,9 +405,9 @@ scopedIntrinsicField: | SPAN_COLON STATUS_MESSAGE { $$ = NewIntrinsic(IntrinsicStatusMessage) } | SPAN_COLON ID { $$ = NewIntrinsic(IntrinsicSpanID) } // event: - | EVENT_COLON NAME { $$ = NewIntrinsic(IntrinsicEventName) } + | EVENT_COLON NAME { $$ = NewIntrinsic(IntrinsicEventName) } // link: - | LINK_COLON TRACE_ID { $$ = NewIntrinsic(IntrinsicLinkTraceID) } + | LINK_COLON TRACE_ID { $$ = NewIntrinsic(IntrinsicLinkTraceID) } | LINK_COLON SPAN_ID { $$ = NewIntrinsic(IntrinsicLinkSpanID) } ; @@ -418,4 +418,5 @@ attributeField: | PARENT_DOT IDENTIFIER END_ATTRIBUTE { $$ = NewScopedAttribute(AttributeScopeNone, true, $2) } | PARENT_DOT RESOURCE_DOT IDENTIFIER END_ATTRIBUTE { $$ = NewScopedAttribute(AttributeScopeResource, true, $3) } | PARENT_DOT SPAN_DOT IDENTIFIER END_ATTRIBUTE { $$ = NewScopedAttribute(AttributeScopeSpan, true, $3) } + | EVENT_DOT IDENTIFIER END_ATTRIBUTE { $$ = NewScopedAttribute(AttributeScopeEvent, false, $2) } ; diff --git a/pkg/traceql/expr.y.go b/pkg/traceql/expr.y.go index c2458817be1..a1e6c539321 100644 --- a/pkg/traceql/expr.y.go +++ b/pkg/traceql/expr.y.go @@ -101,52 +101,53 @@ const SPAN_DOT = 57388 const TRACE_COLON = 57389 const SPAN_COLON = 57390 const EVENT_COLON = 57391 -const LINK_COLON = 57392 -const COUNT = 57393 -const AVG = 57394 -const MAX = 57395 -const MIN = 57396 -const SUM = 57397 -const BY = 57398 -const COALESCE = 57399 -const SELECT = 57400 -const END_ATTRIBUTE = 57401 -const RATE = 57402 -const COUNT_OVER_TIME = 57403 -const QUANTILE_OVER_TIME = 57404 -const HISTOGRAM_OVER_TIME = 57405 -const COMPARE = 57406 -const WITH = 57407 -const PIPE = 57408 -const AND = 57409 -const OR = 57410 -const EQ = 57411 -const NEQ = 57412 -const LT = 57413 -const LTE = 57414 -const GT = 57415 -const GTE = 57416 -const NRE = 57417 -const RE = 57418 -const DESC = 57419 -const ANCE = 57420 -const SIBL = 57421 -const NOT_CHILD = 57422 -const NOT_PARENT = 57423 -const NOT_DESC = 57424 -const NOT_ANCE = 57425 -const UNION_CHILD = 57426 -const UNION_PARENT = 57427 -const UNION_DESC = 57428 -const UNION_ANCE = 57429 -const UNION_SIBL = 57430 -const ADD = 57431 -const SUB = 57432 -const NOT = 57433 -const MUL = 57434 -const DIV = 57435 -const MOD = 57436 -const POW = 57437 +const EVENT_DOT = 57392 +const LINK_COLON = 57393 +const COUNT = 57394 +const AVG = 57395 +const MAX = 57396 +const MIN = 57397 +const SUM = 57398 +const BY = 57399 +const COALESCE = 57400 +const SELECT = 57401 +const END_ATTRIBUTE = 57402 +const RATE = 57403 +const COUNT_OVER_TIME = 57404 +const QUANTILE_OVER_TIME = 57405 +const HISTOGRAM_OVER_TIME = 57406 +const COMPARE = 57407 +const WITH = 57408 +const PIPE = 57409 +const AND = 57410 +const OR = 57411 +const EQ = 57412 +const NEQ = 57413 +const LT = 57414 +const LTE = 57415 +const GT = 57416 +const GTE = 57417 +const NRE = 57418 +const RE = 57419 +const DESC = 57420 +const ANCE = 57421 +const SIBL = 57422 +const NOT_CHILD = 57423 +const NOT_PARENT = 57424 +const NOT_DESC = 57425 +const NOT_ANCE = 57426 +const UNION_CHILD = 57427 +const UNION_PARENT = 57428 +const UNION_DESC = 57429 +const UNION_ANCE = 57430 +const UNION_SIBL = 57431 +const ADD = 57432 +const SUB = 57433 +const NOT = 57434 +const MUL = 57435 +const DIV = 57436 +const MOD = 57437 +const POW = 57438 var yyToknames = [...]string{ "$end", @@ -198,6 +199,7 @@ var yyToknames = [...]string{ "TRACE_COLON", "SPAN_COLON", "EVENT_COLON", + "EVENT_DOT", "LINK_COLON", "COUNT", "AVG", @@ -256,158 +258,158 @@ var yyExca = [...]int{ -1, 1, 1, -1, -2, 0, - -1, 284, + -1, 286, 13, 86, -2, 94, } const yyPrivate = 57344 -const yyLast = 949 +const yyLast = 948 var yyAct = [...]int{ - 101, 5, 100, 6, 99, 8, 222, 7, 272, 98, - 12, 67, 18, 13, 282, 2, 241, 90, 223, 94, - 77, 319, 198, 70, 66, 228, 229, 198, 230, 231, - 232, 241, 149, 199, 150, 30, 153, 29, 151, 85, - 86, 329, 87, 88, 89, 90, 230, 231, 232, 241, - 179, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 316, 72, 73, - 328, 74, 75, 76, 77, 326, 310, 315, 309, 308, - 199, 205, 87, 88, 89, 90, 74, 75, 76, 77, - 307, 356, 343, 226, 333, 225, 332, 224, 213, 215, - 216, 217, 218, 219, 220, 264, 265, 263, 364, 289, - 250, 221, 360, 289, 361, 244, 245, 246, 334, 17, - 365, 242, 243, 233, 234, 235, 236, 237, 238, 240, - 239, 242, 243, 233, 234, 235, 236, 237, 238, 240, - 239, 68, 11, 228, 229, 335, 230, 231, 232, 241, - 325, 251, 252, 228, 229, 321, 230, 231, 232, 241, - 320, 279, 266, 267, 268, 269, 270, 353, 289, 352, - 289, 350, 351, 280, 233, 234, 235, 236, 237, 238, - 240, 239, 279, 202, 19, 20, 21, 17, 17, 180, - 159, 359, 363, 203, 228, 229, 349, 230, 231, 232, - 241, 149, 339, 150, 338, 153, 281, 151, 348, 347, - 336, 337, 284, 204, 207, 208, 209, 210, 211, 212, - 278, 286, 317, 318, 288, 289, 277, 276, 280, 23, - 26, 24, 25, 27, 14, 160, 15, 275, 154, 155, - 156, 157, 158, 274, 206, 162, 358, 200, 290, 291, - 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 147, 146, 145, 144, 22, 85, - 86, 143, 87, 88, 89, 90, 142, 226, 226, 225, - 225, 224, 224, 92, 253, 67, 91, 67, 344, 324, - 226, 254, 225, 255, 224, 322, 323, 70, 256, 70, - 286, 48, 53, 355, 354, 50, 273, 49, 327, 57, - 312, 51, 52, 54, 55, 56, 59, 58, 60, 61, - 64, 63, 62, 84, 139, 140, 141, 330, 149, 331, - 150, 311, 153, 249, 151, 71, 342, 341, 248, 226, - 226, 225, 225, 224, 224, 345, 346, 247, 28, 271, - 226, 340, 225, 69, 224, 16, 357, 4, 148, 10, - 226, 152, 225, 1, 224, 0, 362, 102, 103, 104, - 108, 131, 0, 93, 95, 0, 0, 107, 105, 106, - 110, 109, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 124, 123, 125, 126, 0, 127, - 128, 129, 130, 201, 0, 0, 134, 132, 133, 135, - 136, 137, 138, 314, 0, 102, 103, 104, 108, 131, - 0, 0, 95, 0, 0, 107, 105, 106, 110, 109, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 124, 123, 125, 126, 0, 127, 128, 129, - 130, 313, 96, 97, 134, 132, 133, 135, 136, 137, - 138, 306, 0, 0, 0, 0, 0, 242, 243, 233, - 234, 235, 236, 237, 238, 240, 239, 0, 0, 72, - 73, 0, 74, 75, 76, 77, 0, 0, 0, 228, - 229, 287, 230, 231, 232, 241, 0, 0, 0, 227, - 96, 97, 0, 0, 0, 242, 243, 233, 234, 235, - 236, 237, 238, 240, 239, 242, 243, 233, 234, 235, - 236, 237, 238, 240, 239, 0, 0, 228, 229, 203, - 230, 231, 232, 241, 0, 0, 0, 228, 229, 0, - 230, 231, 232, 241, 0, 242, 243, 233, 234, 235, - 236, 237, 238, 240, 239, 242, 243, 233, 234, 235, - 236, 237, 238, 240, 239, 0, 0, 228, 229, 0, - 230, 231, 232, 241, 197, 0, 0, 228, 229, 0, - 230, 231, 232, 241, 0, 78, 79, 80, 81, 82, - 83, 0, 78, 79, 80, 81, 82, 83, 0, 78, - 79, 80, 81, 82, 83, 85, 86, 0, 87, 88, - 89, 90, 85, 86, 0, 87, 88, 89, 90, 72, - 73, 0, 74, 75, 76, 77, 0, 0, 31, 36, - 0, 0, 33, 0, 32, 0, 42, 0, 34, 35, - 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, - 48, 53, 0, 0, 50, 0, 49, 0, 57, 0, - 51, 52, 54, 55, 56, 59, 58, 60, 61, 64, - 63, 62, 31, 36, 0, 0, 33, 0, 32, 0, - 42, 0, 34, 35, 37, 38, 39, 40, 41, 43, - 44, 45, 46, 47, 19, 20, 21, 0, 17, 0, - 159, 0, 19, 20, 21, 0, 17, 0, 285, 0, - 19, 20, 21, 50, 17, 49, 283, 57, 0, 51, - 52, 54, 55, 56, 59, 58, 60, 61, 64, 63, - 62, 0, 0, 0, 0, 0, 0, 0, 0, 23, - 26, 24, 25, 27, 14, 160, 15, 23, 26, 24, + 101, 5, 100, 6, 99, 8, 223, 7, 274, 98, + 12, 67, 18, 13, 284, 2, 242, 90, 224, 94, + 77, 322, 200, 70, 66, 19, 20, 21, 30, 17, + 29, 287, 150, 332, 151, 331, 154, 315, 152, 229, + 230, 312, 231, 232, 233, 242, 231, 232, 233, 242, + 180, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 319, 311, 310, + 309, 23, 26, 24, 25, 27, 14, 318, 15, 85, + 86, 206, 87, 88, 89, 90, 72, 73, 199, 74, + 75, 76, 77, 227, 359, 226, 346, 225, 214, 216, + 217, 218, 219, 220, 221, 87, 88, 89, 90, 199, + 22, 222, 336, 335, 265, 245, 246, 247, 74, 75, + 76, 77, 243, 244, 234, 235, 236, 237, 238, 239, + 241, 240, 243, 244, 234, 235, 236, 237, 238, 239, + 241, 240, 329, 204, 229, 230, 364, 231, 232, 233, + 242, 251, 266, 267, 229, 230, 337, 231, 232, 233, + 242, 368, 281, 200, 269, 270, 271, 272, 367, 291, + 363, 291, 356, 291, 282, 234, 235, 236, 237, 238, + 239, 241, 240, 281, 19, 20, 21, 338, 17, 17, + 160, 181, 252, 253, 328, 229, 230, 324, 231, 232, + 233, 242, 150, 255, 151, 323, 154, 268, 152, 203, + 256, 362, 257, 286, 355, 291, 352, 258, 353, 354, + 85, 86, 288, 87, 88, 89, 90, 351, 350, 282, + 23, 26, 24, 25, 27, 14, 161, 15, 342, 155, + 156, 157, 158, 159, 339, 340, 204, 320, 321, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 341, 19, 20, 21, 22, + 17, 259, 160, 260, 262, 263, 283, 261, 280, 227, + 227, 226, 226, 225, 225, 264, 279, 67, 278, 67, + 277, 327, 227, 276, 226, 207, 225, 325, 326, 70, + 163, 70, 288, 78, 79, 80, 81, 82, 83, 148, + 330, 147, 23, 26, 24, 25, 27, 14, 161, 15, + 290, 291, 146, 85, 86, 145, 87, 88, 89, 90, + 333, 150, 334, 151, 144, 154, 143, 152, 92, 91, + 84, 17, 227, 227, 226, 226, 225, 225, 348, 349, + 366, 22, 71, 227, 361, 226, 347, 225, 28, 360, + 140, 141, 142, 227, 275, 226, 314, 225, 313, 365, + 102, 103, 104, 108, 131, 254, 93, 95, 358, 357, + 107, 105, 106, 110, 109, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 124, 123, 125, + 126, 250, 127, 128, 129, 130, 202, 345, 344, 134, + 132, 133, 136, 137, 138, 135, 139, 317, 273, 102, + 103, 104, 108, 131, 249, 248, 95, 343, 69, 107, + 105, 106, 110, 109, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 124, 123, 125, 126, + 16, 127, 128, 129, 130, 316, 96, 97, 134, 132, + 133, 136, 137, 138, 135, 139, 308, 4, 149, 10, + 153, 1, 243, 244, 234, 235, 236, 237, 238, 239, + 241, 240, 0, 72, 73, 0, 74, 75, 76, 77, + 0, 0, 0, 0, 229, 230, 289, 231, 232, 233, + 242, 0, 0, 0, 228, 96, 97, 0, 0, 0, + 243, 244, 234, 235, 236, 237, 238, 239, 241, 240, + 0, 243, 244, 234, 235, 236, 237, 238, 239, 241, + 240, 0, 229, 230, 0, 231, 232, 233, 242, 0, + 0, 0, 0, 229, 230, 0, 231, 232, 233, 242, + 0, 243, 244, 234, 235, 236, 237, 238, 239, 241, + 240, 243, 244, 234, 235, 236, 237, 238, 239, 241, + 240, 201, 0, 229, 230, 0, 231, 232, 233, 242, + 0, 0, 0, 229, 230, 0, 231, 232, 233, 242, + 78, 79, 80, 81, 82, 83, 198, 78, 79, 80, + 81, 82, 83, 0, 0, 0, 0, 0, 0, 0, + 85, 86, 0, 87, 88, 89, 90, 72, 73, 0, + 74, 75, 76, 77, 0, 0, 48, 53, 0, 0, + 50, 0, 49, 0, 57, 0, 51, 52, 54, 55, + 56, 59, 58, 60, 61, 64, 63, 62, 0, 0, + 0, 31, 36, 0, 0, 33, 0, 32, 0, 42, + 0, 34, 35, 37, 38, 39, 40, 41, 43, 44, + 45, 46, 47, 48, 53, 0, 0, 50, 0, 49, + 0, 57, 0, 51, 52, 54, 55, 56, 59, 58, + 60, 61, 64, 63, 62, 31, 36, 0, 0, 33, + 0, 32, 0, 42, 0, 34, 35, 37, 38, 39, + 40, 41, 43, 44, 45, 46, 47, 19, 20, 21, + 50, 17, 49, 285, 57, 0, 51, 52, 54, 55, + 56, 59, 58, 60, 61, 64, 63, 62, 33, 0, + 32, 0, 42, 0, 34, 35, 37, 38, 39, 40, + 41, 43, 44, 45, 46, 47, 0, 0, 0, 0, + 0, 0, 0, 23, 26, 24, 25, 27, 14, 0, + 15, 19, 20, 21, 0, 17, 0, 9, 0, 19, + 20, 21, 0, 17, 0, 160, 19, 20, 21, 0, + 0, 0, 215, 0, 0, 0, 0, 0, 0, 0, + 68, 11, 22, 0, 0, 65, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 23, 26, 24, 25, 27, 14, 0, 15, 23, 26, 24, 25, 27, - 14, 0, 15, 19, 20, 21, 0, 17, 0, 9, - 0, 19, 20, 21, 0, 17, 0, 159, 22, 19, - 20, 21, 0, 0, 0, 214, 22, 0, 0, 33, - 0, 32, 0, 42, 22, 34, 35, 37, 38, 39, - 40, 41, 43, 44, 45, 46, 47, 0, 23, 26, - 24, 25, 27, 14, 0, 15, 23, 26, 24, 25, - 27, 0, 0, 0, 23, 26, 24, 25, 27, 257, - 0, 258, 260, 261, 0, 259, 0, 0, 0, 0, - 0, 0, 0, 262, 0, 0, 131, 22, 0, 0, - 0, 0, 0, 0, 0, 22, 65, 3, 0, 0, - 0, 0, 0, 22, 118, 119, 120, 121, 122, 124, - 123, 125, 126, 0, 127, 128, 129, 130, 0, 0, - 0, 134, 132, 133, 135, 136, 137, 138, 161, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 102, 103, 104, 108, 0, - 0, 0, 206, 0, 0, 107, 105, 106, 110, 109, - 111, 112, 113, 114, 115, 116, 117, 102, 103, 104, - 108, 0, 0, 0, 0, 0, 0, 107, 105, 106, - 110, 109, 111, 112, 113, 114, 115, 116, 117, + 0, 0, 23, 26, 24, 25, 27, 162, 164, 165, + 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 0, 0, 22, 0, 0, 0, + 0, 131, 0, 0, 22, 0, 0, 0, 0, 0, + 0, 22, 205, 208, 209, 210, 211, 212, 213, 118, + 119, 120, 121, 122, 124, 123, 125, 126, 0, 127, + 128, 129, 130, 0, 0, 0, 134, 132, 133, 136, + 137, 138, 135, 139, 102, 103, 104, 108, 0, 0, + 0, 207, 0, 0, 107, 105, 106, 110, 109, 111, + 112, 113, 114, 115, 116, 117, 102, 103, 104, 108, + 0, 0, 0, 0, 0, 0, 107, 105, 106, 110, + 109, 111, 112, 113, 114, 115, 116, 117, } var yyPact = [...]int{ - 757, -28, -31, 605, -1000, 583, -1000, -1000, -1000, 757, - -1000, 530, -1000, 523, 274, 271, -1000, 362, -1000, -1000, - -1000, -1000, 318, 264, 259, 255, 254, 253, -1000, 252, - 178, 233, 233, 233, 233, 233, 233, 233, 233, 233, - 233, 233, 233, 233, 233, 233, 233, 233, 177, 177, - 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, - 177, 177, 177, 177, 177, 561, 14, 234, 390, 170, - 516, 900, 232, 232, 232, 232, 232, 232, -1000, -1000, - -1000, -1000, -1000, -1000, 773, 773, 773, 773, 773, 773, - 773, 410, 837, -1000, 488, 410, 410, 410, -1000, -1000, + 765, -36, -39, 627, -1000, 605, -1000, -1000, -1000, 765, + -1000, 527, -1000, 520, 327, 326, -1000, 365, -1000, -1000, + -1000, -1000, 354, 324, 322, 313, 310, 299, -1000, 297, + 178, 288, 288, 288, 288, 288, 288, 288, 288, 288, + 288, 288, 288, 288, 288, 288, 288, 288, 179, 179, + 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, + 179, 179, 179, 179, 179, 583, 96, 558, 393, 196, + 233, 899, 283, 283, 283, 283, 283, 283, -1000, -1000, + -1000, -1000, -1000, -1000, 780, 780, 780, 780, 780, 780, + 780, 414, 852, -1000, 493, 414, 414, 414, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 421, 420, 397, 147, 371, 176, 244, 85, 110, + -1000, -1000, -1000, 194, 414, 414, 414, 414, 360, -1000, + 605, -1000, -1000, -1000, -1000, 281, 278, 276, 274, 266, + 773, 264, 666, 711, -1000, -1000, -1000, -1000, 666, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 648, 179, -1000, -1000, -1000, -1000, 648, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 343, 334, 329, 106, 257, 802, 78, 63, -1000, - -1000, -1000, 149, 410, 410, 410, 410, 302, -1000, 583, - -1000, -1000, -1000, -1000, 231, 225, 215, 214, 208, 765, - 194, 718, 704, -1000, -1000, -1000, -1000, 718, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 642, - 177, -1000, -1000, -1000, -1000, 642, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 688, - -1000, -1000, -1000, -1000, -21, -1000, 696, -6, -6, -75, - -75, -75, -75, -50, 773, -10, -10, -78, -78, -78, - -78, 478, 211, -1000, -1000, -1000, -1000, -1000, 410, 410, - 410, 410, 410, 410, 410, 410, 410, 410, 410, 410, - 410, 410, 410, 410, 448, -46, -46, 31, 20, 19, - 17, 327, 306, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 438, 400, 64, - 54, 209, -1000, -48, 147, 142, 837, 837, 109, 234, - 180, 137, 9, 704, -1000, 696, -33, -1000, -1000, 837, - -46, -46, -79, -79, -79, -64, -64, -64, -64, -64, - -64, -64, -64, -79, 105, 105, -1000, -1000, -1000, -1000, - -1000, 11, -18, -1000, -1000, -1000, -1000, -1000, 302, 922, - 40, 38, 104, 132, 197, -1000, 688, -1000, -1000, -1000, - -1000, -1000, 192, 190, 330, 36, -1000, 282, 837, 837, - 195, -1000, -1000, 184, 158, 156, 154, 297, 35, 837, - -1000, 240, -1000, -1000, -1000, -1000, 179, 99, 100, 837, - -1000, 186, 95, 107, -1000, -1000, + 260, -1000, -1000, -1000, -1000, -4, -1000, 19, 25, 25, + -76, -76, -76, -76, -11, 780, 12, 12, -79, -79, + -79, -79, 483, 307, -1000, -1000, -1000, -1000, -1000, 414, + 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, + 414, 414, 414, 414, 414, 453, -47, -47, 10, 9, + 8, -19, 364, 362, -23, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 442, + 404, 64, 54, 234, -1000, -49, 192, 184, 852, 852, + 331, 558, 130, 181, 75, 711, -1000, 19, -45, -1000, + -1000, 852, -47, -47, -80, -80, -80, -51, -51, -51, + -51, -51, -51, -51, -51, -80, 105, 105, -1000, -1000, + -1000, -1000, -1000, -25, -27, -1000, -1000, -1000, -1000, -1000, + -1000, 360, 921, 56, 55, 142, 174, 231, -1000, 260, + -1000, -1000, -1000, -1000, -1000, 253, 226, 401, 39, -1000, + 350, 852, 852, 214, -1000, -1000, 204, 205, 201, 159, + 372, 37, 852, -1000, 348, -1000, -1000, -1000, -1000, 199, + 157, 132, 852, -1000, 344, 155, 148, -1000, -1000, } var yyPgo = [...]int{ - 0, 363, 7, 361, 5, 6, 1, 856, 359, 14, - 10, 3, 323, 358, 357, 141, 13, 355, 353, 12, - 19, 9, 4, 2, 0, 18, 351, 8, 349, 348, + 0, 471, 7, 470, 5, 6, 1, 805, 469, 14, + 10, 3, 340, 468, 467, 800, 13, 450, 428, 12, + 19, 9, 4, 2, 0, 18, 427, 8, 418, 358, } var yyR1 = [...]int{ @@ -430,7 +432,7 @@ var yyR1 = [...]int{ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 23, 23, 23, - 23, 23, + 23, 23, 23, } var yyR2 = [...]int{ @@ -453,47 +455,47 @@ var yyR2 = [...]int{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, - 4, 4, + 4, 4, 3, } var yyChk = [...]int{ -1000, -1, -9, -7, -14, -6, -11, -2, -4, 12, - -8, -15, -10, -16, 56, 58, -17, 10, -19, 6, - 7, 8, 90, 51, 53, 54, 52, 55, -29, 65, - 66, 67, 73, 71, 77, 78, 68, 79, 80, 81, - 82, 83, 75, 84, 85, 86, 87, 88, 67, 73, - 71, 77, 78, 68, 79, 80, 81, 75, 83, 82, - 84, 85, 88, 87, 86, -7, -9, -6, -15, -18, - -16, -12, 89, 90, 92, 93, 94, 95, 69, 70, - 71, 72, 73, 74, -12, 89, 90, 92, 93, 94, - 95, 12, 12, 11, -20, 12, 90, 91, -21, -22, + -8, -15, -10, -16, 57, 59, -17, 10, -19, 6, + 7, 8, 91, 52, 54, 55, 53, 56, -29, 66, + 67, 68, 74, 72, 78, 79, 69, 80, 81, 82, + 83, 84, 76, 85, 86, 87, 88, 89, 68, 74, + 72, 78, 79, 69, 80, 81, 82, 76, 84, 83, + 85, 86, 89, 88, 87, -7, -9, -6, -15, -18, + -16, -12, 90, 91, 93, 94, 95, 96, 70, 71, + 72, 73, 74, 75, -12, 90, 91, 93, 94, 95, + 96, 12, 12, 11, -20, 12, 91, 92, -21, -22, -23, -24, 5, 6, 7, 16, 17, 15, 8, 19, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 32, 34, 35, 37, 38, 39, - 40, 9, 45, 46, 44, 47, 48, 49, 50, 6, - 7, 8, 12, 12, 12, 12, 12, 12, -13, -6, - -11, -2, -3, -4, 60, 61, 62, 63, 64, 12, - 57, -7, 12, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -6, - 12, -6, -6, -6, -6, -6, -6, -6, -6, -6, - -6, -6, -6, -6, -6, -6, -6, 13, 13, 66, - 13, 13, 13, 13, -15, -21, 12, -15, -15, -15, - -15, -15, -15, -16, 12, -16, -16, -16, -16, -16, - -16, -20, -5, -25, -22, -23, -24, 11, 89, 90, - 92, 93, 94, 69, 70, 71, 72, 73, 74, 76, - 75, 95, 67, 68, -20, -20, -20, 4, 4, 4, - 4, 45, 46, 27, 34, 36, 41, 27, 29, 33, - 30, 31, 41, 29, 42, 43, 13, -20, -20, -20, - -20, -28, -27, 4, 12, 12, 12, 12, 12, -6, - -16, 12, -9, 12, -19, 12, -9, 13, 13, 14, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, 13, 59, 59, 59, - 59, 4, 4, 13, 13, 13, 13, 13, 14, 69, - 13, 13, -25, -25, -10, 13, 66, -25, 59, 59, - -27, -21, 56, 56, 14, 13, 13, 14, 12, 12, - -26, 7, 6, 56, 6, -5, -5, 14, 13, 12, - 13, 14, 13, 13, 7, 6, 56, -5, 6, 12, - 13, 14, -5, 6, 13, 13, + 40, 9, 45, 46, 44, 50, 47, 48, 49, 51, + 6, 7, 8, 12, 12, 12, 12, 12, 12, -13, + -6, -11, -2, -3, -4, 61, 62, 63, 64, 65, + 12, 58, -7, 12, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -6, 12, -6, -6, -6, -6, -6, -6, -6, -6, + -6, -6, -6, -6, -6, -6, -6, -6, 13, 13, + 67, 13, 13, 13, 13, -15, -21, 12, -15, -15, + -15, -15, -15, -15, -16, 12, -16, -16, -16, -16, + -16, -16, -20, -5, -25, -22, -23, -24, 11, 90, + 91, 93, 94, 95, 70, 71, 72, 73, 74, 75, + 77, 76, 96, 68, 69, -20, -20, -20, 4, 4, + 4, 4, 45, 46, 4, 27, 34, 36, 41, 27, + 29, 33, 30, 31, 41, 29, 42, 43, 13, -20, + -20, -20, -20, -28, -27, 4, 12, 12, 12, 12, + 12, -6, -16, 12, -9, 12, -19, 12, -9, 13, + 13, 14, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, 13, 60, + 60, 60, 60, 4, 4, 60, 13, 13, 13, 13, + 13, 14, 70, 13, 13, -25, -25, -10, 13, 67, + -25, 60, 60, -27, -21, 57, 57, 14, 13, 13, + 14, 12, 12, -26, 7, 6, 57, 6, -5, -5, + 14, 13, 12, 13, 14, 13, 13, 7, 6, 57, + -5, 6, 12, 13, 14, -5, 6, 13, 13, } var yyDef = [...]int{ @@ -510,30 +512,30 @@ var yyDef = [...]int{ 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 0, 0, 0, 0, 0, 0, 0, 0, 98, - 99, 100, 0, 0, 0, 0, 0, 0, 4, 30, - 31, 32, 33, 34, 0, 0, 0, 0, 0, 0, - 0, 7, 0, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 48, - 0, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 6, 25, 0, - 47, 77, 85, 87, 75, 76, 0, 78, 79, 80, - 81, 82, 83, 68, 0, 88, 89, 90, 91, 92, - 93, 0, 0, 41, 38, 39, 40, 67, 0, 0, + 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 99, 100, 0, 0, 0, 0, 0, 0, 4, + 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, + 0, 0, 7, 0, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 48, 0, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 6, 25, + 0, 47, 77, 85, 87, 75, 76, 0, 78, 79, + 80, 81, 82, 83, 68, 0, 88, 89, 90, 91, + 92, 93, 0, 0, 41, 38, 39, 40, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 138, 139, 0, 0, 0, - 0, 0, 0, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 101, 0, 0, 0, - 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, -2, 0, 0, 35, 37, 0, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 121, 186, 187, 188, - 189, 0, 0, 102, 103, 104, 105, 118, 0, 0, - 106, 108, 0, 0, 0, 36, 0, 42, 190, 191, - 120, 117, 0, 0, 0, 112, 114, 0, 0, 0, - 0, 43, 44, 0, 0, 0, 0, 0, 110, 0, - 115, 0, 107, 109, 45, 46, 0, 0, 0, 0, - 113, 0, 0, 0, 111, 116, + 0, 0, 0, 0, 0, 0, 138, 139, 0, 0, + 0, 0, 0, 0, 0, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 101, 0, + 0, 0, 0, 0, 119, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -2, 0, 0, 35, + 37, 0, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 121, 186, + 187, 188, 189, 0, 0, 192, 102, 103, 104, 105, + 118, 0, 0, 106, 108, 0, 0, 0, 36, 0, + 42, 190, 191, 120, 117, 0, 0, 0, 112, 114, + 0, 0, 0, 0, 43, 44, 0, 0, 0, 0, + 0, 110, 0, 115, 0, 107, 109, 45, 46, 0, + 0, 0, 0, 113, 0, 0, 0, 111, 116, } var yyTok1 = [...]int{ @@ -550,7 +552,7 @@ var yyTok2 = [...]int{ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, + 92, 93, 94, 95, 96, } var yyTok3 = [...]int{ 0, @@ -2039,6 +2041,12 @@ yydefault: { yyVAL.attributeField = NewScopedAttribute(AttributeScopeSpan, true, yyDollar[3].staticStr) } + case 192: + yyDollar = yyS[yypt-3 : yypt+1] +//line pkg/traceql/expr.y:421 + { + yyVAL.attributeField = NewScopedAttribute(AttributeScopeEvent, false, yyDollar[2].staticStr) + } } goto yystack /* stack new state and value */ } diff --git a/pkg/traceql/lexer.go b/pkg/traceql/lexer.go index ff818b0f7cd..afc07981fdb 100644 --- a/pkg/traceql/lexer.go +++ b/pkg/traceql/lexer.go @@ -86,6 +86,7 @@ var tokens = map[string]int{ "span:": SPAN_COLON, "event:": EVENT_COLON, "link:": LINK_COLON, + "event.": EVENT_DOT, "count": COUNT, "avg": AVG, "max": MAX, @@ -213,7 +214,8 @@ func (l *lexer) Lex(lval *yySymType) int { multiTok == SPAN_COLON || multiTok == TRACE_COLON || multiTok == EVENT_COLON || - multiTok == LINK_COLON { + multiTok == LINK_COLON || + multiTok == EVENT_DOT { l.currentScope = multiTok } @@ -403,5 +405,6 @@ func startsAttribute(tok int) bool { return tok == DOT || tok == RESOURCE_DOT || tok == SPAN_DOT || - tok == PARENT_DOT + tok == PARENT_DOT || + tok == EVENT_DOT } diff --git a/pkg/traceql/lexer_test.go b/pkg/traceql/lexer_test.go index caf7ccdcafb..3767d343f66 100644 --- a/pkg/traceql/lexer_test.go +++ b/pkg/traceql/lexer_test.go @@ -44,6 +44,13 @@ func TestLexerAttributes(t *testing.T) { {`resource.foo3`, []int{RESOURCE_DOT, IDENTIFIER, END_ATTRIBUTE}}, {`resource.foo+bar`, []int{RESOURCE_DOT, IDENTIFIER, END_ATTRIBUTE}}, {`resource.foo-bar`, []int{RESOURCE_DOT, IDENTIFIER, END_ATTRIBUTE}}, + // event attributes + {`event.foo`, []int{EVENT_DOT, IDENTIFIER, END_ATTRIBUTE}}, + {`event.count`, []int{EVENT_DOT, IDENTIFIER, END_ATTRIBUTE}}, + {`event.count`, []int{EVENT_DOT, IDENTIFIER, END_ATTRIBUTE}}, + {`event.foo3`, []int{EVENT_DOT, IDENTIFIER, END_ATTRIBUTE}}, + {`event.foo+bar`, []int{EVENT_DOT, IDENTIFIER, END_ATTRIBUTE}}, + {`event.foo-bar`, []int{EVENT_DOT, IDENTIFIER, END_ATTRIBUTE}}, // parent span attributes {`parent.span.foo`, []int{PARENT_DOT, SPAN_DOT, IDENTIFIER, END_ATTRIBUTE}}, {`parent.span.count`, []int{PARENT_DOT, SPAN_DOT, IDENTIFIER, END_ATTRIBUTE}}, diff --git a/pkg/traceql/parse_test.go b/pkg/traceql/parse_test.go index 74ebf99ce44..e9d1ac8ed70 100644 --- a/pkg/traceql/parse_test.go +++ b/pkg/traceql/parse_test.go @@ -1020,6 +1020,7 @@ func TestAttributes(t *testing.T) { {in: "parent.foo.bar.baz", expected: NewScopedAttribute(AttributeScopeNone, true, "foo.bar.baz")}, {in: "resource.foo.bar.baz", expected: NewScopedAttribute(AttributeScopeResource, false, "foo.bar.baz")}, {in: "span.foo.bar", expected: NewScopedAttribute(AttributeScopeSpan, false, "foo.bar")}, + {in: "event.foo.bar", expected: NewScopedAttribute(AttributeScopeEvent, false, "foo.bar")}, {in: "parent.resource.foo", expected: NewScopedAttribute(AttributeScopeResource, true, "foo")}, {in: "parent.span.foo", expected: NewScopedAttribute(AttributeScopeSpan, true, "foo")}, {in: "parent.resource.foo.bar.baz", expected: NewScopedAttribute(AttributeScopeResource, true, "foo.bar.baz")}, diff --git a/pkg/traceql/test_examples.yaml b/pkg/traceql/test_examples.yaml index 75c8636a6f1..6b0a1531d05 100644 --- a/pkg/traceql/test_examples.yaml +++ b/pkg/traceql/test_examples.yaml @@ -51,6 +51,7 @@ valid: - '{ duration > 1s }' - '{ 1 < 1h }' - '{ 1 <= 1.1 }' + - '{ event.foo = "bar" }' # scoped intrinsics - '{ trace:duration > 2s }' - '{ trace:rootName = "a" }' @@ -318,4 +319,3 @@ unsupported: # parsed and the ast is dumped to stdout. this is a debugging tool dump: -- '{ trace:id = "3485734785643"}' \ No newline at end of file diff --git a/tempodb/encoding/vparquet4/block_traceql.go b/tempodb/encoding/vparquet4/block_traceql.go index 83c2f90446e..cfe03895a90 100644 --- a/tempodb/encoding/vparquet4/block_traceql.go +++ b/tempodb/encoding/vparquet4/block_traceql.go @@ -882,6 +882,12 @@ const ( columnPathEventName = "rs.list.element.ss.list.element.Spans.list.element.Events.list.element.Name" columnPathLinkTraceID = "rs.list.element.ss.list.element.Spans.list.element.Links.list.element.TraceID" columnPathLinkSpanID = "rs.list.element.ss.list.element.Spans.list.element.Links.list.element.SpanID" + columnPathEventAttrKey = "rs.list.element.ss.list.element.Spans.list.element.Events.list.element.Attrs.list.element.Key" + columnPathEventAttrString = "rs.list.element.ss.list.element.Spans.list.element.Events.list.element.Attrs.list.element.Value.list.element" + columnPathEventAttrInt = "rs.list.element.ss.list.element.Spans.list.element.Events.list.element.Attrs.list.element.ValueInt.list.element" + columnPathEventAttrDouble = "rs.list.element.ss.list.element.Spans.list.element.Events.list.element.Attrs.list.element.ValueDouble.list.element" + columnPathEventAttrBool = "rs.list.element.ss.list.element.Spans.list.element.Events.list.element.Attrs.list.element.ValueBool.list.element" + otherEntrySpansetKey = "spanset" otherEntrySpanKey = "span" @@ -1573,6 +1579,7 @@ func createEventIterator(makeIter makeIterFn, conditions []traceql.Condition) (p return nil, err } eventIters = append(eventIters, makeIter(columnPathEventName, pred, columnPathEventName)) + continue } } From 5eabea82c51d684b715c8453511f3fa21bbc1185 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Tue, 4 Jun 2024 14:07:40 -0500 Subject: [PATCH 02/22] block stuff --- tempodb/encoding/vparquet4/block_traceql.go | 106 ++++++++++++++++++-- tempodb/encoding/vparquet4/schema.go | 1 + 2 files changed, 98 insertions(+), 9 deletions(-) diff --git a/tempodb/encoding/vparquet4/block_traceql.go b/tempodb/encoding/vparquet4/block_traceql.go index cfe03895a90..c266d48feeb 100644 --- a/tempodb/encoding/vparquet4/block_traceql.go +++ b/tempodb/encoding/vparquet4/block_traceql.go @@ -5,6 +5,8 @@ import ( "context" "errors" "fmt" + "github.com/opentracing/opentracing-go" + "github.com/parquet-go/parquet-go" "io" "math" "reflect" @@ -13,9 +15,6 @@ import ( "time" "unsafe" - "github.com/opentracing/opentracing-go" - "github.com/parquet-go/parquet-go" - "github.com/grafana/tempo/pkg/cache" "github.com/grafana/tempo/pkg/parquetquery" v1 "github.com/grafana/tempo/pkg/tempopb/trace/v1" @@ -888,7 +887,6 @@ const ( columnPathEventAttrDouble = "rs.list.element.ss.list.element.Spans.list.element.Events.list.element.Attrs.list.element.ValueDouble.list.element" columnPathEventAttrBool = "rs.list.element.ss.list.element.Spans.list.element.Events.list.element.Attrs.list.element.ValueBool.list.element" - otherEntrySpansetKey = "spanset" otherEntrySpanKey = "span" otherEntryEventKey = "event" @@ -1535,7 +1533,7 @@ func createAllIterator(ctx context.Context, primaryIter parquetquery.Iterator, c innerIterators = append(innerIterators, primaryIter) } - eventIter, err := createEventIterator(makeIter, catConditions.event) + eventIter, err := createEventIterator(makeIter, primaryIter, catConditions.event, allConditions) if err != nil { return nil, fmt.Errorf("creating event iterator: %w", err) } @@ -1564,12 +1562,13 @@ func createAllIterator(ctx context.Context, primaryIter parquetquery.Iterator, c return createTraceIterator(makeIter, resourceIter, catConditions.trace, start, end, shardID, shardCount, allConditions, selectAll) } -func createEventIterator(makeIter makeIterFn, conditions []traceql.Condition) (parquetquery.Iterator, error) { +func createEventIterator(makeIter makeIterFn, primaryIter parquetquery.Iterator, conditions []traceql.Condition, allConditions bool) (parquetquery.Iterator, error) { if len(conditions) == 0 { return nil, nil } eventIters := make([]parquetquery.Iterator, 0, len(conditions)) + var genericConditions []traceql.Condition for _, cond := range conditions { switch cond.Attribute.Intrinsic { @@ -1581,13 +1580,69 @@ func createEventIterator(makeIter makeIterFn, conditions []traceql.Condition) (p eventIters = append(eventIters, makeIter(columnPathEventName, pred, columnPathEventName)) continue } + genericConditions = append(genericConditions, cond) } if len(eventIters) == 0 { return nil, nil } - return parquetquery.NewJoinIterator(DefinitionLevelResourceSpansILSSpanEvent, eventIters, &eventCollector{}, parquetquery.WithPool(pqEventPool)), nil + attrIter, err := createAttributeIterator(makeIter, genericConditions, DefinitionLevelResourceSpansILSSpanEventAttrs, + columnPathEventAttrKey, columnPathEventAttrString, columnPathEventAttrInt, columnPathEventAttrDouble, columnPathEventAttrBool, allConditions) + if err != nil { + return nil, fmt.Errorf("creating span attribute iterator: %w", err) + } + + if attrIter != nil { + eventIters = append(eventIters, attrIter) + } + + var required []parquetquery.Iterator + if primaryIter != nil { + required = []parquetquery.Iterator{primaryIter} + } + + minCount := 0 + + if allConditions { + // The final number of expected attributes. + distinct := map[string]struct{}{} + for _, cond := range conditions { + distinct[cond.Attribute.Name] = struct{}{} + } + minCount = len(distinct) + } + + eventCol := &eventCollector{ + minAttributes: minCount, + } + + // This is an optimization for when all of the span conditions must be met. + // We simply move all iterators into the required list. + if allConditions { + required = append(required, eventIters...) + eventIters = nil + } + + // This is an optimization for cases when allConditions is false, and + // only span conditions are present, and we require at least one of them to match. + // Wrap up the individual conditions with a union and move it into the required list. + // This skips over static columns like ID that are omnipresent. This is also only + // possible when there isn't a duration filter because it's computed from start/end. + + // if there are no direct conditions imposed on the span/span attributes level we are purposefully going to request the "Kind" column + // b/c it is extremely cheap to retrieve. retrieving matching spans in this case will allow aggregates such as "count" to be computed + // how do we know to pull duration for things like | avg(duration) > 1s? look at avg(span.http.status_code) it pushes a column request down here + // the entire engine is built around spans. we have to return at least one entry for every span to the layers above for things to work + // TODO: note that if the query is { kind = client } the fetch layer will actually create two iterators over the kind column. this is evidence + // this spaniterator code could be tightened up + // Also note that this breaks optimizations related to requireAtLeastOneMatch and requireAtLeastOneMatchOverall b/c it will add a kind attribute + // to the span attributes map in spanCollector + if len(required) == 0 { + required = []parquetquery.Iterator{makeIter(columnPathEventName, nil, "")} + } + + return parquetquery.NewLeftJoinIterator(DefinitionLevelResourceSpansILSSpanEvent, required, eventIters, eventCol, parquetquery.WithPool(pqEventPool)) } func createLinkIterator(makeIter makeIterFn, conditions []traceql.Condition) (parquetquery.Iterator, error) { @@ -2340,6 +2395,7 @@ func createAttributeIterator(makeIter makeIterFn, conditions []traceql.Condition for _, cond := range conditions { attrKeys = append(attrKeys, cond.Attribute.Name) + fmt.Printf("createAttributeIterator: condition name: %s\n", cond.Attribute.Name) if cond.Op == traceql.OpNone { // This means we have to scan all values, we don't know what type @@ -2354,6 +2410,7 @@ func createAttributeIterator(makeIter makeIterFn, conditions []traceql.Condition switch cond.Operands[0].Type { case traceql.TypeString: + fmt.Println("createAttributeIterator: condition type: string") pred, err := createStringPredicate(cond.Op, cond.Operands) if err != nil { return nil, fmt.Errorf("creating attribute predicate: %w", err) @@ -2404,6 +2461,7 @@ func createAttributeIterator(makeIter makeIterFn, conditions []traceql.Condition // if all conditions must be true we can use a simple join iterator to test the values one column at a time. // len(valueIters) must be 1 to handle queries like `{ span.foo = "x" && span.bar > 1}` if allConditions && len(valueIters) == 1 { + fmt.Println("createAttributeIterator: all conditions true") iters := append([]parquetquery.Iterator{makeIter(keyPath, parquetquery.NewStringInPredicate(attrKeys), "key")}, valueIters...) return parquetquery.NewJoinIterator(definitionLevel, iters, @@ -2437,6 +2495,7 @@ func (c *spanCollector) String() string { } func (c *spanCollector) KeepGroup(res *parquetquery.IteratorResult) bool { + fmt.Println("spanCollector: KeepGroup") var sp *span // look for existing span first. this occurs on the second pass for _, e := range res.OtherEntries { @@ -2558,6 +2617,7 @@ func (c *batchCollector) String() string { // the span-level iterators. It updates the spans in-place in the OtherEntries slice. // Creation of the spanset is delayed until the traceCollector. func (c *batchCollector) KeepGroup(res *parquetquery.IteratorResult) bool { + fmt.Println("batch collector keep group") // First pass over spans and attributes from the AttributeCollector spans := res.OtherEntries[:0] c.resAttrs = c.resAttrs[:0] @@ -2756,6 +2816,7 @@ func (c *attributeCollector) String() string { func (c *attributeCollector) KeepGroup(res *parquetquery.IteratorResult) bool { var key string var val traceql.Static + fmt.Println("attributeCollector: KeepGroup") for _, e := range res.Entries { // Ignore nulls, this leaves val as the remaining found value, @@ -2806,7 +2867,9 @@ func getEvent() *event { // eventCollector receives rows from the event columns and joins them together into // map[key]value entries with the right type. -type eventCollector struct{} +type eventCollector struct{ + minAttributes int +} var _ parquetquery.GroupPredicate = (*eventCollector)(nil) @@ -2815,6 +2878,7 @@ func (c *eventCollector) String() string { } func (c *eventCollector) KeepGroup(res *parquetquery.IteratorResult) bool { + fmt.Println("eventCollector: KeepGroup") var ev *event // look for existing event first @@ -2830,6 +2894,16 @@ func (c *eventCollector) KeepGroup(res *parquetquery.IteratorResult) bool { ev = getEvent() } + // extract from attribute collector + for _, e := range res.OtherEntries { + if v, ok := e.Value.(traceql.Static); ok { + ev.attrs = append(ev.attrs, attrVal{ + a: newEventAttr(e.Key), + s: v, + }) + } + } + for _, e := range res.Entries { switch e.Key { case columnPathEventName: @@ -2840,7 +2914,17 @@ func (c *eventCollector) KeepGroup(res *parquetquery.IteratorResult) bool { } } - res.Reset() + if c.minAttributes > 0 { + fmt.Println("min attributes", c.minAttributes) + fmt.Println("len(ev.attrs)", len(ev.attrs)) + if len(ev.attrs) < c.minAttributes { + putEvent(ev) + return false + } + } + + res.Entries = res.Entries[:0] + res.OtherEntries = res.OtherEntries[:0] res.AppendOtherValue(otherEntryEventKey, ev) return true @@ -2920,6 +3004,10 @@ func newResAttr(name string) traceql.Attribute { return traceql.NewScopedAttribute(traceql.AttributeScopeResource, false, name) } +func newEventAttr(name string) traceql.Attribute { + return traceql.NewScopedAttribute(traceql.AttributeScopeEvent, false, name) +} + func unionIfNeeded(definitionLevel int, iters []parquetquery.Iterator, pred parquetquery.GroupPredicate) parquetquery.Iterator { switch len(iters) { case 0: diff --git a/tempodb/encoding/vparquet4/schema.go b/tempodb/encoding/vparquet4/schema.go index 8b41f292fd1..06408987048 100644 --- a/tempodb/encoding/vparquet4/schema.go +++ b/tempodb/encoding/vparquet4/schema.go @@ -54,6 +54,7 @@ const ( DefinitionLevelResourceSpansILSSpanAttrs = 4 DefinitionLevelResourceSpansILSSpanEvent = 4 DefinitionLevelResourceSpansILSSpanLink = 4 + DefinitionLevelResourceSpansILSSpanEventAttrs = 5 FieldResourceAttrKey = "rs.list.element.Resource.Attrs.list.element.Key" FieldResourceAttrVal = "rs.list.element.Resource.Attrs.list.element.Value.list.element" From 93ce3f62de90f71260fd07dfa7a3f872dc78e0e9 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Thu, 13 Jun 2024 09:43:31 -0500 Subject: [PATCH 03/22] adding one more definition level --- pkg/parquetquery/iters.go | 75 ++- tempodb/encoding/vparquet4/block_traceql.go | 17 +- .../vparquet4/block_traceql_meta_test.go | 33 + .../encoding/vparquet4/block_traceql_test.go | 572 +++++++++--------- 4 files changed, 394 insertions(+), 303 deletions(-) diff --git a/pkg/parquetquery/iters.go b/pkg/parquetquery/iters.go index ebf44fc43fb..953f80b8394 100644 --- a/pkg/parquetquery/iters.go +++ b/pkg/parquetquery/iters.go @@ -30,14 +30,14 @@ import ( // D 0, 1, 0 // E 0, 2, -1 // -// Currently supports 6 levels of nesting which should be enough for anybody. :) -type RowNumber [6]int32 +// Currently supports 7 levels of nesting which should be enough for anybody. :) +type RowNumber [7]int32 -const MaxDefinitionLevel = 5 +const MaxDefinitionLevel = 6 // EmptyRowNumber creates an empty invalid row number. func EmptyRowNumber() RowNumber { - return RowNumber{-1, -1, -1, -1, -1, -1} + return RowNumber{-1, -1, -1, -1, -1, -1, -1} } // MaxRowNumber is a helper that represents the maximum(-ish) representable value. @@ -80,7 +80,8 @@ func EqualRowNumber(upToDefinitionLevel int, a, b RowNumber) bool { (a[2] == b[2] || upToDefinitionLevel < 2) && (a[3] == b[3] || upToDefinitionLevel < 3) && (a[4] == b[4] || upToDefinitionLevel < 4) && - (a[5] == b[5] || upToDefinitionLevel < 5) + (a[5] == b[5] || upToDefinitionLevel < 5) && + (a[6] == b[6] || upToDefinitionLevel < 6) } func TruncateRowNumber(definitionLevelToKeep int, t RowNumber) RowNumber { @@ -123,36 +124,49 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[1] = 0 t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[1] = 0 t[2] = 0 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[1] = 0 t[2] = 0 t[3] = 0 t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[1] = 0 t[2] = 0 t[3] = 0 t[4] = 0 t[5] = -1 + t[6] = -1 case 5: t[1] = 0 t[2] = 0 t[3] = 0 t[4] = 0 t[5] = 0 + t[6] = -1 + case 6: + t[1] = 0 + t[2] = 0 + t[3] = 0 + t[4] = 0 + t[5] = 0 + t[6] = 0 } case 1: switch definitionLevel { @@ -162,31 +176,43 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[2] = 0 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[2] = 0 t[3] = 0 t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[2] = 0 t[3] = 0 t[4] = 0 t[5] = -1 + t[6] = -1 case 5: t[2] = 0 t[3] = 0 t[4] = 0 t[5] = 0 + t[6] = -1 + case 6: + t[2] = 0 + t[3] = 0 + t[4] = 0 + t[5] = 0 + t[6] = 0 } case 2: switch definitionLevel { @@ -196,27 +222,38 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[3] = 0 t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[3] = 0 t[4] = 0 t[5] = -1 + t[6] = -1 case 5: t[3] = 0 t[4] = 0 t[5] = 0 + t[6] = -1 + case 6: + t[3] = 0 + t[4] = 0 + t[5] = 0 + t[6] = 0 } case 3: switch definitionLevel { @@ -226,24 +263,34 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[4] = 0 t[5] = -1 + t[6] = -1 case 5: t[4] = 0 t[5] = 0 + t[6] = -1 + case 6: + t[4] = 0 + t[5] = 0 + t[6] = 0 } case 4: switch definitionLevel { @@ -253,22 +300,31 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[5] = -1 + t[6] = -1 case 5: t[5] = 0 + t[6] = -1 + case 6: + t[5] = 0 + t[6] = 0 } case 5: switch definitionLevel { @@ -278,20 +334,29 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[5] = -1 + t[6] = -1 + case 5: + t[6] = -1 + case 6: + t[6] = 0 } } } diff --git a/tempodb/encoding/vparquet4/block_traceql.go b/tempodb/encoding/vparquet4/block_traceql.go index c266d48feeb..ca9a2c3a6a6 100644 --- a/tempodb/encoding/vparquet4/block_traceql.go +++ b/tempodb/encoding/vparquet4/block_traceql.go @@ -1583,10 +1583,6 @@ func createEventIterator(makeIter makeIterFn, primaryIter parquetquery.Iterator, genericConditions = append(genericConditions, cond) } - if len(eventIters) == 0 { - return nil, nil - } - attrIter, err := createAttributeIterator(makeIter, genericConditions, DefinitionLevelResourceSpansILSSpanEventAttrs, columnPathEventAttrKey, columnPathEventAttrString, columnPathEventAttrInt, columnPathEventAttrDouble, columnPathEventAttrBool, allConditions) if err != nil { @@ -1642,6 +1638,10 @@ func createEventIterator(makeIter makeIterFn, primaryIter parquetquery.Iterator, required = []parquetquery.Iterator{makeIter(columnPathEventName, nil, "")} } + if len(eventIters) == 0 && len(required) == 0 { + return nil, nil + } + return parquetquery.NewLeftJoinIterator(DefinitionLevelResourceSpansILSSpanEvent, required, eventIters, eventCol, parquetquery.WithPool(pqEventPool)) } @@ -2395,7 +2395,6 @@ func createAttributeIterator(makeIter makeIterFn, conditions []traceql.Condition for _, cond := range conditions { attrKeys = append(attrKeys, cond.Attribute.Name) - fmt.Printf("createAttributeIterator: condition name: %s\n", cond.Attribute.Name) if cond.Op == traceql.OpNone { // This means we have to scan all values, we don't know what type @@ -2410,7 +2409,6 @@ func createAttributeIterator(makeIter makeIterFn, conditions []traceql.Condition switch cond.Operands[0].Type { case traceql.TypeString: - fmt.Println("createAttributeIterator: condition type: string") pred, err := createStringPredicate(cond.Op, cond.Operands) if err != nil { return nil, fmt.Errorf("creating attribute predicate: %w", err) @@ -2461,7 +2459,6 @@ func createAttributeIterator(makeIter makeIterFn, conditions []traceql.Condition // if all conditions must be true we can use a simple join iterator to test the values one column at a time. // len(valueIters) must be 1 to handle queries like `{ span.foo = "x" && span.bar > 1}` if allConditions && len(valueIters) == 1 { - fmt.Println("createAttributeIterator: all conditions true") iters := append([]parquetquery.Iterator{makeIter(keyPath, parquetquery.NewStringInPredicate(attrKeys), "key")}, valueIters...) return parquetquery.NewJoinIterator(definitionLevel, iters, @@ -2495,7 +2492,6 @@ func (c *spanCollector) String() string { } func (c *spanCollector) KeepGroup(res *parquetquery.IteratorResult) bool { - fmt.Println("spanCollector: KeepGroup") var sp *span // look for existing span first. this occurs on the second pass for _, e := range res.OtherEntries { @@ -2617,7 +2613,6 @@ func (c *batchCollector) String() string { // the span-level iterators. It updates the spans in-place in the OtherEntries slice. // Creation of the spanset is delayed until the traceCollector. func (c *batchCollector) KeepGroup(res *parquetquery.IteratorResult) bool { - fmt.Println("batch collector keep group") // First pass over spans and attributes from the AttributeCollector spans := res.OtherEntries[:0] c.resAttrs = c.resAttrs[:0] @@ -2816,7 +2811,6 @@ func (c *attributeCollector) String() string { func (c *attributeCollector) KeepGroup(res *parquetquery.IteratorResult) bool { var key string var val traceql.Static - fmt.Println("attributeCollector: KeepGroup") for _, e := range res.Entries { // Ignore nulls, this leaves val as the remaining found value, @@ -2878,7 +2872,6 @@ func (c *eventCollector) String() string { } func (c *eventCollector) KeepGroup(res *parquetquery.IteratorResult) bool { - fmt.Println("eventCollector: KeepGroup") var ev *event // look for existing event first @@ -2915,8 +2908,6 @@ func (c *eventCollector) KeepGroup(res *parquetquery.IteratorResult) bool { } if c.minAttributes > 0 { - fmt.Println("min attributes", c.minAttributes) - fmt.Println("len(ev.attrs)", len(ev.attrs)) if len(ev.attrs) < c.minAttributes { putEvent(ev) return false diff --git a/tempodb/encoding/vparquet4/block_traceql_meta_test.go b/tempodb/encoding/vparquet4/block_traceql_meta_test.go index 0d3d5a8051c..e0f748b8de4 100644 --- a/tempodb/encoding/vparquet4/block_traceql_meta_test.go +++ b/tempodb/encoding/vparquet4/block_traceql_meta_test.go @@ -541,6 +541,39 @@ func TestBackendBlockSearchFetchMetaData(t *testing.T) { ), ), }, + { + "Event attribute lookup", + makeReq( + parse(t, `{event.message =~ "excepti"}`), // + ), + makeSpansets( + makeSpanset( + wantTr.TraceID, + wantTr.RootSpanName, + wantTr.RootServiceName, + wantTr.StartTimeUnixNano, + wantTr.DurationNano, + &span{ + id: wantTr.ResourceSpans[0].ScopeSpans[0].Spans[0].SpanID, + startTimeUnixNanos: wantTr.ResourceSpans[0].ScopeSpans[0].Spans[0].StartTimeUnixNano, + durationNanos: wantTr.ResourceSpans[0].ScopeSpans[0].Spans[0].DurationNano, + spanAttrs: []attrVal{ + {traceql.NewIntrinsic(traceql.IntrinsicDuration), traceql.NewStaticDuration(100 * time.Second)}, + {traceql.NewIntrinsic(traceql.IntrinsicSpanID), traceql.NewStaticString(util.SpanIDToHexString(wantTr.ResourceSpans[0].ScopeSpans[0].Spans[0].SpanID))}, + }, + traceAttrs: []attrVal{ + {traceql.NewIntrinsic(traceql.IntrinsicTraceRootService), traceql.NewStaticString("RootService")}, + {traceql.NewIntrinsic(traceql.IntrinsicTraceRootSpan), traceql.NewStaticString("RootSpan")}, + {traceql.NewIntrinsic(traceql.IntrinsicTraceDuration), traceql.NewStaticDuration(100 * time.Millisecond)}, + {traceql.NewIntrinsic(traceql.IntrinsicTraceID), traceql.NewStaticString(util.TraceIDToHexString(wantTr.TraceID))}, + }, + eventAttrs: []attrVal{ + {traceql.NewScopedAttribute(traceql.AttributeScopeEvent, false, "message"), traceql.NewStaticString("exception")}, + }, + }, + ), + ), + }, { "Intrinsic link trace ID lookup", makeReq( diff --git a/tempodb/encoding/vparquet4/block_traceql_test.go b/tempodb/encoding/vparquet4/block_traceql_test.go index 0c1cb4bdf27..d896ba549e1 100644 --- a/tempodb/encoding/vparquet4/block_traceql_test.go +++ b/tempodb/encoding/vparquet4/block_traceql_test.go @@ -54,7 +54,7 @@ func TestOne(t *testing.T) { } func TestBackendBlockSearchTraceQL(t *testing.T) { - numTraces := 250 + numTraces := 2 traces := make([]*Trace, 0, numTraces) wantTraceIdx := rand.Intn(numTraces) wantTraceID := test.ValidTraceID(nil) @@ -72,169 +72,170 @@ func TestBackendBlockSearchTraceQL(t *testing.T) { b := makeBackendBlockWithTraces(t, traces) ctx := context.Background() - traceIDText := util.TraceIDToHexString(wantTraceID) + //traceIDText := util.TraceIDToHexString(wantTraceID) searchesThatMatch := []struct { name string req traceql.FetchSpansRequest }{ - {"empty request", traceql.FetchSpansRequest{}}, - { - "Time range inside trace", - traceql.FetchSpansRequest{ - StartTimeUnixNanos: uint64(1100 * time.Second), - EndTimeUnixNanos: uint64(1200 * time.Second), - }, - }, - { - "Time range overlap start", - traceql.FetchSpansRequest{ - StartTimeUnixNanos: uint64(900 * time.Second), - EndTimeUnixNanos: uint64(1100 * time.Second), - }, - }, - { - "Time range overlap end", - traceql.FetchSpansRequest{ - StartTimeUnixNanos: uint64(1900 * time.Second), - EndTimeUnixNanos: uint64(2100 * time.Second), - }, - }, - // Intrinsics - {"Intrinsic: name", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelName + ` = "hello"}`)}, - {"Intrinsic: duration = 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` = 100s}`)}, - {"Intrinsic: duration > 99s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` > 99s}`)}, - {"Intrinsic: duration >= 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` >= 100s}`)}, - {"Intrinsic: duration < 101s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` < 101s}`)}, - {"Intrinsic: duration <= 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` <= 100s}`)}, - {"Intrinsic: status = error", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = error}`)}, - {"Intrinsic: status = 2", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = 2}`)}, - {"Intrinsic: statusMessage = STATUS_CODE_ERROR", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + "statusMessage" + ` = "STATUS_CODE_ERROR"}`)}, - {"Intrinsic: kind = client", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelKind + ` = client }`)}, - {"Intrinsic: trace:id", traceql.MustExtractFetchSpansRequestWithMetadata(`{ trace:id = "` + traceIDText + `" }`)}, - // Resource well-known attributes - {".service.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "spanservicename"}`)}, // Overridden at span}, - {".cluster", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelCluster + ` = "cluster"}`)}, - {".namespace", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelNamespace + ` = "namespace"}`)}, - {".pod", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelPod + ` = "pod"}`)}, - {".container", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelContainer + ` = "container"}`)}, - {".k8s.namespace.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sNamespaceName + ` = "k8snamespace"}`)}, - {".k8s.cluster.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sClusterName + ` = "k8scluster"}`)}, - {".k8s.pod.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sPodName + ` = "k8spod"}`)}, - {".k8s.container.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sContainerName + ` = "k8scontainer"}`)}, - {"resource.service.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` = "myservice"}`)}, - {"resource.cluster", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelCluster + ` = "cluster"}`)}, - {"resource.namespace", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelNamespace + ` = "namespace"}`)}, - {"resource.pod", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelPod + ` = "pod"}`)}, - {"resource.container", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelContainer + ` = "container"}`)}, - {"resource.k8s.namespace.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sNamespaceName + ` = "k8snamespace"}`)}, - {"resource.k8s.cluster.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sClusterName + ` = "k8scluster"}`)}, - {"resource.k8s.pod.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sPodName + ` = "k8spod"}`)}, - {"resource.k8s.container.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sContainerName + ` = "k8scontainer"}`)}, - // Resource dedicated attributes - {"resource.dedicated.resource.3", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.3 = "dedicated-resource-attr-value-3"}`)}, - {"resource.dedicated.resource.5", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.5 = "dedicated-resource-attr-value-5"}`)}, - // Comparing strings - {"resource.service.name > myservice", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` > "myservic"}`)}, - {"resource.service.name >= myservice", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` >= "myservic"}`)}, - {"resource.service.name < myservice1", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` < "myservice1"}`)}, - {"resource.service.name <= myservice1", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` <= "myservice1"}`)}, - // Span well-known attributes - {".http.status_code", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = 500}`)}, - {".http.method", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPMethod + ` = "get"}`)}, - {".http.url", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPUrl + ` = "url/hello/world"}`)}, - {"span.http.status_code", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPStatusCode + ` = 500}`)}, - {"span.http.method", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPMethod + ` = "get"}`)}, - {"span.http.url", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPUrl + ` = "url/hello/world"}`)}, - // Span dedicated attributes - {"span.dedicated.span.2", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.2 = "dedicated-span-attr-value-2"}`)}, - {"span.dedicated.span.4", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.4 = "dedicated-span-attr-value-4"}`)}, - // Events - {"event:name", traceql.MustExtractFetchSpansRequestWithMetadata(`{event:name = "e1"}`)}, - // Links - {"link:spanID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:spanID = "1234567890abcdef"}`)}, - {"link:traceID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:traceID = "1234567890abcdef1234567890abcdef"}`)}, - // Basic data types and operations - {".float = 456.78", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float = 456.78}`)}, // Float == - {".float != 456.79", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float != 456.79}`)}, // Float != - {".float > 456.7", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float > 456.7}`)}, // Float > - {".float >= 456.78", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float >= 456.78}`)}, // Float >= - {".float < 456.781", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float < 456.781}`)}, // Float < - {".bool = false", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bool = false}`)}, // Bool == - {".bool != true", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bool != true}`)}, // Bool != - {".bar = 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar = 123}`)}, // Int == - {".bar != 124", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar != 124}`)}, // Int != - {".bar > 122", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar > 122}`)}, // Int > - {".bar >= 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar >= 123}`)}, // Int >= - {".bar < 124", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar < 124}`)}, // Int < - {".bar <= 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar <= 123}`)}, // Int <= - {".foo = \"def\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "def"}`)}, // String == - {".foo != \"deg\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo != "deg"}`)}, // String != - {".foo =~ \"d.*\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo =~ "d.*"}`)}, // String Regex - {".foo !~ \"x.*\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo !~ "x.*"}`)}, // String Not Regex - {"resource.foo = \"abc\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.foo = "abc"}`)}, // Resource-level only - {"span.foo = \"def\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.foo = "def"}`)}, // Span-level only - {".foo", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo}`)}, // Projection only - {"Matches either condition", makeReq( - parse(t, `{.foo = "baz"}`), - parse(t, `{.`+LabelHTTPStatusCode+` > 100}`), - )}, - {"Same as above but reversed order", makeReq( - parse(t, `{.`+LabelHTTPStatusCode+` > 100}`), - parse(t, `{.foo = "baz"}`), - )}, - {"Same attribute with mixed types", makeReq( - parse(t, `{.foo > 100}`), - parse(t, `{.foo = "def"}`), - )}, - {"Multiple conditions on same well-known attribute, matches either", makeReq( - // - parse(t, `{.`+LabelHTTPStatusCode+` = 500}`), - parse(t, `{.`+LabelHTTPStatusCode+` > 500}`), - )}, - { - "Mix of duration with other conditions", makeReq( - // - parse(t, `{`+LabelName+` = "hello"}`), // Match - parse(t, `{`+LabelDuration+` < 100s }`), // No match - ), - }, - // Edge cases - {"Almost conflicts with intrinsic but still works", traceql.MustExtractFetchSpansRequestWithMetadata(`{.name = "Bob"}`)}, - {"service.name doesn't match type of dedicated column", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` = 123}`)}, - {"service.name present on span", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "spanservicename"}`)}, - {"http.status_code doesn't match type of dedicated column", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = "500ouch"}`)}, - {`.foo = "def"`, traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "def"}`)}, - { - name: "Range at unscoped", - req: traceql.FetchSpansRequest{ - AllConditions: true, - Conditions: []traceql.Condition{ - parse(t, `{.`+LabelHTTPStatusCode+` >= 500}`), - parse(t, `{.`+LabelHTTPStatusCode+` <= 600}`), - }, - }, - }, - { - name: "Range at span scope", - req: traceql.FetchSpansRequest{ - AllConditions: true, - Conditions: []traceql.Condition{ - parse(t, `{span.`+LabelHTTPStatusCode+` >= 500}`), - parse(t, `{span.`+LabelHTTPStatusCode+` <= 600}`), - }, - }, - }, - { - name: "Range at resource scope", - req: traceql.FetchSpansRequest{ - AllConditions: true, - Conditions: []traceql.Condition{ - parse(t, `{resource.`+LabelServiceName+` >= 122}`), - parse(t, `{resource.`+LabelServiceName+` <= 124}`), - }, - }, - }, + // {"empty request", traceql.FetchSpansRequest{}}, + // { + // "Time range inside trace", + // traceql.FetchSpansRequest{ + // StartTimeUnixNanos: uint64(1100 * time.Second), + // EndTimeUnixNanos: uint64(1200 * time.Second), + // }, + // }, + // { + // "Time range overlap start", + // traceql.FetchSpansRequest{ + // StartTimeUnixNanos: uint64(900 * time.Second), + // EndTimeUnixNanos: uint64(1100 * time.Second), + // }, + // }, + // { + // "Time range overlap end", + // traceql.FetchSpansRequest{ + // StartTimeUnixNanos: uint64(1900 * time.Second), + // EndTimeUnixNanos: uint64(2100 * time.Second), + // }, + // }, + // // Intrinsics + // {"Intrinsic: name", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelName + ` = "hello"}`)}, + // {"Intrinsic: duration = 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` = 100s}`)}, + // {"Intrinsic: duration > 99s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` > 99s}`)}, + // {"Intrinsic: duration >= 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` >= 100s}`)}, + // {"Intrinsic: duration < 101s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` < 101s}`)}, + // {"Intrinsic: duration <= 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` <= 100s}`)}, + // {"Intrinsic: status = error", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = error}`)}, + // {"Intrinsic: status = 2", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = 2}`)}, + // {"Intrinsic: statusMessage = STATUS_CODE_ERROR", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + "statusMessage" + ` = "STATUS_CODE_ERROR"}`)}, + // {"Intrinsic: kind = client", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelKind + ` = client }`)}, + // {"Intrinsic: trace:id", traceql.MustExtractFetchSpansRequestWithMetadata(`{ trace:id = "` + traceIDText + `" }`)}, + // // Resource well-known attributes + // {".service.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "spanservicename"}`)}, // Overridden at span}, + // {".cluster", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelCluster + ` = "cluster"}`)}, + // {".namespace", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelNamespace + ` = "namespace"}`)}, + // {".pod", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelPod + ` = "pod"}`)}, + // {".container", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelContainer + ` = "container"}`)}, + // {".k8s.namespace.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sNamespaceName + ` = "k8snamespace"}`)}, + // {".k8s.cluster.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sClusterName + ` = "k8scluster"}`)}, + // {".k8s.pod.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sPodName + ` = "k8spod"}`)}, + // {".k8s.container.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sContainerName + ` = "k8scontainer"}`)}, + // {"resource.service.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` = "myservice"}`)}, + // {"resource.cluster", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelCluster + ` = "cluster"}`)}, + // {"resource.namespace", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelNamespace + ` = "namespace"}`)}, + // {"resource.pod", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelPod + ` = "pod"}`)}, + // {"resource.container", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelContainer + ` = "container"}`)}, + // {"resource.k8s.namespace.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sNamespaceName + ` = "k8snamespace"}`)}, + // {"resource.k8s.cluster.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sClusterName + ` = "k8scluster"}`)}, + // {"resource.k8s.pod.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sPodName + ` = "k8spod"}`)}, + // {"resource.k8s.container.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sContainerName + ` = "k8scontainer"}`)}, + // // Resource dedicated attributes + // {"resource.dedicated.resource.3", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.3 = "dedicated-resource-attr-value-3"}`)}, + // {"resource.dedicated.resource.5", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.5 = "dedicated-resource-attr-value-5"}`)}, + // // Comparing strings + // {"resource.service.name > myservice", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` > "myservic"}`)}, + // {"resource.service.name >= myservice", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` >= "myservic"}`)}, + // {"resource.service.name < myservice1", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` < "myservice1"}`)}, + // {"resource.service.name <= myservice1", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` <= "myservice1"}`)}, + // // Span well-known attributes + // {".http.status_code", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = 500}`)}, + // {".http.method", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPMethod + ` = "get"}`)}, + // {".http.url", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPUrl + ` = "url/hello/world"}`)}, + // {"span.http.status_code", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPStatusCode + ` = 500}`)}, + // {"span.http.method", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPMethod + ` = "get"}`)}, + // {"span.http.url", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPUrl + ` = "url/hello/world"}`)}, + // // Span dedicated attributes + // {"span.dedicated.span.2", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.2 = "dedicated-span-attr-value-2"}`)}, + // {"span.dedicated.span.4", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.4 = "dedicated-span-attr-value-4"}`)}, + // // Events + // {"event:name", traceql.MustExtractFetchSpansRequestWithMetadata(`{event:name = "e1"}`)}, + {"event.message", traceql.MustExtractFetchSpansRequestWithMetadata(`{event.message = "exception"}`)}, + // // Links + // {"link:spanID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:spanID = "1234567890abcdef"}`)}, + // {"link:traceID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:traceID = "1234567890abcdef1234567890abcdef"}`)}, + // // Basic data types and operations + // {".float = 456.78", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float = 456.78}`)}, // Float == + // {".float != 456.79", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float != 456.79}`)}, // Float != + // {".float > 456.7", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float > 456.7}`)}, // Float > + // {".float >= 456.78", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float >= 456.78}`)}, // Float >= + // {".float < 456.781", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float < 456.781}`)}, // Float < + // {".bool = false", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bool = false}`)}, // Bool == + // {".bool != true", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bool != true}`)}, // Bool != + // {".bar = 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar = 123}`)}, // Int == + // {".bar != 124", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar != 124}`)}, // Int != + // {".bar > 122", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar > 122}`)}, // Int > + // {".bar >= 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar >= 123}`)}, // Int >= + // {".bar < 124", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar < 124}`)}, // Int < + // {".bar <= 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar <= 123}`)}, // Int <= + // {".foo = \"def\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "def"}`)}, // String == + // {".foo != \"deg\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo != "deg"}`)}, // String != + // {".foo =~ \"d.*\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo =~ "d.*"}`)}, // String Regex + // {".foo !~ \"x.*\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo !~ "x.*"}`)}, // String Not Regex + // {"resource.foo = \"abc\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.foo = "abc"}`)}, // Resource-level only + // {"span.foo = \"def\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.foo = "def"}`)}, // Span-level only + // {".foo", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo}`)}, // Projection only + // {"Matches either condition", makeReq( + // parse(t, `{.foo = "baz"}`), + // parse(t, `{.`+LabelHTTPStatusCode+` > 100}`), + // )}, + // {"Same as above but reversed order", makeReq( + // parse(t, `{.`+LabelHTTPStatusCode+` > 100}`), + // parse(t, `{.foo = "baz"}`), + // )}, + // {"Same attribute with mixed types", makeReq( + // parse(t, `{.foo > 100}`), + // parse(t, `{.foo = "def"}`), + // )}, + // {"Multiple conditions on same well-known attribute, matches either", makeReq( + // // + // parse(t, `{.`+LabelHTTPStatusCode+` = 500}`), + // parse(t, `{.`+LabelHTTPStatusCode+` > 500}`), + // )}, + // { + // "Mix of duration with other conditions", makeReq( + // // + // parse(t, `{`+LabelName+` = "hello"}`), // Match + // parse(t, `{`+LabelDuration+` < 100s }`), // No match + // ), + // }, + // // Edge cases + // {"Almost conflicts with intrinsic but still works", traceql.MustExtractFetchSpansRequestWithMetadata(`{.name = "Bob"}`)}, + // {"service.name doesn't match type of dedicated column", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` = 123}`)}, + // {"service.name present on span", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "spanservicename"}`)}, + // {"http.status_code doesn't match type of dedicated column", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = "500ouch"}`)}, + // {`.foo = "def"`, traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "def"}`)}, + // { + // name: "Range at unscoped", + // req: traceql.FetchSpansRequest{ + // AllConditions: true, + // Conditions: []traceql.Condition{ + // parse(t, `{.`+LabelHTTPStatusCode+` >= 500}`), + // parse(t, `{.`+LabelHTTPStatusCode+` <= 600}`), + // }, + // }, + // }, + // { + // name: "Range at span scope", + // req: traceql.FetchSpansRequest{ + // AllConditions: true, + // Conditions: []traceql.Condition{ + // parse(t, `{span.`+LabelHTTPStatusCode+` >= 500}`), + // parse(t, `{span.`+LabelHTTPStatusCode+` <= 600}`), + // }, + // }, + // }, + // { + // name: "Range at resource scope", + // req: traceql.FetchSpansRequest{ + // AllConditions: true, + // Conditions: []traceql.Condition{ + // parse(t, `{resource.`+LabelServiceName+` >= 122}`), + // parse(t, `{resource.`+LabelServiceName+` <= 124}`), + // }, + // }, + // }, } for _, tc := range searchesThatMatch { @@ -264,129 +265,129 @@ func TestBackendBlockSearchTraceQL(t *testing.T) { }) } - searchesThatDontMatch := []struct { - name string - req traceql.FetchSpansRequest - }{ - // TODO - Should the below query return data or not? It does match the resource - // makeReq(parse(t, `{.foo = "abc"}`)), // This should not return results because the span has overridden this attribute to "def". - {"Regex IN", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo =~ "xyz.*"}`)}, - {"String Not Regex", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo !~ ".*"}`)}, - {"Bool not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.bool = true && name = "hello"}`)}, // name = "hello" only matches the first span - {"Intrinsic: duration", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` > 1000s}`)}, - {"Intrinsic: status", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = unset}`)}, - {"Intrinsic: statusMessage", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + "statusMessage" + ` = "abc"}`)}, - {"Intrinsic: name", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelName + ` = "nothello"}`)}, - {"Intrinsic: kind", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelKind + ` = producer }`)}, - {"Intrinsic: event:name", traceql.MustExtractFetchSpansRequestWithMetadata(`{event:name = "x2"}`)}, - {"Intrinsic: link:spanID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:spanID = "ffffffffffffffff"}`)}, - {"Intrinsic: link:traceID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:traceID = "ffffffffffffffffffffffffffffffff"}`)}, - {"Well-known attribute: service.name not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "notmyservice"}`)}, - {"Well-known attribute: http.status_code not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = 200}`)}, - {"Well-known attribute: http.status_code not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` > 600}`)}, - {"Matches neither condition", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "xyz" || .` + LabelHTTPStatusCode + " = 1000}")}, - {"Resource dedicated attributes does not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.3 = "dedicated-resource-attr-value-4"}`)}, - {"Resource dedicated attributes does not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.2 = "dedicated-span-attr-value-5"}`)}, - { - name: "Time range after trace", - req: traceql.FetchSpansRequest{ - StartTimeUnixNanos: uint64(20000 * time.Second), - EndTimeUnixNanos: uint64(30000 * time.Second), - }, - }, - { - name: "Time range before trace", - req: traceql.FetchSpansRequest{ - StartTimeUnixNanos: uint64(600 * time.Second), - EndTimeUnixNanos: uint64(700 * time.Second), - }, - }, - { - name: "Matches some conditions but not all. Mix of span-level columns", - req: traceql.FetchSpansRequest{ - AllConditions: true, - Conditions: []traceql.Condition{ - parse(t, `{span.foo = "baz"}`), // no match - parse(t, `{span.`+LabelHTTPStatusCode+` > 100}`), // match - parse(t, `{name = "hello"}`), // match - }, - }, - }, - { - name: "Matches some conditions but not all. Only span generic attr lookups", - req: traceql.FetchSpansRequest{ - AllConditions: true, - Conditions: []traceql.Condition{ - parse(t, `{span.foo = "baz"}`), // no match - parse(t, `{span.bar = 123}`), // match - }, - }, - }, - { - name: "Matches some conditions but not all. Mix of span and resource columns", - req: traceql.FetchSpansRequest{ - AllConditions: true, - Conditions: []traceql.Condition{ - parse(t, `{resource.cluster = "cluster"}`), // match - parse(t, `{resource.namespace = "namespace"}`), // match - parse(t, `{span.foo = "baz"}`), // no match - }, - }, - }, - { - name: "Matches some conditions but not all. Mix of resource columns", - req: traceql.FetchSpansRequest{ - AllConditions: true, - Conditions: []traceql.Condition{ - parse(t, `{resource.cluster = "notcluster"}`), // no match - parse(t, `{resource.namespace = "namespace"}`), // match - parse(t, `{resource.foo = "abc"}`), // match - }, - }, - }, - { - name: "Matches some conditions but not all. Only resource generic attr lookups", - req: traceql.FetchSpansRequest{ - AllConditions: true, - Conditions: []traceql.Condition{ - parse(t, `{resource.foo = "abc"}`), // match - parse(t, `{resource.bar = 123}`), // no match - }, - }, - }, - { - name: "Mix of duration with other conditions", - req: traceql.FetchSpansRequest{ - AllConditions: true, - Conditions: []traceql.Condition{ - parse(t, `{`+LabelName+` = "nothello"}`), // No match - parse(t, `{`+LabelDuration+` = 100s }`), // Match - }, - }, - }, - } - - for _, tc := range searchesThatDontMatch { - t.Run(tc.name, func(t *testing.T) { - req := tc.req - if req.SecondPass == nil { - req.SecondPass = func(s *traceql.Spanset) ([]*traceql.Spanset, error) { return []*traceql.Spanset{s}, nil } - req.SecondPassConditions = traceql.SearchMetaConditions() - } - - resp, err := b.Fetch(ctx, req, common.DefaultSearchOptions()) - require.NoError(t, err, "search request:", req) - - for { - spanSet, err := resp.Results.Next(ctx) - require.NoError(t, err, "search request:", req) - if spanSet == nil { - break - } - require.NotEqual(t, wantTraceID, spanSet.TraceID, "search request:", req) - } - }) - } + // searchesThatDontMatch := []struct { + // name string + // req traceql.FetchSpansRequest + // }{ + // // TODO - Should the below query return data or not? It does match the resource + // // makeReq(parse(t, `{.foo = "abc"}`)), // This should not return results because the span has overridden this attribute to "def". + // {"Regex IN", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo =~ "xyz.*"}`)}, + // {"String Not Regex", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo !~ ".*"}`)}, + // {"Bool not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.bool = true && name = "hello"}`)}, // name = "hello" only matches the first span + // {"Intrinsic: duration", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` > 1000s}`)}, + // {"Intrinsic: status", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = unset}`)}, + // {"Intrinsic: statusMessage", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + "statusMessage" + ` = "abc"}`)}, + // {"Intrinsic: name", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelName + ` = "nothello"}`)}, + // {"Intrinsic: kind", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelKind + ` = producer }`)}, + // {"Intrinsic: event:name", traceql.MustExtractFetchSpansRequestWithMetadata(`{event:name = "x2"}`)}, + // {"Intrinsic: link:spanID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:spanID = "ffffffffffffffff"}`)}, + // {"Intrinsic: link:traceID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:traceID = "ffffffffffffffffffffffffffffffff"}`)}, + // {"Well-known attribute: service.name not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "notmyservice"}`)}, + // {"Well-known attribute: http.status_code not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = 200}`)}, + // {"Well-known attribute: http.status_code not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` > 600}`)}, + // {"Matches neither condition", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "xyz" || .` + LabelHTTPStatusCode + " = 1000}")}, + // {"Resource dedicated attributes does not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.3 = "dedicated-resource-attr-value-4"}`)}, + // {"Resource dedicated attributes does not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.2 = "dedicated-span-attr-value-5"}`)}, + // { + // name: "Time range after trace", + // req: traceql.FetchSpansRequest{ + // StartTimeUnixNanos: uint64(20000 * time.Second), + // EndTimeUnixNanos: uint64(30000 * time.Second), + // }, + // }, + // { + // name: "Time range before trace", + // req: traceql.FetchSpansRequest{ + // StartTimeUnixNanos: uint64(600 * time.Second), + // EndTimeUnixNanos: uint64(700 * time.Second), + // }, + // }, + // { + // name: "Matches some conditions but not all. Mix of span-level columns", + // req: traceql.FetchSpansRequest{ + // AllConditions: true, + // Conditions: []traceql.Condition{ + // parse(t, `{span.foo = "baz"}`), // no match + // parse(t, `{span.`+LabelHTTPStatusCode+` > 100}`), // match + // parse(t, `{name = "hello"}`), // match + // }, + // }, + // }, + // { + // name: "Matches some conditions but not all. Only span generic attr lookups", + // req: traceql.FetchSpansRequest{ + // AllConditions: true, + // Conditions: []traceql.Condition{ + // parse(t, `{span.foo = "baz"}`), // no match + // parse(t, `{span.bar = 123}`), // match + // }, + // }, + // }, + // { + // name: "Matches some conditions but not all. Mix of span and resource columns", + // req: traceql.FetchSpansRequest{ + // AllConditions: true, + // Conditions: []traceql.Condition{ + // parse(t, `{resource.cluster = "cluster"}`), // match + // parse(t, `{resource.namespace = "namespace"}`), // match + // parse(t, `{span.foo = "baz"}`), // no match + // }, + // }, + // }, + // { + // name: "Matches some conditions but not all. Mix of resource columns", + // req: traceql.FetchSpansRequest{ + // AllConditions: true, + // Conditions: []traceql.Condition{ + // parse(t, `{resource.cluster = "notcluster"}`), // no match + // parse(t, `{resource.namespace = "namespace"}`), // match + // parse(t, `{resource.foo = "abc"}`), // match + // }, + // }, + // }, + // { + // name: "Matches some conditions but not all. Only resource generic attr lookups", + // req: traceql.FetchSpansRequest{ + // AllConditions: true, + // Conditions: []traceql.Condition{ + // parse(t, `{resource.foo = "abc"}`), // match + // parse(t, `{resource.bar = 123}`), // no match + // }, + // }, + // }, + // { + // name: "Mix of duration with other conditions", + // req: traceql.FetchSpansRequest{ + // AllConditions: true, + // Conditions: []traceql.Condition{ + // parse(t, `{`+LabelName+` = "nothello"}`), // No match + // parse(t, `{`+LabelDuration+` = 100s }`), // Match + // }, + // }, + // }, + // } + + // for _, tc := range searchesThatDontMatch { + // t.Run(tc.name, func(t *testing.T) { + // req := tc.req + // if req.SecondPass == nil { + // req.SecondPass = func(s *traceql.Spanset) ([]*traceql.Spanset, error) { return []*traceql.Spanset{s}, nil } + // req.SecondPassConditions = traceql.SearchMetaConditions() + // } + + // resp, err := b.Fetch(ctx, req, common.DefaultSearchOptions()) + // require.NoError(t, err, "search request:", req) + + // for { + // spanSet, err := resp.Results.Next(ctx) + // require.NoError(t, err, "search request:", req) + // if spanSet == nil { + // break + // } + // require.NotEqual(t, wantTraceID, spanSet.TraceID, "search request:", req) + // } + // }) + // } } func makeReq(conditions ...traceql.Condition) traceql.FetchSpansRequest { @@ -525,6 +526,7 @@ func fullyPopulatedTestTrace(id common.ID) *Trace { Attrs: []Attribute{ attr("event-attr-key-1", "event-value-1"), attr("event-attr-key-2", "event-value-2"), + attr("message", "exception"), }, }, {TimeSinceStartNano: 2, Name: "e2", Attrs: []Attribute{}}, @@ -847,11 +849,11 @@ func BenchmarkBackendBlockTraceQL(b *testing.B) { ctx := context.TODO() tenantID := "1" // blockID := uuid.MustParse("06ebd383-8d4e-4289-b0e9-cf2197d611d5") - blockID := uuid.MustParse("0008e57d-069d-4510-a001-b9433b2da08c") + blockID := uuid.MustParse("000090cb-6dce-4cf2-863f-1930a86439fa") r, _, _, err := local.New(&local.Config{ // Path: path.Join("/Users/marty/src/tmp"), - Path: path.Join("/Users/mapno/workspace/testblock"), + Path: path.Join("/Users/jenniepham/grafana/data/"), }) require.NoError(b, err) @@ -860,7 +862,7 @@ func BenchmarkBackendBlockTraceQL(b *testing.B) { require.NoError(b, err) opts := common.DefaultSearchOptions() - opts.StartPage = 3 + opts.StartPage = 0 opts.TotalPages = 2 block := newBackendBlock(meta, rr) From e7587d6a5f0347473c39aa7fdc40ab8ec0ec68d3 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Thu, 13 Jun 2024 10:07:43 -0500 Subject: [PATCH 04/22] added tests back --- .../encoding/vparquet4/block_traceql_test.go | 572 +++++++++--------- 1 file changed, 286 insertions(+), 286 deletions(-) diff --git a/tempodb/encoding/vparquet4/block_traceql_test.go b/tempodb/encoding/vparquet4/block_traceql_test.go index d896ba549e1..8502b412a71 100644 --- a/tempodb/encoding/vparquet4/block_traceql_test.go +++ b/tempodb/encoding/vparquet4/block_traceql_test.go @@ -54,7 +54,7 @@ func TestOne(t *testing.T) { } func TestBackendBlockSearchTraceQL(t *testing.T) { - numTraces := 2 + numTraces := 250 traces := make([]*Trace, 0, numTraces) wantTraceIdx := rand.Intn(numTraces) wantTraceID := test.ValidTraceID(nil) @@ -72,170 +72,170 @@ func TestBackendBlockSearchTraceQL(t *testing.T) { b := makeBackendBlockWithTraces(t, traces) ctx := context.Background() - //traceIDText := util.TraceIDToHexString(wantTraceID) + traceIDText := util.TraceIDToHexString(wantTraceID) searchesThatMatch := []struct { name string req traceql.FetchSpansRequest }{ - // {"empty request", traceql.FetchSpansRequest{}}, - // { - // "Time range inside trace", - // traceql.FetchSpansRequest{ - // StartTimeUnixNanos: uint64(1100 * time.Second), - // EndTimeUnixNanos: uint64(1200 * time.Second), - // }, - // }, - // { - // "Time range overlap start", - // traceql.FetchSpansRequest{ - // StartTimeUnixNanos: uint64(900 * time.Second), - // EndTimeUnixNanos: uint64(1100 * time.Second), - // }, - // }, - // { - // "Time range overlap end", - // traceql.FetchSpansRequest{ - // StartTimeUnixNanos: uint64(1900 * time.Second), - // EndTimeUnixNanos: uint64(2100 * time.Second), - // }, - // }, - // // Intrinsics - // {"Intrinsic: name", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelName + ` = "hello"}`)}, - // {"Intrinsic: duration = 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` = 100s}`)}, - // {"Intrinsic: duration > 99s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` > 99s}`)}, - // {"Intrinsic: duration >= 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` >= 100s}`)}, - // {"Intrinsic: duration < 101s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` < 101s}`)}, - // {"Intrinsic: duration <= 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` <= 100s}`)}, - // {"Intrinsic: status = error", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = error}`)}, - // {"Intrinsic: status = 2", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = 2}`)}, - // {"Intrinsic: statusMessage = STATUS_CODE_ERROR", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + "statusMessage" + ` = "STATUS_CODE_ERROR"}`)}, - // {"Intrinsic: kind = client", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelKind + ` = client }`)}, - // {"Intrinsic: trace:id", traceql.MustExtractFetchSpansRequestWithMetadata(`{ trace:id = "` + traceIDText + `" }`)}, - // // Resource well-known attributes - // {".service.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "spanservicename"}`)}, // Overridden at span}, - // {".cluster", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelCluster + ` = "cluster"}`)}, - // {".namespace", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelNamespace + ` = "namespace"}`)}, - // {".pod", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelPod + ` = "pod"}`)}, - // {".container", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelContainer + ` = "container"}`)}, - // {".k8s.namespace.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sNamespaceName + ` = "k8snamespace"}`)}, - // {".k8s.cluster.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sClusterName + ` = "k8scluster"}`)}, - // {".k8s.pod.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sPodName + ` = "k8spod"}`)}, - // {".k8s.container.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sContainerName + ` = "k8scontainer"}`)}, - // {"resource.service.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` = "myservice"}`)}, - // {"resource.cluster", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelCluster + ` = "cluster"}`)}, - // {"resource.namespace", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelNamespace + ` = "namespace"}`)}, - // {"resource.pod", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelPod + ` = "pod"}`)}, - // {"resource.container", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelContainer + ` = "container"}`)}, - // {"resource.k8s.namespace.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sNamespaceName + ` = "k8snamespace"}`)}, - // {"resource.k8s.cluster.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sClusterName + ` = "k8scluster"}`)}, - // {"resource.k8s.pod.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sPodName + ` = "k8spod"}`)}, - // {"resource.k8s.container.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sContainerName + ` = "k8scontainer"}`)}, - // // Resource dedicated attributes - // {"resource.dedicated.resource.3", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.3 = "dedicated-resource-attr-value-3"}`)}, - // {"resource.dedicated.resource.5", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.5 = "dedicated-resource-attr-value-5"}`)}, - // // Comparing strings - // {"resource.service.name > myservice", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` > "myservic"}`)}, - // {"resource.service.name >= myservice", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` >= "myservic"}`)}, - // {"resource.service.name < myservice1", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` < "myservice1"}`)}, - // {"resource.service.name <= myservice1", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` <= "myservice1"}`)}, - // // Span well-known attributes - // {".http.status_code", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = 500}`)}, - // {".http.method", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPMethod + ` = "get"}`)}, - // {".http.url", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPUrl + ` = "url/hello/world"}`)}, - // {"span.http.status_code", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPStatusCode + ` = 500}`)}, - // {"span.http.method", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPMethod + ` = "get"}`)}, - // {"span.http.url", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPUrl + ` = "url/hello/world"}`)}, - // // Span dedicated attributes - // {"span.dedicated.span.2", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.2 = "dedicated-span-attr-value-2"}`)}, - // {"span.dedicated.span.4", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.4 = "dedicated-span-attr-value-4"}`)}, - // // Events - // {"event:name", traceql.MustExtractFetchSpansRequestWithMetadata(`{event:name = "e1"}`)}, - {"event.message", traceql.MustExtractFetchSpansRequestWithMetadata(`{event.message = "exception"}`)}, - // // Links - // {"link:spanID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:spanID = "1234567890abcdef"}`)}, - // {"link:traceID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:traceID = "1234567890abcdef1234567890abcdef"}`)}, - // // Basic data types and operations - // {".float = 456.78", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float = 456.78}`)}, // Float == - // {".float != 456.79", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float != 456.79}`)}, // Float != - // {".float > 456.7", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float > 456.7}`)}, // Float > - // {".float >= 456.78", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float >= 456.78}`)}, // Float >= - // {".float < 456.781", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float < 456.781}`)}, // Float < - // {".bool = false", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bool = false}`)}, // Bool == - // {".bool != true", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bool != true}`)}, // Bool != - // {".bar = 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar = 123}`)}, // Int == - // {".bar != 124", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar != 124}`)}, // Int != - // {".bar > 122", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar > 122}`)}, // Int > - // {".bar >= 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar >= 123}`)}, // Int >= - // {".bar < 124", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar < 124}`)}, // Int < - // {".bar <= 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar <= 123}`)}, // Int <= - // {".foo = \"def\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "def"}`)}, // String == - // {".foo != \"deg\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo != "deg"}`)}, // String != - // {".foo =~ \"d.*\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo =~ "d.*"}`)}, // String Regex - // {".foo !~ \"x.*\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo !~ "x.*"}`)}, // String Not Regex - // {"resource.foo = \"abc\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.foo = "abc"}`)}, // Resource-level only - // {"span.foo = \"def\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.foo = "def"}`)}, // Span-level only - // {".foo", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo}`)}, // Projection only - // {"Matches either condition", makeReq( - // parse(t, `{.foo = "baz"}`), - // parse(t, `{.`+LabelHTTPStatusCode+` > 100}`), - // )}, - // {"Same as above but reversed order", makeReq( - // parse(t, `{.`+LabelHTTPStatusCode+` > 100}`), - // parse(t, `{.foo = "baz"}`), - // )}, - // {"Same attribute with mixed types", makeReq( - // parse(t, `{.foo > 100}`), - // parse(t, `{.foo = "def"}`), - // )}, - // {"Multiple conditions on same well-known attribute, matches either", makeReq( - // // - // parse(t, `{.`+LabelHTTPStatusCode+` = 500}`), - // parse(t, `{.`+LabelHTTPStatusCode+` > 500}`), - // )}, - // { - // "Mix of duration with other conditions", makeReq( - // // - // parse(t, `{`+LabelName+` = "hello"}`), // Match - // parse(t, `{`+LabelDuration+` < 100s }`), // No match - // ), - // }, - // // Edge cases - // {"Almost conflicts with intrinsic but still works", traceql.MustExtractFetchSpansRequestWithMetadata(`{.name = "Bob"}`)}, - // {"service.name doesn't match type of dedicated column", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` = 123}`)}, - // {"service.name present on span", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "spanservicename"}`)}, - // {"http.status_code doesn't match type of dedicated column", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = "500ouch"}`)}, - // {`.foo = "def"`, traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "def"}`)}, - // { - // name: "Range at unscoped", - // req: traceql.FetchSpansRequest{ - // AllConditions: true, - // Conditions: []traceql.Condition{ - // parse(t, `{.`+LabelHTTPStatusCode+` >= 500}`), - // parse(t, `{.`+LabelHTTPStatusCode+` <= 600}`), - // }, - // }, - // }, - // { - // name: "Range at span scope", - // req: traceql.FetchSpansRequest{ - // AllConditions: true, - // Conditions: []traceql.Condition{ - // parse(t, `{span.`+LabelHTTPStatusCode+` >= 500}`), - // parse(t, `{span.`+LabelHTTPStatusCode+` <= 600}`), - // }, - // }, - // }, - // { - // name: "Range at resource scope", - // req: traceql.FetchSpansRequest{ - // AllConditions: true, - // Conditions: []traceql.Condition{ - // parse(t, `{resource.`+LabelServiceName+` >= 122}`), - // parse(t, `{resource.`+LabelServiceName+` <= 124}`), - // }, - // }, - // }, + {"empty request", traceql.FetchSpansRequest{}}, + { + "Time range inside trace", + traceql.FetchSpansRequest{ + StartTimeUnixNanos: uint64(1100 * time.Second), + EndTimeUnixNanos: uint64(1200 * time.Second), + }, + }, + { + "Time range overlap start", + traceql.FetchSpansRequest{ + StartTimeUnixNanos: uint64(900 * time.Second), + EndTimeUnixNanos: uint64(1100 * time.Second), + }, + }, + { + "Time range overlap end", + traceql.FetchSpansRequest{ + StartTimeUnixNanos: uint64(1900 * time.Second), + EndTimeUnixNanos: uint64(2100 * time.Second), + }, + }, + // Intrinsics + {"Intrinsic: name", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelName + ` = "hello"}`)}, + {"Intrinsic: duration = 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` = 100s}`)}, + {"Intrinsic: duration > 99s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` > 99s}`)}, + {"Intrinsic: duration >= 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` >= 100s}`)}, + {"Intrinsic: duration < 101s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` < 101s}`)}, + {"Intrinsic: duration <= 100s", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` <= 100s}`)}, + {"Intrinsic: status = error", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = error}`)}, + {"Intrinsic: status = 2", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = 2}`)}, + {"Intrinsic: statusMessage = STATUS_CODE_ERROR", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + "statusMessage" + ` = "STATUS_CODE_ERROR"}`)}, + {"Intrinsic: kind = client", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelKind + ` = client }`)}, + {"Intrinsic: trace:id", traceql.MustExtractFetchSpansRequestWithMetadata(`{ trace:id = "` + traceIDText + `" }`)}, + // Resource well-known attributes + {".service.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "spanservicename"}`)}, // Overridden at span}, + {".cluster", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelCluster + ` = "cluster"}`)}, + {".namespace", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelNamespace + ` = "namespace"}`)}, + {".pod", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelPod + ` = "pod"}`)}, + {".container", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelContainer + ` = "container"}`)}, + {".k8s.namespace.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sNamespaceName + ` = "k8snamespace"}`)}, + {".k8s.cluster.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sClusterName + ` = "k8scluster"}`)}, + {".k8s.pod.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sPodName + ` = "k8spod"}`)}, + {".k8s.container.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelK8sContainerName + ` = "k8scontainer"}`)}, + {"resource.service.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` = "myservice"}`)}, + {"resource.cluster", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelCluster + ` = "cluster"}`)}, + {"resource.namespace", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelNamespace + ` = "namespace"}`)}, + {"resource.pod", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelPod + ` = "pod"}`)}, + {"resource.container", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelContainer + ` = "container"}`)}, + {"resource.k8s.namespace.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sNamespaceName + ` = "k8snamespace"}`)}, + {"resource.k8s.cluster.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sClusterName + ` = "k8scluster"}`)}, + {"resource.k8s.pod.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sPodName + ` = "k8spod"}`)}, + {"resource.k8s.container.name", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelK8sContainerName + ` = "k8scontainer"}`)}, + // Resource dedicated attributes + {"resource.dedicated.resource.3", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.3 = "dedicated-resource-attr-value-3"}`)}, + {"resource.dedicated.resource.5", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.5 = "dedicated-resource-attr-value-5"}`)}, + // Comparing strings + {"resource.service.name > myservice", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` > "myservic"}`)}, + {"resource.service.name >= myservice", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` >= "myservic"}`)}, + {"resource.service.name < myservice1", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` < "myservice1"}`)}, + {"resource.service.name <= myservice1", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` <= "myservice1"}`)}, + // Span well-known attributes + {".http.status_code", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = 500}`)}, + {".http.method", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPMethod + ` = "get"}`)}, + {".http.url", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPUrl + ` = "url/hello/world"}`)}, + {"span.http.status_code", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPStatusCode + ` = 500}`)}, + {"span.http.method", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPMethod + ` = "get"}`)}, + {"span.http.url", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.` + LabelHTTPUrl + ` = "url/hello/world"}`)}, + // Span dedicated attributes + {"span.dedicated.span.2", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.2 = "dedicated-span-attr-value-2"}`)}, + {"span.dedicated.span.4", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.4 = "dedicated-span-attr-value-4"}`)}, + // Events + {"event:name", traceql.MustExtractFetchSpansRequestWithMetadata(`{event:name = "e1"}`)}, + {"event.message", traceql.MustExtractFetchSpansRequestWithMetadata(`{event.message =~ "exception"}`)}, + // Links + {"link:spanID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:spanID = "1234567890abcdef"}`)}, + {"link:traceID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:traceID = "1234567890abcdef1234567890abcdef"}`)}, + // Basic data types and operations + {".float = 456.78", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float = 456.78}`)}, // Float == + {".float != 456.79", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float != 456.79}`)}, // Float != + {".float > 456.7", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float > 456.7}`)}, // Float > + {".float >= 456.78", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float >= 456.78}`)}, // Float >= + {".float < 456.781", traceql.MustExtractFetchSpansRequestWithMetadata(`{.float < 456.781}`)}, // Float < + {".bool = false", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bool = false}`)}, // Bool == + {".bool != true", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bool != true}`)}, // Bool != + {".bar = 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar = 123}`)}, // Int == + {".bar != 124", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar != 124}`)}, // Int != + {".bar > 122", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar > 122}`)}, // Int > + {".bar >= 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar >= 123}`)}, // Int >= + {".bar < 124", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar < 124}`)}, // Int < + {".bar <= 123", traceql.MustExtractFetchSpansRequestWithMetadata(`{.bar <= 123}`)}, // Int <= + {".foo = \"def\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "def"}`)}, // String == + {".foo != \"deg\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo != "deg"}`)}, // String != + {".foo =~ \"d.*\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo =~ "d.*"}`)}, // String Regex + {".foo !~ \"x.*\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo !~ "x.*"}`)}, // String Not Regex + {"resource.foo = \"abc\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.foo = "abc"}`)}, // Resource-level only + {"span.foo = \"def\"", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.foo = "def"}`)}, // Span-level only + {".foo", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo}`)}, // Projection only + {"Matches either condition", makeReq( + parse(t, `{.foo = "baz"}`), + parse(t, `{.`+LabelHTTPStatusCode+` > 100}`), + )}, + {"Same as above but reversed order", makeReq( + parse(t, `{.`+LabelHTTPStatusCode+` > 100}`), + parse(t, `{.foo = "baz"}`), + )}, + {"Same attribute with mixed types", makeReq( + parse(t, `{.foo > 100}`), + parse(t, `{.foo = "def"}`), + )}, + {"Multiple conditions on same well-known attribute, matches either", makeReq( + // + parse(t, `{.`+LabelHTTPStatusCode+` = 500}`), + parse(t, `{.`+LabelHTTPStatusCode+` > 500}`), + )}, + { + "Mix of duration with other conditions", makeReq( + // + parse(t, `{`+LabelName+` = "hello"}`), // Match + parse(t, `{`+LabelDuration+` < 100s }`), // No match + ), + }, + // Edge cases + {"Almost conflicts with intrinsic but still works", traceql.MustExtractFetchSpansRequestWithMetadata(`{.name = "Bob"}`)}, + {"service.name doesn't match type of dedicated column", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.` + LabelServiceName + ` = 123}`)}, + {"service.name present on span", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "spanservicename"}`)}, + {"http.status_code doesn't match type of dedicated column", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = "500ouch"}`)}, + {`.foo = "def"`, traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "def"}`)}, + { + name: "Range at unscoped", + req: traceql.FetchSpansRequest{ + AllConditions: true, + Conditions: []traceql.Condition{ + parse(t, `{.`+LabelHTTPStatusCode+` >= 500}`), + parse(t, `{.`+LabelHTTPStatusCode+` <= 600}`), + }, + }, + }, + { + name: "Range at span scope", + req: traceql.FetchSpansRequest{ + AllConditions: true, + Conditions: []traceql.Condition{ + parse(t, `{span.`+LabelHTTPStatusCode+` >= 500}`), + parse(t, `{span.`+LabelHTTPStatusCode+` <= 600}`), + }, + }, + }, + { + name: "Range at resource scope", + req: traceql.FetchSpansRequest{ + AllConditions: true, + Conditions: []traceql.Condition{ + parse(t, `{resource.`+LabelServiceName+` >= 122}`), + parse(t, `{resource.`+LabelServiceName+` <= 124}`), + }, + }, + }, } for _, tc := range searchesThatMatch { @@ -265,129 +265,129 @@ func TestBackendBlockSearchTraceQL(t *testing.T) { }) } - // searchesThatDontMatch := []struct { - // name string - // req traceql.FetchSpansRequest - // }{ - // // TODO - Should the below query return data or not? It does match the resource - // // makeReq(parse(t, `{.foo = "abc"}`)), // This should not return results because the span has overridden this attribute to "def". - // {"Regex IN", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo =~ "xyz.*"}`)}, - // {"String Not Regex", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo !~ ".*"}`)}, - // {"Bool not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.bool = true && name = "hello"}`)}, // name = "hello" only matches the first span - // {"Intrinsic: duration", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` > 1000s}`)}, - // {"Intrinsic: status", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = unset}`)}, - // {"Intrinsic: statusMessage", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + "statusMessage" + ` = "abc"}`)}, - // {"Intrinsic: name", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelName + ` = "nothello"}`)}, - // {"Intrinsic: kind", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelKind + ` = producer }`)}, - // {"Intrinsic: event:name", traceql.MustExtractFetchSpansRequestWithMetadata(`{event:name = "x2"}`)}, - // {"Intrinsic: link:spanID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:spanID = "ffffffffffffffff"}`)}, - // {"Intrinsic: link:traceID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:traceID = "ffffffffffffffffffffffffffffffff"}`)}, - // {"Well-known attribute: service.name not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "notmyservice"}`)}, - // {"Well-known attribute: http.status_code not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = 200}`)}, - // {"Well-known attribute: http.status_code not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` > 600}`)}, - // {"Matches neither condition", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "xyz" || .` + LabelHTTPStatusCode + " = 1000}")}, - // {"Resource dedicated attributes does not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.3 = "dedicated-resource-attr-value-4"}`)}, - // {"Resource dedicated attributes does not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.2 = "dedicated-span-attr-value-5"}`)}, - // { - // name: "Time range after trace", - // req: traceql.FetchSpansRequest{ - // StartTimeUnixNanos: uint64(20000 * time.Second), - // EndTimeUnixNanos: uint64(30000 * time.Second), - // }, - // }, - // { - // name: "Time range before trace", - // req: traceql.FetchSpansRequest{ - // StartTimeUnixNanos: uint64(600 * time.Second), - // EndTimeUnixNanos: uint64(700 * time.Second), - // }, - // }, - // { - // name: "Matches some conditions but not all. Mix of span-level columns", - // req: traceql.FetchSpansRequest{ - // AllConditions: true, - // Conditions: []traceql.Condition{ - // parse(t, `{span.foo = "baz"}`), // no match - // parse(t, `{span.`+LabelHTTPStatusCode+` > 100}`), // match - // parse(t, `{name = "hello"}`), // match - // }, - // }, - // }, - // { - // name: "Matches some conditions but not all. Only span generic attr lookups", - // req: traceql.FetchSpansRequest{ - // AllConditions: true, - // Conditions: []traceql.Condition{ - // parse(t, `{span.foo = "baz"}`), // no match - // parse(t, `{span.bar = 123}`), // match - // }, - // }, - // }, - // { - // name: "Matches some conditions but not all. Mix of span and resource columns", - // req: traceql.FetchSpansRequest{ - // AllConditions: true, - // Conditions: []traceql.Condition{ - // parse(t, `{resource.cluster = "cluster"}`), // match - // parse(t, `{resource.namespace = "namespace"}`), // match - // parse(t, `{span.foo = "baz"}`), // no match - // }, - // }, - // }, - // { - // name: "Matches some conditions but not all. Mix of resource columns", - // req: traceql.FetchSpansRequest{ - // AllConditions: true, - // Conditions: []traceql.Condition{ - // parse(t, `{resource.cluster = "notcluster"}`), // no match - // parse(t, `{resource.namespace = "namespace"}`), // match - // parse(t, `{resource.foo = "abc"}`), // match - // }, - // }, - // }, - // { - // name: "Matches some conditions but not all. Only resource generic attr lookups", - // req: traceql.FetchSpansRequest{ - // AllConditions: true, - // Conditions: []traceql.Condition{ - // parse(t, `{resource.foo = "abc"}`), // match - // parse(t, `{resource.bar = 123}`), // no match - // }, - // }, - // }, - // { - // name: "Mix of duration with other conditions", - // req: traceql.FetchSpansRequest{ - // AllConditions: true, - // Conditions: []traceql.Condition{ - // parse(t, `{`+LabelName+` = "nothello"}`), // No match - // parse(t, `{`+LabelDuration+` = 100s }`), // Match - // }, - // }, - // }, - // } - - // for _, tc := range searchesThatDontMatch { - // t.Run(tc.name, func(t *testing.T) { - // req := tc.req - // if req.SecondPass == nil { - // req.SecondPass = func(s *traceql.Spanset) ([]*traceql.Spanset, error) { return []*traceql.Spanset{s}, nil } - // req.SecondPassConditions = traceql.SearchMetaConditions() - // } - - // resp, err := b.Fetch(ctx, req, common.DefaultSearchOptions()) - // require.NoError(t, err, "search request:", req) - - // for { - // spanSet, err := resp.Results.Next(ctx) - // require.NoError(t, err, "search request:", req) - // if spanSet == nil { - // break - // } - // require.NotEqual(t, wantTraceID, spanSet.TraceID, "search request:", req) - // } - // }) - // } + searchesThatDontMatch := []struct { + name string + req traceql.FetchSpansRequest + }{ + // TODO - Should the below query return data or not? It does match the resource + // makeReq(parse(t, `{.foo = "abc"}`)), // This should not return results because the span has overridden this attribute to "def". + {"Regex IN", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo =~ "xyz.*"}`)}, + {"String Not Regex", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo !~ ".*"}`)}, + {"Bool not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.bool = true && name = "hello"}`)}, // name = "hello" only matches the first span + {"Intrinsic: duration", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelDuration + ` > 1000s}`)}, + {"Intrinsic: status", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelStatus + ` = unset}`)}, + {"Intrinsic: statusMessage", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + "statusMessage" + ` = "abc"}`)}, + {"Intrinsic: name", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelName + ` = "nothello"}`)}, + {"Intrinsic: kind", traceql.MustExtractFetchSpansRequestWithMetadata(`{` + LabelKind + ` = producer }`)}, + {"Intrinsic: event:name", traceql.MustExtractFetchSpansRequestWithMetadata(`{event:name = "x2"}`)}, + {"Intrinsic: link:spanID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:spanID = "ffffffffffffffff"}`)}, + {"Intrinsic: link:traceID", traceql.MustExtractFetchSpansRequestWithMetadata(`{link:traceID = "ffffffffffffffffffffffffffffffff"}`)}, + {"Well-known attribute: service.name not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelServiceName + ` = "notmyservice"}`)}, + {"Well-known attribute: http.status_code not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` = 200}`)}, + {"Well-known attribute: http.status_code not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{.` + LabelHTTPStatusCode + ` > 600}`)}, + {"Matches neither condition", traceql.MustExtractFetchSpansRequestWithMetadata(`{.foo = "xyz" || .` + LabelHTTPStatusCode + " = 1000}")}, + {"Resource dedicated attributes does not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{resource.dedicated.resource.3 = "dedicated-resource-attr-value-4"}`)}, + {"Resource dedicated attributes does not match", traceql.MustExtractFetchSpansRequestWithMetadata(`{span.dedicated.span.2 = "dedicated-span-attr-value-5"}`)}, + { + name: "Time range after trace", + req: traceql.FetchSpansRequest{ + StartTimeUnixNanos: uint64(20000 * time.Second), + EndTimeUnixNanos: uint64(30000 * time.Second), + }, + }, + { + name: "Time range before trace", + req: traceql.FetchSpansRequest{ + StartTimeUnixNanos: uint64(600 * time.Second), + EndTimeUnixNanos: uint64(700 * time.Second), + }, + }, + { + name: "Matches some conditions but not all. Mix of span-level columns", + req: traceql.FetchSpansRequest{ + AllConditions: true, + Conditions: []traceql.Condition{ + parse(t, `{span.foo = "baz"}`), // no match + parse(t, `{span.`+LabelHTTPStatusCode+` > 100}`), // match + parse(t, `{name = "hello"}`), // match + }, + }, + }, + { + name: "Matches some conditions but not all. Only span generic attr lookups", + req: traceql.FetchSpansRequest{ + AllConditions: true, + Conditions: []traceql.Condition{ + parse(t, `{span.foo = "baz"}`), // no match + parse(t, `{span.bar = 123}`), // match + }, + }, + }, + { + name: "Matches some conditions but not all. Mix of span and resource columns", + req: traceql.FetchSpansRequest{ + AllConditions: true, + Conditions: []traceql.Condition{ + parse(t, `{resource.cluster = "cluster"}`), // match + parse(t, `{resource.namespace = "namespace"}`), // match + parse(t, `{span.foo = "baz"}`), // no match + }, + }, + }, + { + name: "Matches some conditions but not all. Mix of resource columns", + req: traceql.FetchSpansRequest{ + AllConditions: true, + Conditions: []traceql.Condition{ + parse(t, `{resource.cluster = "notcluster"}`), // no match + parse(t, `{resource.namespace = "namespace"}`), // match + parse(t, `{resource.foo = "abc"}`), // match + }, + }, + }, + { + name: "Matches some conditions but not all. Only resource generic attr lookups", + req: traceql.FetchSpansRequest{ + AllConditions: true, + Conditions: []traceql.Condition{ + parse(t, `{resource.foo = "abc"}`), // match + parse(t, `{resource.bar = 123}`), // no match + }, + }, + }, + { + name: "Mix of duration with other conditions", + req: traceql.FetchSpansRequest{ + AllConditions: true, + Conditions: []traceql.Condition{ + parse(t, `{`+LabelName+` = "nothello"}`), // No match + parse(t, `{`+LabelDuration+` = 100s }`), // Match + }, + }, + }, + } + + for _, tc := range searchesThatDontMatch { + t.Run(tc.name, func(t *testing.T) { + req := tc.req + if req.SecondPass == nil { + req.SecondPass = func(s *traceql.Spanset) ([]*traceql.Spanset, error) { return []*traceql.Spanset{s}, nil } + req.SecondPassConditions = traceql.SearchMetaConditions() + } + + resp, err := b.Fetch(ctx, req, common.DefaultSearchOptions()) + require.NoError(t, err, "search request:", req) + + for { + spanSet, err := resp.Results.Next(ctx) + require.NoError(t, err, "search request:", req) + if spanSet == nil { + break + } + require.NotEqual(t, wantTraceID, spanSet.TraceID, "search request:", req) + } + }) + } } func makeReq(conditions ...traceql.Condition) traceql.FetchSpansRequest { @@ -849,11 +849,11 @@ func BenchmarkBackendBlockTraceQL(b *testing.B) { ctx := context.TODO() tenantID := "1" // blockID := uuid.MustParse("06ebd383-8d4e-4289-b0e9-cf2197d611d5") - blockID := uuid.MustParse("000090cb-6dce-4cf2-863f-1930a86439fa") + blockID := uuid.MustParse("0008e57d-069d-4510-a001-b9433b2da08c") r, _, _, err := local.New(&local.Config{ // Path: path.Join("/Users/marty/src/tmp"), - Path: path.Join("/Users/jenniepham/grafana/data/"), + Path: path.Join("/Users/mapno/workspace/testblock"), }) require.NoError(b, err) @@ -862,7 +862,7 @@ func BenchmarkBackendBlockTraceQL(b *testing.B) { require.NoError(b, err) opts := common.DefaultSearchOptions() - opts.StartPage = 0 + opts.StartPage = 3 opts.TotalPages = 2 block := newBackendBlock(meta, rr) From f1e14b4d8828a2a6cdea679bda198fa740db718c Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Thu, 13 Jun 2024 11:01:24 -0500 Subject: [PATCH 05/22] lint --- tempodb/encoding/vparquet4/block_traceql.go | 6 +++--- tempodb/encoding/vparquet4/schema.go | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tempodb/encoding/vparquet4/block_traceql.go b/tempodb/encoding/vparquet4/block_traceql.go index ca9a2c3a6a6..9d890abc960 100644 --- a/tempodb/encoding/vparquet4/block_traceql.go +++ b/tempodb/encoding/vparquet4/block_traceql.go @@ -1641,7 +1641,7 @@ func createEventIterator(makeIter makeIterFn, primaryIter parquetquery.Iterator, if len(eventIters) == 0 && len(required) == 0 { return nil, nil } - + return parquetquery.NewLeftJoinIterator(DefinitionLevelResourceSpansILSSpanEvent, required, eventIters, eventCol, parquetquery.WithPool(pqEventPool)) } @@ -2861,8 +2861,8 @@ func getEvent() *event { // eventCollector receives rows from the event columns and joins them together into // map[key]value entries with the right type. -type eventCollector struct{ - minAttributes int +type eventCollector struct { + minAttributes int } var _ parquetquery.GroupPredicate = (*eventCollector)(nil) diff --git a/tempodb/encoding/vparquet4/schema.go b/tempodb/encoding/vparquet4/schema.go index 06408987048..448e40a3323 100644 --- a/tempodb/encoding/vparquet4/schema.go +++ b/tempodb/encoding/vparquet4/schema.go @@ -46,14 +46,14 @@ const ( // These definition levels match the schema below const ( - DefinitionLevelTrace = 0 - DefinitionLevelServiceStats = 1 - DefinitionLevelResourceSpans = 1 - DefinitionLevelResourceAttrs = 2 - DefinitionLevelResourceSpansILSSpan = 3 - DefinitionLevelResourceSpansILSSpanAttrs = 4 - DefinitionLevelResourceSpansILSSpanEvent = 4 - DefinitionLevelResourceSpansILSSpanLink = 4 + DefinitionLevelTrace = 0 + DefinitionLevelServiceStats = 1 + DefinitionLevelResourceSpans = 1 + DefinitionLevelResourceAttrs = 2 + DefinitionLevelResourceSpansILSSpan = 3 + DefinitionLevelResourceSpansILSSpanAttrs = 4 + DefinitionLevelResourceSpansILSSpanEvent = 4 + DefinitionLevelResourceSpansILSSpanLink = 4 DefinitionLevelResourceSpansILSSpanEventAttrs = 5 FieldResourceAttrKey = "rs.list.element.Resource.Attrs.list.element.Key" From b656992ce08b32a8d3ae1c6ef19726dffa163ad1 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Thu, 13 Jun 2024 11:01:58 -0500 Subject: [PATCH 06/22] lets see if the hack passes tests --- pkg/parquetquery/iters.go | 78 +++------------------ tempodb/encoding/vparquet4/block_traceql.go | 5 +- 2 files changed, 11 insertions(+), 72 deletions(-) diff --git a/pkg/parquetquery/iters.go b/pkg/parquetquery/iters.go index 953f80b8394..3c71aad49bf 100644 --- a/pkg/parquetquery/iters.go +++ b/pkg/parquetquery/iters.go @@ -30,14 +30,14 @@ import ( // D 0, 1, 0 // E 0, 2, -1 // -// Currently supports 7 levels of nesting which should be enough for anybody. :) -type RowNumber [7]int32 +// Currently supports 6 levels of nesting which should be enough for anybody. :) +type RowNumber [6]int32 -const MaxDefinitionLevel = 6 +const MaxDefinitionLevel = 5 // EmptyRowNumber creates an empty invalid row number. func EmptyRowNumber() RowNumber { - return RowNumber{-1, -1, -1, -1, -1, -1, -1} + return RowNumber{-1, -1, -1, -1, -1, -1} } // MaxRowNumber is a helper that represents the maximum(-ish) representable value. @@ -80,8 +80,7 @@ func EqualRowNumber(upToDefinitionLevel int, a, b RowNumber) bool { (a[2] == b[2] || upToDefinitionLevel < 2) && (a[3] == b[3] || upToDefinitionLevel < 3) && (a[4] == b[4] || upToDefinitionLevel < 4) && - (a[5] == b[5] || upToDefinitionLevel < 5) && - (a[6] == b[6] || upToDefinitionLevel < 6) + (a[5] == b[5] || upToDefinitionLevel < 5) } func TruncateRowNumber(definitionLevelToKeep int, t RowNumber) RowNumber { @@ -113,6 +112,9 @@ func (t *RowNumber) Valid() bool { // null | 0 | 1 | { 1, 0, -1, -1 } func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[repetitionLevel]++ + if definitionLevel == 6 { + definitionLevel = 5 + } // the following is nextSlow() unrolled switch repetitionLevel { @@ -124,49 +126,36 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 1: t[1] = 0 t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 2: t[1] = 0 t[2] = 0 t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 3: t[1] = 0 t[2] = 0 t[3] = 0 t[4] = -1 t[5] = -1 - t[6] = -1 case 4: t[1] = 0 t[2] = 0 t[3] = 0 t[4] = 0 t[5] = -1 - t[6] = -1 case 5: t[1] = 0 t[2] = 0 t[3] = 0 t[4] = 0 t[5] = 0 - t[6] = -1 - case 6: - t[1] = 0 - t[2] = 0 - t[3] = 0 - t[4] = 0 - t[5] = 0 - t[6] = 0 } case 1: switch definitionLevel { @@ -176,43 +165,31 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 2: t[2] = 0 t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 3: t[2] = 0 t[3] = 0 t[4] = -1 t[5] = -1 - t[6] = -1 case 4: t[2] = 0 t[3] = 0 t[4] = 0 t[5] = -1 - t[6] = -1 case 5: t[2] = 0 t[3] = 0 t[4] = 0 t[5] = 0 - t[6] = -1 - case 6: - t[2] = 0 - t[3] = 0 - t[4] = 0 - t[5] = 0 - t[6] = 0 } case 2: switch definitionLevel { @@ -222,38 +199,27 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 3: t[3] = 0 t[4] = -1 t[5] = -1 - t[6] = -1 case 4: t[3] = 0 t[4] = 0 t[5] = -1 - t[6] = -1 case 5: t[3] = 0 t[4] = 0 t[5] = 0 - t[6] = -1 - case 6: - t[3] = 0 - t[4] = 0 - t[5] = 0 - t[6] = 0 } case 3: switch definitionLevel { @@ -263,34 +229,24 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 3: t[4] = -1 t[5] = -1 - t[6] = -1 case 4: t[4] = 0 t[5] = -1 - t[6] = -1 case 5: t[4] = 0 t[5] = 0 - t[6] = -1 - case 6: - t[4] = 0 - t[5] = 0 - t[6] = 0 } case 4: switch definitionLevel { @@ -300,31 +256,22 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 3: t[4] = -1 t[5] = -1 - t[6] = -1 case 4: t[5] = -1 - t[6] = -1 case 5: t[5] = 0 - t[6] = -1 - case 6: - t[5] = 0 - t[6] = 0 } case 5: switch definitionLevel { @@ -334,29 +281,20 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 - t[6] = -1 case 3: t[4] = -1 t[5] = -1 - t[6] = -1 case 4: t[5] = -1 - t[6] = -1 - case 5: - t[6] = -1 - case 6: - t[6] = 0 } } } diff --git a/tempodb/encoding/vparquet4/block_traceql.go b/tempodb/encoding/vparquet4/block_traceql.go index 9d890abc960..f5ec0cda927 100644 --- a/tempodb/encoding/vparquet4/block_traceql.go +++ b/tempodb/encoding/vparquet4/block_traceql.go @@ -5,8 +5,6 @@ import ( "context" "errors" "fmt" - "github.com/opentracing/opentracing-go" - "github.com/parquet-go/parquet-go" "io" "math" "reflect" @@ -15,6 +13,9 @@ import ( "time" "unsafe" + "github.com/opentracing/opentracing-go" + "github.com/parquet-go/parquet-go" + "github.com/grafana/tempo/pkg/cache" "github.com/grafana/tempo/pkg/parquetquery" v1 "github.com/grafana/tempo/pkg/tempopb/trace/v1" From 484b57195c539e4f06de054b615c1a5a74e7482e Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Thu, 13 Jun 2024 13:07:40 -0500 Subject: [PATCH 07/22] the real change --- pkg/parquetquery/iters.go | 78 ++++++++++++++++++++++++++++++---- pkg/parquetquery/iters_test.go | 26 ++++++------ 2 files changed, 83 insertions(+), 21 deletions(-) diff --git a/pkg/parquetquery/iters.go b/pkg/parquetquery/iters.go index 3c71aad49bf..953f80b8394 100644 --- a/pkg/parquetquery/iters.go +++ b/pkg/parquetquery/iters.go @@ -30,14 +30,14 @@ import ( // D 0, 1, 0 // E 0, 2, -1 // -// Currently supports 6 levels of nesting which should be enough for anybody. :) -type RowNumber [6]int32 +// Currently supports 7 levels of nesting which should be enough for anybody. :) +type RowNumber [7]int32 -const MaxDefinitionLevel = 5 +const MaxDefinitionLevel = 6 // EmptyRowNumber creates an empty invalid row number. func EmptyRowNumber() RowNumber { - return RowNumber{-1, -1, -1, -1, -1, -1} + return RowNumber{-1, -1, -1, -1, -1, -1, -1} } // MaxRowNumber is a helper that represents the maximum(-ish) representable value. @@ -80,7 +80,8 @@ func EqualRowNumber(upToDefinitionLevel int, a, b RowNumber) bool { (a[2] == b[2] || upToDefinitionLevel < 2) && (a[3] == b[3] || upToDefinitionLevel < 3) && (a[4] == b[4] || upToDefinitionLevel < 4) && - (a[5] == b[5] || upToDefinitionLevel < 5) + (a[5] == b[5] || upToDefinitionLevel < 5) && + (a[6] == b[6] || upToDefinitionLevel < 6) } func TruncateRowNumber(definitionLevelToKeep int, t RowNumber) RowNumber { @@ -112,9 +113,6 @@ func (t *RowNumber) Valid() bool { // null | 0 | 1 | { 1, 0, -1, -1 } func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[repetitionLevel]++ - if definitionLevel == 6 { - definitionLevel = 5 - } // the following is nextSlow() unrolled switch repetitionLevel { @@ -126,36 +124,49 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[1] = 0 t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[1] = 0 t[2] = 0 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[1] = 0 t[2] = 0 t[3] = 0 t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[1] = 0 t[2] = 0 t[3] = 0 t[4] = 0 t[5] = -1 + t[6] = -1 case 5: t[1] = 0 t[2] = 0 t[3] = 0 t[4] = 0 t[5] = 0 + t[6] = -1 + case 6: + t[1] = 0 + t[2] = 0 + t[3] = 0 + t[4] = 0 + t[5] = 0 + t[6] = 0 } case 1: switch definitionLevel { @@ -165,31 +176,43 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[2] = 0 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[2] = 0 t[3] = 0 t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[2] = 0 t[3] = 0 t[4] = 0 t[5] = -1 + t[6] = -1 case 5: t[2] = 0 t[3] = 0 t[4] = 0 t[5] = 0 + t[6] = -1 + case 6: + t[2] = 0 + t[3] = 0 + t[4] = 0 + t[5] = 0 + t[6] = 0 } case 2: switch definitionLevel { @@ -199,27 +222,38 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[3] = 0 t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[3] = 0 t[4] = 0 t[5] = -1 + t[6] = -1 case 5: t[3] = 0 t[4] = 0 t[5] = 0 + t[6] = -1 + case 6: + t[3] = 0 + t[4] = 0 + t[5] = 0 + t[6] = 0 } case 3: switch definitionLevel { @@ -229,24 +263,34 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[4] = 0 t[5] = -1 + t[6] = -1 case 5: t[4] = 0 t[5] = 0 + t[6] = -1 + case 6: + t[4] = 0 + t[5] = 0 + t[6] = 0 } case 4: switch definitionLevel { @@ -256,22 +300,31 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[5] = -1 + t[6] = -1 case 5: t[5] = 0 + t[6] = -1 + case 6: + t[5] = 0 + t[6] = 0 } case 5: switch definitionLevel { @@ -281,20 +334,29 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 + t[6] = -1 case 3: t[4] = -1 t[5] = -1 + t[6] = -1 case 4: t[5] = -1 + t[6] = -1 + case 5: + t[6] = -1 + case 6: + t[6] = 0 } } } diff --git a/pkg/parquetquery/iters_test.go b/pkg/parquetquery/iters_test.go index 304ff31ed1f..b2cc25476ce 100644 --- a/pkg/parquetquery/iters_test.go +++ b/pkg/parquetquery/iters_test.go @@ -29,8 +29,8 @@ var iterTestCases = []struct { // TestNext compares the unrolled Next() with the original nextSlow() to // prevent drift func TestNext(t *testing.T) { - rn1 := RowNumber{0, 0, 0, 0, 0, 0} - rn2 := RowNumber{0, 0, 0, 0, 0, 0} + rn1 := RowNumber{0, 0, 0, 0, 0, 0, 0} + rn2 := RowNumber{0, 0, 0, 0, 0, 0, 0} for i := 0; i < 1000; i++ { r := rand.Intn(6) @@ -45,7 +45,7 @@ func TestNext(t *testing.T) { func TestRowNumber(t *testing.T) { tr := EmptyRowNumber() - require.Equal(t, RowNumber{-1, -1, -1, -1, -1, -1}, tr) + require.Equal(t, RowNumber{-1, -1, -1, -1, -1, -1, -1}, tr) steps := []struct { repetitionLevel int @@ -53,11 +53,11 @@ func TestRowNumber(t *testing.T) { expected RowNumber }{ // Name.Language.Country examples from the Dremel whitepaper - {0, 3, RowNumber{0, 0, 0, 0, -1, -1}}, - {2, 2, RowNumber{0, 0, 1, -1, -1, -1}}, - {1, 1, RowNumber{0, 1, -1, -1, -1, -1}}, - {1, 3, RowNumber{0, 2, 0, 0, -1, -1}}, - {0, 1, RowNumber{1, 0, -1, -1, -1, -1}}, + {0, 3, RowNumber{0, 0, 0, 0, -1, -1, -1}}, + {2, 2, RowNumber{0, 0, 1, -1, -1, -1, -1}}, + {1, 1, RowNumber{0, 1, -1, -1, -1, -1, -1}}, + {1, 3, RowNumber{0, 2, 0, 0, -1, -1, -1}}, + {0, 1, RowNumber{1, 0, -1, -1, -1, -1, -1}}, } for _, step := range steps { @@ -88,8 +88,8 @@ func TestRowNumberPreceding(t *testing.T) { testCases := []struct { start, preceding RowNumber }{ - {RowNumber{1000, -1, -1, -1, -1, -1}, RowNumber{999, -1, -1, -1, -1, -1}}, - {RowNumber{1000, 0, 0, 0, 0, 0}, RowNumber{999, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32}}, + {RowNumber{1000, -1, -1, -1, -1, -1, -1}, RowNumber{999, -1, -1, -1, -1, -1, -1}}, + {RowNumber{1000, 0, 0, 0, 0, 0, 0}, RowNumber{999, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32}}, } for _, tc := range testCases { @@ -117,7 +117,7 @@ func testColumnIterator(t *testing.T, makeIter makeTestIterFn) { res, err := iter.Next() require.NoError(t, err) require.NotNil(t, res, "i=%d", i) - require.Equal(t, RowNumber{int32(i), -1, -1, -1, -1, -1}, res.RowNumber) + require.Equal(t, RowNumber{int32(i), -1, -1, -1, -1, -1, -1}, res.RowNumber) require.Equal(t, int64(i), res.ToMap()["A"][0].Int64()) } @@ -156,7 +156,7 @@ func testColumnIteratorSeek(t *testing.T, makeIter makeTestIterFn) { res, err := iter.SeekTo(rn, 0) require.NoError(t, err) require.NotNil(t, res, "seekTo=%v", seekTo) - require.Equal(t, RowNumber{seekTo, -1, -1, -1, -1, -1}, res.RowNumber) + require.Equal(t, RowNumber{seekTo, -1, -1, -1, -1, -1, -1}, res.RowNumber) require.Equal(t, seekTo, res.ToMap()["A"][0].Int32()) } } @@ -189,7 +189,7 @@ func testColumnIteratorPredicate(t *testing.T, makeIter makeTestIterFn) { res, err := iter.Next() require.NoError(t, err) require.NotNil(t, res) - require.Equal(t, RowNumber{expectedResult, -1, -1, -1, -1, -1}, res.RowNumber) + require.Equal(t, RowNumber{expectedResult, -1, -1, -1, -1, -1, -1}, res.RowNumber) require.Equal(t, expectedResult, res.ToMap()["A"][0].Int32()) } } From 463890a437316f7b10b034af90475df6ead86a0c Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Mon, 24 Jun 2024 21:47:43 -0500 Subject: [PATCH 08/22] 8 levels --- pkg/parquetquery/iters.go | 188 +++++++++++++++++++++++++++++++-- pkg/parquetquery/iters_test.go | 51 +++++---- 2 files changed, 215 insertions(+), 24 deletions(-) diff --git a/pkg/parquetquery/iters.go b/pkg/parquetquery/iters.go index 953f80b8394..e6790931f1b 100644 --- a/pkg/parquetquery/iters.go +++ b/pkg/parquetquery/iters.go @@ -30,14 +30,14 @@ import ( // D 0, 1, 0 // E 0, 2, -1 // -// Currently supports 7 levels of nesting which should be enough for anybody. :) -type RowNumber [7]int32 +// Currently supports 8 levels of nesting which should be enough for anybody. :) +type RowNumber [8]int32 -const MaxDefinitionLevel = 6 +const MaxDefinitionLevel = 7 // EmptyRowNumber creates an empty invalid row number. func EmptyRowNumber() RowNumber { - return RowNumber{-1, -1, -1, -1, -1, -1, -1} + return RowNumber{-1, -1, -1, -1, -1, -1, -1, -1} } // MaxRowNumber is a helper that represents the maximum(-ish) representable value. @@ -81,10 +81,11 @@ func EqualRowNumber(upToDefinitionLevel int, a, b RowNumber) bool { (a[3] == b[3] || upToDefinitionLevel < 3) && (a[4] == b[4] || upToDefinitionLevel < 4) && (a[5] == b[5] || upToDefinitionLevel < 5) && - (a[6] == b[6] || upToDefinitionLevel < 6) + (a[6] == b[6] || upToDefinitionLevel < 6) && + (a[7] == b[7] || upToDefinitionLevel < 7) } -func TruncateRowNumber(definitionLevelToKeep int, t RowNumber) RowNumber { +func truncateRowNumberSlow(definitionLevelToKeep int, t RowNumber) RowNumber { n := EmptyRowNumber() for i := 0; i <= definitionLevelToKeep; i++ { n[i] = t[i] @@ -92,6 +93,28 @@ func TruncateRowNumber(definitionLevelToKeep int, t RowNumber) RowNumber { return n } +func TruncateRowNumber(definitionLevelToKeep int, t RowNumber) RowNumber { + switch definitionLevelToKeep { + case 0: + return RowNumber{t[0], -1, -1, -1, -1, -1, -1, -1} + case 1: + return RowNumber{t[0], t[1], -1, -1, -1, -1, -1, -1} + case 2: + return RowNumber{t[0], t[1], t[2], -1, -1, -1, -1, -1} + case 3: + return RowNumber{t[0], t[1], t[2], t[3], -1, -1, -1, -1} + case 4: + return RowNumber{t[0], t[1], t[2], t[3], t[4], -1, -1, -1} + case 5: + return RowNumber{t[0], t[1], t[2], t[3], t[4], t[5], -1, -1} + case 6: + return RowNumber{t[0], t[1], t[2], t[3], t[4], t[5], t[6], -1} + case 7: + return RowNumber{t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]} + } + return TruncateRowNumber(definitionLevelToKeep, t) +} + func (t *RowNumber) Valid() bool { return t[0] >= 0 } @@ -125,6 +148,7 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 1: t[1] = 0 t[2] = -1 @@ -132,6 +156,7 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 2: t[1] = 0 t[2] = 0 @@ -139,6 +164,7 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 3: t[1] = 0 t[2] = 0 @@ -146,6 +172,7 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 4: t[1] = 0 t[2] = 0 @@ -153,6 +180,7 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = 0 t[5] = -1 t[6] = -1 + t[7] = -1 case 5: t[1] = 0 t[2] = 0 @@ -160,6 +188,7 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = 0 t[5] = 0 t[6] = -1 + t[7] = -1 case 6: t[1] = 0 t[2] = 0 @@ -167,6 +196,15 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = 0 t[5] = 0 t[6] = 0 + t[7] = -1 + case 7: + t[1] = 0 + t[2] = 0 + t[3] = 0 + t[4] = 0 + t[5] = 0 + t[6] = 0 + t[7] = 0 } case 1: switch definitionLevel { @@ -177,42 +215,56 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 2: t[2] = 0 t[3] = -1 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 3: t[2] = 0 t[3] = 0 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 4: t[2] = 0 t[3] = 0 t[4] = 0 t[5] = -1 t[6] = -1 + t[7] = -1 case 5: t[2] = 0 t[3] = 0 t[4] = 0 t[5] = 0 t[6] = -1 + t[7] = -1 case 6: t[2] = 0 t[3] = 0 t[4] = 0 t[5] = 0 t[6] = 0 + t[7] = -1 + case 7: + t[2] = 0 + t[3] = 0 + t[4] = 0 + t[5] = 0 + t[6] = 0 + t[7] = 0 } case 2: switch definitionLevel { @@ -223,37 +275,50 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 3: t[3] = 0 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 4: t[3] = 0 t[4] = 0 t[5] = -1 t[6] = -1 + t[7] = -1 case 5: t[3] = 0 t[4] = 0 t[5] = 0 t[6] = -1 + t[7] = -1 case 6: t[3] = 0 t[4] = 0 t[5] = 0 t[6] = 0 + t[7] = -1 + case 7: + t[3] = 0 + t[4] = 0 + t[5] = 0 + t[6] = 0 + t[7] = 0 } case 3: switch definitionLevel { @@ -264,33 +329,45 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 3: t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 4: t[4] = 0 t[5] = -1 t[6] = -1 + t[7] = -1 case 5: t[4] = 0 t[5] = 0 t[6] = -1 + t[7] = -1 case 6: t[4] = 0 t[5] = 0 t[6] = 0 + t[7] = -1 + case 7: + t[4] = 0 + t[5] = 0 + t[6] = 0 + t[7] = 0 } case 4: switch definitionLevel { @@ -301,30 +378,41 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 3: t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 4: t[5] = -1 t[6] = -1 + t[7] = -1 case 5: t[5] = 0 t[6] = -1 + t[7] = -1 case 6: t[5] = 0 t[6] = 0 + t[7] = -1 + case 7: + t[5] = 0 + t[6] = 0 + t[7] = 0 } case 5: switch definitionLevel { @@ -335,28 +423,116 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 1: t[2] = -1 t[3] = -1 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 2: t[3] = -1 t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 3: t[4] = -1 t[5] = -1 t[6] = -1 + t[7] = -1 case 4: t[5] = -1 t[6] = -1 + t[7] = -1 case 5: t[6] = -1 + t[7] = -1 case 6: t[6] = 0 + t[7] = -1 + case 7: + t[6] = 0 + t[7] = 0 + } + case 6: + switch definitionLevel { + case 0: + t[1] = -1 + t[2] = -1 + t[3] = -1 + t[4] = -1 + t[5] = -1 + t[6] = -1 + t[7] = -1 + case 1: + t[2] = -1 + t[3] = -1 + t[4] = -1 + t[5] = -1 + t[6] = -1 + t[7] = -1 + case 2: + t[3] = -1 + t[4] = -1 + t[5] = -1 + t[6] = -1 + t[7] = -1 + case 3: + t[4] = -1 + t[5] = -1 + t[6] = -1 + t[7] = -1 + case 4: + t[5] = -1 + t[6] = -1 + t[7] = -1 + case 5: + t[6] = -1 + t[7] = -1 + case 6: + t[7] = -1 + case 7: + t[7] = 0 + } + case 7: + switch definitionLevel { + case 0: + t[1] = -1 + t[2] = -1 + t[3] = -1 + t[4] = -1 + t[5] = -1 + t[6] = -1 + t[7] = -1 + case 1: + t[2] = -1 + t[3] = -1 + t[4] = -1 + t[5] = -1 + t[6] = -1 + t[7] = -1 + case 2: + t[3] = -1 + t[4] = -1 + t[5] = -1 + t[6] = -1 + t[7] = -1 + case 3: + t[4] = -1 + t[5] = -1 + t[6] = -1 + t[7] = -1 + case 4: + t[5] = -1 + t[6] = -1 + t[7] = -1 + case 5: + t[6] = -1 + t[7] = -1 + case 6: + t[7] = -1 } } } diff --git a/pkg/parquetquery/iters_test.go b/pkg/parquetquery/iters_test.go index b2cc25476ce..173119096e9 100644 --- a/pkg/parquetquery/iters_test.go +++ b/pkg/parquetquery/iters_test.go @@ -29,12 +29,12 @@ var iterTestCases = []struct { // TestNext compares the unrolled Next() with the original nextSlow() to // prevent drift func TestNext(t *testing.T) { - rn1 := RowNumber{0, 0, 0, 0, 0, 0, 0} - rn2 := RowNumber{0, 0, 0, 0, 0, 0, 0} + rn1 := RowNumber{0, 0, 0, 0, 0, 0, 0, 0} + rn2 := RowNumber{0, 0, 0, 0, 0, 0, 0, 0} for i := 0; i < 1000; i++ { - r := rand.Intn(6) - d := rand.Intn(6) + r := rand.Intn(MaxDefinitionLevel + 1) + d := rand.Intn(MaxDefinitionLevel + 1) rn1.Next(r, d) rn2.nextSlow(r, d) @@ -43,9 +43,24 @@ func TestNext(t *testing.T) { } } +// TestTruncate compares the unrolled TruncateRowNumber() with the original truncateRowNumberSlow() to +// prevent drift +func TestTruncate(t *testing.T) { + + for i := 0; i < 1000; i++ { + rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} + d := rand.Intn(MaxDefinitionLevel + 1) + + new := TruncateRowNumber(d, rn) + old := truncateRowNumberSlow(d, rn) + + require.Equal(t, new, old) + } +} + func TestRowNumber(t *testing.T) { tr := EmptyRowNumber() - require.Equal(t, RowNumber{-1, -1, -1, -1, -1, -1, -1}, tr) + require.Equal(t, RowNumber{-1, -1, -1, -1, -1, -1, -1, -1}, tr) steps := []struct { repetitionLevel int @@ -53,11 +68,11 @@ func TestRowNumber(t *testing.T) { expected RowNumber }{ // Name.Language.Country examples from the Dremel whitepaper - {0, 3, RowNumber{0, 0, 0, 0, -1, -1, -1}}, - {2, 2, RowNumber{0, 0, 1, -1, -1, -1, -1}}, - {1, 1, RowNumber{0, 1, -1, -1, -1, -1, -1}}, - {1, 3, RowNumber{0, 2, 0, 0, -1, -1, -1}}, - {0, 1, RowNumber{1, 0, -1, -1, -1, -1, -1}}, + {0, 3, RowNumber{0, 0, 0, 0, -1, -1, -1, -1}}, + {2, 2, RowNumber{0, 0, 1, -1, -1, -1, -1, -1}}, + {1, 1, RowNumber{0, 1, -1, -1, -1, -1, -1, -1}}, + {1, 3, RowNumber{0, 2, 0, 0, -1, -1, -1, -1}}, + {0, 1, RowNumber{1, 0, -1, -1, -1, -1, -1, -1}}, } for _, step := range steps { @@ -88,8 +103,8 @@ func TestRowNumberPreceding(t *testing.T) { testCases := []struct { start, preceding RowNumber }{ - {RowNumber{1000, -1, -1, -1, -1, -1, -1}, RowNumber{999, -1, -1, -1, -1, -1, -1}}, - {RowNumber{1000, 0, 0, 0, 0, 0, 0}, RowNumber{999, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32}}, + {RowNumber{1000, -1, -1, -1, -1, -1, -1, -1}, RowNumber{999, -1, -1, -1, -1, -1, -1, -1}}, + {RowNumber{1000, 0, 0, 0, 0, 0, 0, 0}, RowNumber{999, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32, math.MaxInt32}}, } for _, tc := range testCases { @@ -117,7 +132,7 @@ func testColumnIterator(t *testing.T, makeIter makeTestIterFn) { res, err := iter.Next() require.NoError(t, err) require.NotNil(t, res, "i=%d", i) - require.Equal(t, RowNumber{int32(i), -1, -1, -1, -1, -1, -1}, res.RowNumber) + require.Equal(t, RowNumber{int32(i), -1, -1, -1, -1, -1, -1, -1}, res.RowNumber) require.Equal(t, int64(i), res.ToMap()["A"][0].Int64()) } @@ -156,7 +171,7 @@ func testColumnIteratorSeek(t *testing.T, makeIter makeTestIterFn) { res, err := iter.SeekTo(rn, 0) require.NoError(t, err) require.NotNil(t, res, "seekTo=%v", seekTo) - require.Equal(t, RowNumber{seekTo, -1, -1, -1, -1, -1, -1}, res.RowNumber) + require.Equal(t, RowNumber{seekTo, -1, -1, -1, -1, -1, -1, -1}, res.RowNumber) require.Equal(t, seekTo, res.ToMap()["A"][0].Int32()) } } @@ -189,7 +204,7 @@ func testColumnIteratorPredicate(t *testing.T, makeIter makeTestIterFn) { res, err := iter.Next() require.NoError(t, err) require.NotNil(t, res) - require.Equal(t, RowNumber{expectedResult, -1, -1, -1, -1, -1, -1}, res.RowNumber) + require.Equal(t, RowNumber{expectedResult, -1, -1, -1, -1, -1, -1, -1}, res.RowNumber) require.Equal(t, expectedResult, res.ToMap()["A"][0].Int32()) } } @@ -357,13 +372,13 @@ func TestEqualRowNumber(t *testing.T) { } func BenchmarkEqualRowNumber(b *testing.B) { - r1 := RowNumber{1, 2, 3, 4, 5, 6} - r2 := RowNumber{1, 2, 3, 5, 7, 9} + r1 := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} + r2 := RowNumber{1, 2, 3, 5, 7, 9, 11, 13} for d := 0; d <= MaxDefinitionLevel; d++ { b.Run(strconv.Itoa(d), func(b *testing.B) { for i := 0; i < b.N; i++ { - EqualRowNumber(3, r1, r2) + EqualRowNumber(d, r1, r2) } }) } From c4d98e9614d7e55b11571dccfe0a8723bd47a1d9 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Mon, 24 Jun 2024 22:31:47 -0500 Subject: [PATCH 09/22] update doc --- docs/sources/tempo/traceql/_index.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/sources/tempo/traceql/_index.md b/docs/sources/tempo/traceql/_index.md index 6efc8dd14a7..b44b9378536 100644 --- a/docs/sources/tempo/traceql/_index.md +++ b/docs/sources/tempo/traceql/_index.md @@ -101,7 +101,7 @@ possible to span-level intrinsics. ### Attribute fields -There are two types of attributes: span attributes and resource attributes. By expanding a span in the Grafana UI, you can see both its span attributes (1 in the screenshot) and resource attributes (2 in the screenshot). +There are three types of attributes: span attributes, resource attributes, and event attributes. By expanding a span in the Grafana UI, you can see both its span attributes (1 in the screenshot) and resource attributes (2 in the screenshot).

Example of span and resource  attributes.

@@ -158,6 +158,11 @@ You can use quoted attributes syntax with non-quoted attribute syntax, the follo { span.attribute."attribute name with space" = "value" } ``` +You can query for an exception in your span event +``` +{ event.exception.message ~= "something went wrong" } +``` + {{< admonition type="note" >}} Currently, only the `\"` and `\\` escape sequences are supported. {{% /admonition %}} From 2d037123de10281f32aeafea45296a17d0db48c4 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Mon, 24 Jun 2024 23:04:12 -0500 Subject: [PATCH 10/22] rebase and changelog --- CHANGELOG.md | 1 + tempodb/encoding/vparquet4/block_traceql.go | 59 ++++++++++++--------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44f67816624..7f69a62f5a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * [CHANGE] Update Go to 1.22.4 [#3757](https://github.com/grafana/tempo/pull/3757) [#3793](https://github.com/grafana/tempo/pull/3793) (@joe-elliott, @mapno) * [FEATURE] TraceQL support for link scope and link:traceID and link:spanID [#3741](https://github.com/grafana/tempo/pull/3741) (@stoewer) * [FEATURE] TraceQL support for event scope and event:name intrinsic [#3708](https://github.com/grafana/tempo/pull/3708) (@stoewer) +* [FEATURE] TraecQL support for event attributes [#3708](https://github.com/grafana/tempo/pull/3748) (@ie-pham) * [FEATURE] Flush and query RF1 blocks for TraceQL metric queries [#3628](https://github.com/grafana/tempo/pull/3628) [#3691](https://github.com/grafana/tempo/pull/3691) [#3723](https://github.com/grafana/tempo/pull/3723) (@mapno) * [FEATURE] Add new compare() metrics function [#3695](https://github.com/grafana/tempo/pull/3695) (@mdisibio) * [ENHANCEMENT] Tag value lookup use protobuf internally for improved latency [#3731](https://github.com/grafana/tempo/pull/3731) (@mdisibio) diff --git a/tempodb/encoding/vparquet4/block_traceql.go b/tempodb/encoding/vparquet4/block_traceql.go index f5ec0cda927..a69a5111cc0 100644 --- a/tempodb/encoding/vparquet4/block_traceql.go +++ b/tempodb/encoding/vparquet4/block_traceql.go @@ -1369,27 +1369,38 @@ func (i *mergeSpansetIterator) Close() { // // Diagram: // -// Span attribute iterator: key ----------------------------- -// ... -------------------------- | -// Span attribute iterator: valueN ----------------------| | | -// | | | -// V V V -// ------------- -// | attribute | -// | collector | -// ------------- -// | -// | List of attributes -// | -// | -// Span column iterator 1 --------------------------- | -// ... ------------------------ | | -// Span column iterator N --------------------- | | | -// (ex: name, status) | | | | -// V V V V -// ------------------ -// | span collector | -// ------------------ +// Event attribute iterator: key -------------------------------------------- +// | | +// Event attribute iterator: valunN --------------------------------------- | | +// | | | +// V V V +// ------------ +// Event column iterator 1 --------------------------------------------- | attribute | +// (ex: name, time since) | | collector | +// | ------------ +// | | +// V V +// Span attribute iterator: key ------------------------- ------------ +// ... ----------------------- | | event | +// Span attribute iterator: valueN -------------------| | | | collector | +// | | | ------------- +// V V V | +// ------------- | +// | attribute | | +// | collector | | +// ------------- | +// | | +// | List | +// | of span | +// | attributes | +// Span column iterator 1 --------------------------- | | +// ... ------------------------ | | | +// Span column iterator N --------------------- | | | | +// (ex: name, status) | | | | | +// V V V V V +// ------------------------------------------------- +// | span collector | +// ------------------------------------------------- // | // | List of Spans // Resource attribute | @@ -1534,7 +1545,7 @@ func createAllIterator(ctx context.Context, primaryIter parquetquery.Iterator, c innerIterators = append(innerIterators, primaryIter) } - eventIter, err := createEventIterator(makeIter, primaryIter, catConditions.event, allConditions) + eventIter, err := createEventIterator(makeIter, primaryIter, catConditions.event, allConditions, selectAll) if err != nil { return nil, fmt.Errorf("creating event iterator: %w", err) } @@ -1563,7 +1574,7 @@ func createAllIterator(ctx context.Context, primaryIter parquetquery.Iterator, c return createTraceIterator(makeIter, resourceIter, catConditions.trace, start, end, shardID, shardCount, allConditions, selectAll) } -func createEventIterator(makeIter makeIterFn, primaryIter parquetquery.Iterator, conditions []traceql.Condition, allConditions bool) (parquetquery.Iterator, error) { +func createEventIterator(makeIter makeIterFn, primaryIter parquetquery.Iterator, conditions []traceql.Condition, allConditions bool, selectAll bool) (parquetquery.Iterator, error) { if len(conditions) == 0 { return nil, nil } @@ -1585,7 +1596,7 @@ func createEventIterator(makeIter makeIterFn, primaryIter parquetquery.Iterator, } attrIter, err := createAttributeIterator(makeIter, genericConditions, DefinitionLevelResourceSpansILSSpanEventAttrs, - columnPathEventAttrKey, columnPathEventAttrString, columnPathEventAttrInt, columnPathEventAttrDouble, columnPathEventAttrBool, allConditions) + columnPathEventAttrKey, columnPathEventAttrString, columnPathEventAttrInt, columnPathEventAttrDouble, columnPathEventAttrBool, allConditions, selectAll) if err != nil { return nil, fmt.Errorf("creating span attribute iterator: %w", err) } From b54275d87e44d82b5acba07e09a012818234d935 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Mon, 24 Jun 2024 23:09:07 -0500 Subject: [PATCH 11/22] meow --- docs/sources/tempo/traceql/_index.md | 12 ++++++------ tempodb/encoding/vparquet4/block_traceql.go | 16 +--------------- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/docs/sources/tempo/traceql/_index.md b/docs/sources/tempo/traceql/_index.md index b44b9378536..991293312c8 100644 --- a/docs/sources/tempo/traceql/_index.md +++ b/docs/sources/tempo/traceql/_index.md @@ -128,6 +128,12 @@ Find any database connection string that goes to a Postgres or MySQL database: { span.db.system =~ "postgresql|mysql" } ``` +You can use quoted attributes syntax with non-quoted attribute syntax, the following is a valid TraceQL query: + +``` +{ span.attribute."attribute name with space" = "value" } +``` + ### Unscoped attribute fields Attributes can be unscoped if you are unsure if the requested attribute exists on the span or resource. When possible, use scoped instead of unscoped attributes. Scoped attributes provide faster query results. @@ -152,12 +158,6 @@ To find a span with the attribute name `attribute name with space`, use the foll { ."attribute name with space" = "value" } ``` -You can use quoted attributes syntax with non-quoted attribute syntax, the following is a valid TraceQL query: - -``` -{ span.attribute."attribute name with space" = "value" } -``` - You can query for an exception in your span event ``` { event.exception.message ~= "something went wrong" } diff --git a/tempodb/encoding/vparquet4/block_traceql.go b/tempodb/encoding/vparquet4/block_traceql.go index a69a5111cc0..e73bfdaf996 100644 --- a/tempodb/encoding/vparquet4/block_traceql.go +++ b/tempodb/encoding/vparquet4/block_traceql.go @@ -1598,7 +1598,7 @@ func createEventIterator(makeIter makeIterFn, primaryIter parquetquery.Iterator, attrIter, err := createAttributeIterator(makeIter, genericConditions, DefinitionLevelResourceSpansILSSpanEventAttrs, columnPathEventAttrKey, columnPathEventAttrString, columnPathEventAttrInt, columnPathEventAttrDouble, columnPathEventAttrBool, allConditions, selectAll) if err != nil { - return nil, fmt.Errorf("creating span attribute iterator: %w", err) + return nil, fmt.Errorf("creating event attribute iterator: %w", err) } if attrIter != nil { @@ -1632,20 +1632,6 @@ func createEventIterator(makeIter makeIterFn, primaryIter parquetquery.Iterator, eventIters = nil } - // This is an optimization for cases when allConditions is false, and - // only span conditions are present, and we require at least one of them to match. - // Wrap up the individual conditions with a union and move it into the required list. - // This skips over static columns like ID that are omnipresent. This is also only - // possible when there isn't a duration filter because it's computed from start/end. - - // if there are no direct conditions imposed on the span/span attributes level we are purposefully going to request the "Kind" column - // b/c it is extremely cheap to retrieve. retrieving matching spans in this case will allow aggregates such as "count" to be computed - // how do we know to pull duration for things like | avg(duration) > 1s? look at avg(span.http.status_code) it pushes a column request down here - // the entire engine is built around spans. we have to return at least one entry for every span to the layers above for things to work - // TODO: note that if the query is { kind = client } the fetch layer will actually create two iterators over the kind column. this is evidence - // this spaniterator code could be tightened up - // Also note that this breaks optimizations related to requireAtLeastOneMatch and requireAtLeastOneMatchOverall b/c it will add a kind attribute - // to the span attributes map in spanCollector if len(required) == 0 { required = []parquetquery.Iterator{makeIter(columnPathEventName, nil, "")} } From 3114356e3bfa7483f2552a16542e5e75ff299d18 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Mon, 24 Jun 2024 23:11:11 -0500 Subject: [PATCH 12/22] lint smh --- pkg/parquetquery/iters_test.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/parquetquery/iters_test.go b/pkg/parquetquery/iters_test.go index 173119096e9..da99dcd27ec 100644 --- a/pkg/parquetquery/iters_test.go +++ b/pkg/parquetquery/iters_test.go @@ -46,15 +46,14 @@ func TestNext(t *testing.T) { // TestTruncate compares the unrolled TruncateRowNumber() with the original truncateRowNumberSlow() to // prevent drift func TestTruncate(t *testing.T) { - for i := 0; i < 1000; i++ { rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} d := rand.Intn(MaxDefinitionLevel + 1) - new := TruncateRowNumber(d, rn) - old := truncateRowNumberSlow(d, rn) + newR := TruncateRowNumber(d, rn) + oldR := truncateRowNumberSlow(d, rn) - require.Equal(t, new, old) + require.Equal(t, newR, oldR) } } From 27a7502c39a1c506cc395391f484d2e2278e5e55 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Tue, 25 Jun 2024 17:40:51 -0500 Subject: [PATCH 13/22] oops docs --- docs/sources/tempo/traceql/_index.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/sources/tempo/traceql/_index.md b/docs/sources/tempo/traceql/_index.md index 991293312c8..ff85f8fb45f 100644 --- a/docs/sources/tempo/traceql/_index.md +++ b/docs/sources/tempo/traceql/_index.md @@ -128,10 +128,9 @@ Find any database connection string that goes to a Postgres or MySQL database: { span.db.system =~ "postgresql|mysql" } ``` -You can use quoted attributes syntax with non-quoted attribute syntax, the following is a valid TraceQL query: - +You can query for an exception in your span event ``` -{ span.attribute."attribute name with space" = "value" } +{ event.exception.message ~= "something went wrong" } ``` ### Unscoped attribute fields @@ -158,9 +157,10 @@ To find a span with the attribute name `attribute name with space`, use the foll { ."attribute name with space" = "value" } ``` -You can query for an exception in your span event +You can use quoted attributes syntax with non-quoted attribute syntax, the following is a valid TraceQL query: + ``` -{ event.exception.message ~= "something went wrong" } +{ span.attribute."attribute name with space" = "value" } ``` {{< admonition type="note" >}} From 470f19859f23075331ac6956b0aafca624f9ac2e Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Wed, 26 Jun 2024 09:53:18 -0500 Subject: [PATCH 14/22] addressing comments --- docs/sources/tempo/traceql/_index.md | 6 +++--- pkg/parquetquery/iters.go | 6 +++++- pkg/parquetquery/iters_test.go | 18 +++++++++++++++++- pkg/traceql/expr.y | 6 +++--- tempodb/encoding/vparquet4/block_traceql.go | 13 ++++++------- 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/docs/sources/tempo/traceql/_index.md b/docs/sources/tempo/traceql/_index.md index ff85f8fb45f..13597d90f89 100644 --- a/docs/sources/tempo/traceql/_index.md +++ b/docs/sources/tempo/traceql/_index.md @@ -71,7 +71,7 @@ TraceQL differentiates between two types of span data: intrinsics, which are fun In TraceQL, curly brackets `{}` always select a set of spans from the current trace. They are commonly paired with a condition to reduce the spans being passed in. -### Intrinsic fields +### Scoped Intrinsic fields Intrinsic fields are fundamental to spans. These fields can be referenced when selecting spans. Note that custom attributes are prefixed with `.`, `span.` or `resource.` whereas intrinsics are typed directly. @@ -101,7 +101,7 @@ possible to span-level intrinsics. ### Attribute fields -There are three types of attributes: span attributes, resource attributes, and event attributes. By expanding a span in the Grafana UI, you can see both its span attributes (1 in the screenshot) and resource attributes (2 in the screenshot). +TraceQL has three different attribute scopes: span attributes, resource attributes, and event attributes. By expanding a span in the Grafana UI, you can see both its span attributes (1 in the screenshot) and resource attributes (2 in the screenshot).

Example of span and resource  attributes.

@@ -130,7 +130,7 @@ Find any database connection string that goes to a Postgres or MySQL database: You can query for an exception in your span event ``` -{ event.exception.message ~= "something went wrong" } +{ event.exception.message =~ "something went wrong" } ``` ### Unscoped attribute fields diff --git a/pkg/parquetquery/iters.go b/pkg/parquetquery/iters.go index e6790931f1b..7190b86b9a9 100644 --- a/pkg/parquetquery/iters.go +++ b/pkg/parquetquery/iters.go @@ -10,8 +10,11 @@ import ( "sync" "sync/atomic" + "github.com/go-kit/log/level" + "github.com/grafana/tempo/pkg/parquetquery/intern" "github.com/grafana/tempo/pkg/util" + "github.com/grafana/tempo/pkg/util/log" "github.com/opentracing/opentracing-go" pq "github.com/parquet-go/parquet-go" ) @@ -112,7 +115,8 @@ func TruncateRowNumber(definitionLevelToKeep int, t RowNumber) RowNumber { case 7: return RowNumber{t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]} } - return TruncateRowNumber(definitionLevelToKeep, t) + level.Error(log.Logger).Log("msg", "definition level out of bound: should be [0:7] but got %d", definitionLevelToKeep) + return EmptyRowNumber() } func (t *RowNumber) Valid() bool { diff --git a/pkg/parquetquery/iters_test.go b/pkg/parquetquery/iters_test.go index da99dcd27ec..85643c98a82 100644 --- a/pkg/parquetquery/iters_test.go +++ b/pkg/parquetquery/iters_test.go @@ -45,7 +45,7 @@ func TestNext(t *testing.T) { // TestTruncate compares the unrolled TruncateRowNumber() with the original truncateRowNumberSlow() to // prevent drift -func TestTruncate(t *testing.T) { +func TestTruncateRowNumber(t *testing.T) { for i := 0; i < 1000; i++ { rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} d := rand.Intn(MaxDefinitionLevel + 1) @@ -55,6 +55,22 @@ func TestTruncate(t *testing.T) { require.Equal(t, newR, oldR) } + + // Test with d > MaxDefinitionLevel + rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} + d := MaxDefinitionLevel + 1 + newR := TruncateRowNumber(d, rn) + oldR := truncateRowNumberSlow(d, rn) + + require.Equal(t, newR, oldR) + + // Test with d < 0 + rn = RowNumber{1, 2, 3, 4, 5, 6, 7, 8} + d = -1 + newR = TruncateRowNumber(d, rn) + oldR = truncateRowNumberSlow(d, rn) + + require.Equal(t, newR, oldR) } func TestRowNumber(t *testing.T) { diff --git a/pkg/traceql/expr.y b/pkg/traceql/expr.y index 8a2e15ebe1f..4c5aa59e5cd 100644 --- a/pkg/traceql/expr.y +++ b/pkg/traceql/expr.y @@ -405,10 +405,10 @@ scopedIntrinsicField: | SPAN_COLON STATUS_MESSAGE { $$ = NewIntrinsic(IntrinsicStatusMessage) } | SPAN_COLON ID { $$ = NewIntrinsic(IntrinsicSpanID) } // event: - | EVENT_COLON NAME { $$ = NewIntrinsic(IntrinsicEventName) } + | EVENT_COLON NAME { $$ = NewIntrinsic(IntrinsicEventName) } // link: - | LINK_COLON TRACE_ID { $$ = NewIntrinsic(IntrinsicLinkTraceID) } - | LINK_COLON SPAN_ID { $$ = NewIntrinsic(IntrinsicLinkSpanID) } + | LINK_COLON TRACE_ID { $$ = NewIntrinsic(IntrinsicLinkTraceID) } + | LINK_COLON SPAN_ID { $$ = NewIntrinsic(IntrinsicLinkSpanID) } ; attributeField: diff --git a/tempodb/encoding/vparquet4/block_traceql.go b/tempodb/encoding/vparquet4/block_traceql.go index e73bfdaf996..cea7fe5aaf2 100644 --- a/tempodb/encoding/vparquet4/block_traceql.go +++ b/tempodb/encoding/vparquet4/block_traceql.go @@ -1370,8 +1370,8 @@ func (i *mergeSpansetIterator) Close() { // Diagram: // // Event attribute iterator: key -------------------------------------------- -// | | -// Event attribute iterator: valunN --------------------------------------- | | +// ... ----------------------------------------- | +// Event attribute iterator: valueN --------------------------------------- | | // | | | // V V V // ------------ @@ -1386,9 +1386,9 @@ func (i *mergeSpansetIterator) Close() { // | | | ------------- // V V V | // ------------- | -// | attribute | | -// | collector | | -// ------------- | +// | attribute | | list +// | collector | | of +// ------------- | events // | | // | List | // | of span | @@ -2912,8 +2912,7 @@ func (c *eventCollector) KeepGroup(res *parquetquery.IteratorResult) bool { } } - res.Entries = res.Entries[:0] - res.OtherEntries = res.OtherEntries[:0] + res.Reset() res.AppendOtherValue(otherEntryEventKey, ev) return true From 78b6871486892e9fc6b6cf5ef9c64dbe1b651ce1 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Wed, 26 Jun 2024 13:34:36 -0500 Subject: [PATCH 15/22] oopsie --- docs/sources/tempo/traceql/_index.md | 2 +- pkg/parquetquery/iters.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/sources/tempo/traceql/_index.md b/docs/sources/tempo/traceql/_index.md index 13597d90f89..753c465d8b3 100644 --- a/docs/sources/tempo/traceql/_index.md +++ b/docs/sources/tempo/traceql/_index.md @@ -71,7 +71,7 @@ TraceQL differentiates between two types of span data: intrinsics, which are fun In TraceQL, curly brackets `{}` always select a set of spans from the current trace. They are commonly paired with a condition to reduce the spans being passed in. -### Scoped Intrinsic fields +### Intrinsic fields Intrinsic fields are fundamental to spans. These fields can be referenced when selecting spans. Note that custom attributes are prefixed with `.`, `span.` or `resource.` whereas intrinsics are typed directly. diff --git a/pkg/parquetquery/iters.go b/pkg/parquetquery/iters.go index 7190b86b9a9..9bcb9b6af9f 100644 --- a/pkg/parquetquery/iters.go +++ b/pkg/parquetquery/iters.go @@ -90,6 +90,10 @@ func EqualRowNumber(upToDefinitionLevel int, a, b RowNumber) bool { func truncateRowNumberSlow(definitionLevelToKeep int, t RowNumber) RowNumber { n := EmptyRowNumber() + if definitionLevelToKeep > MaxDefinitionLevel { + level.Error(log.Logger).Log("msg", "definition level out of bound: should be [0:7] but got %d", definitionLevelToKeep) + return n + } for i := 0; i <= definitionLevelToKeep; i++ { n[i] = t[i] } From 30c06402ae3200ac418f156751825ef096a07e15 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Wed, 26 Jun 2024 19:51:02 -0500 Subject: [PATCH 16/22] panic! at the dis-row..number --- pkg/parquetquery/iters.go | 14 +++++---- pkg/parquetquery/iters_test.go | 54 ++++++++++++++++++++++++++-------- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/pkg/parquetquery/iters.go b/pkg/parquetquery/iters.go index 9bcb9b6af9f..c70dd68f84e 100644 --- a/pkg/parquetquery/iters.go +++ b/pkg/parquetquery/iters.go @@ -90,10 +90,6 @@ func EqualRowNumber(upToDefinitionLevel int, a, b RowNumber) bool { func truncateRowNumberSlow(definitionLevelToKeep int, t RowNumber) RowNumber { n := EmptyRowNumber() - if definitionLevelToKeep > MaxDefinitionLevel { - level.Error(log.Logger).Log("msg", "definition level out of bound: should be [0:7] but got %d", definitionLevelToKeep) - return n - } for i := 0; i <= definitionLevelToKeep; i++ { n[i] = t[i] } @@ -119,7 +115,11 @@ func TruncateRowNumber(definitionLevelToKeep int, t RowNumber) RowNumber { case 7: return RowNumber{t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]} } - level.Error(log.Logger).Log("msg", "definition level out of bound: should be [0:7] but got %d", definitionLevelToKeep) + + if definitionLevelToKeep > MaxDefinitionLevel || definitionLevelToKeep < 0 { + level.Error(log.Logger).Log("msg", "definition level out of bound: should be [0:7] but got %d", definitionLevelToKeep) + panic("invalid definition level") + } return EmptyRowNumber() } @@ -543,6 +543,10 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[7] = -1 } } + if definitionLevel > MaxDefinitionLevel || definitionLevel < 0 { + level.Error(log.Logger).Log("msg", "definition level out of bound: should be [0:7] but got %d", definitionLevel) + panic("invalid definition level") + } } // nextSlow is the original implementation of next. it is kept to test against diff --git a/pkg/parquetquery/iters_test.go b/pkg/parquetquery/iters_test.go index 85643c98a82..562199e6ef5 100644 --- a/pkg/parquetquery/iters_test.go +++ b/pkg/parquetquery/iters_test.go @@ -55,22 +55,43 @@ func TestTruncateRowNumber(t *testing.T) { require.Equal(t, newR, oldR) } +} - // Test with d > MaxDefinitionLevel - rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} - d := MaxDefinitionLevel + 1 - newR := TruncateRowNumber(d, rn) - oldR := truncateRowNumberSlow(d, rn) +func TestInvalidDefinitionLevel(t *testing.T) { + t.Run("TruncateRowNumber -1", func(t *testing.T) { + assertPanic(t, func() { + rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} + d := -1 + TruncateRowNumber(d, rn) + }) + }) - require.Equal(t, newR, oldR) + t.Run("TruncateRowNumber Max+1", func(t *testing.T) { + assertPanic(t, func() { + rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} + d := MaxDefinitionLevel + 1 + TruncateRowNumber(d, rn) + }) - // Test with d < 0 - rn = RowNumber{1, 2, 3, 4, 5, 6, 7, 8} - d = -1 - newR = TruncateRowNumber(d, rn) - oldR = truncateRowNumberSlow(d, rn) + }) - require.Equal(t, newR, oldR) + t.Run("Next -1", func(t *testing.T) { + assertPanic(t, func() { + rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} + r := 0 + d := -1 + rn.Next(r, d) + }) + }) + + t.Run("Next Max+1", func(t *testing.T) { + assertPanic(t, func() { + rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} + r := 0 + d := MaxDefinitionLevel + 1 + rn.Next(r, d) + }) + }) } func TestRowNumber(t *testing.T) { @@ -398,3 +419,12 @@ func BenchmarkEqualRowNumber(b *testing.B) { }) } } + +func assertPanic(t *testing.T, f func()) { + defer func() { + if r := recover(); r == nil { + t.Errorf("no panic") + } + }() + f() +} From 7158af9d9ef147aa896078261a442b4809e5245b Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Wed, 26 Jun 2024 20:03:15 -0500 Subject: [PATCH 17/22] lint --- pkg/parquetquery/iters_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/parquetquery/iters_test.go b/pkg/parquetquery/iters_test.go index 562199e6ef5..d36e1f0c194 100644 --- a/pkg/parquetquery/iters_test.go +++ b/pkg/parquetquery/iters_test.go @@ -65,16 +65,13 @@ func TestInvalidDefinitionLevel(t *testing.T) { TruncateRowNumber(d, rn) }) }) - t.Run("TruncateRowNumber Max+1", func(t *testing.T) { assertPanic(t, func() { rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} d := MaxDefinitionLevel + 1 TruncateRowNumber(d, rn) }) - }) - t.Run("Next -1", func(t *testing.T) { assertPanic(t, func() { rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} @@ -83,7 +80,6 @@ func TestInvalidDefinitionLevel(t *testing.T) { rn.Next(r, d) }) }) - t.Run("Next Max+1", func(t *testing.T) { assertPanic(t, func() { rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} From f28f4fe3884b7a78deee672a9597d3cfbf6bd227 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Wed, 26 Jun 2024 20:31:06 -0500 Subject: [PATCH 18/22] thank you, next() --- pkg/parquetquery/iters.go | 31 +++++++++++++++++++++++-------- pkg/parquetquery/iters_test.go | 16 +++++++++------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/pkg/parquetquery/iters.go b/pkg/parquetquery/iters.go index c70dd68f84e..f628fb68c14 100644 --- a/pkg/parquetquery/iters.go +++ b/pkg/parquetquery/iters.go @@ -114,13 +114,10 @@ func TruncateRowNumber(definitionLevelToKeep int, t RowNumber) RowNumber { return RowNumber{t[0], t[1], t[2], t[3], t[4], t[5], t[6], -1} case 7: return RowNumber{t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]} - } - - if definitionLevelToKeep > MaxDefinitionLevel || definitionLevelToKeep < 0 { + default: level.Error(log.Logger).Log("msg", "definition level out of bound: should be [0:7] but got %d", definitionLevelToKeep) panic("invalid definition level") } - return EmptyRowNumber() } func (t *RowNumber) Valid() bool { @@ -213,6 +210,8 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[5] = 0 t[6] = 0 t[7] = 0 + default: + panicWhenInvalidDefinitionLevel(definitionLevel) } case 1: switch definitionLevel { @@ -273,6 +272,8 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[5] = 0 t[6] = 0 t[7] = 0 + default: + panicWhenInvalidDefinitionLevel(definitionLevel) } case 2: switch definitionLevel { @@ -327,6 +328,8 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[5] = 0 t[6] = 0 t[7] = 0 + default: + panicWhenInvalidDefinitionLevel(definitionLevel) } case 3: switch definitionLevel { @@ -376,6 +379,8 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[5] = 0 t[6] = 0 t[7] = 0 + default: + panicWhenInvalidDefinitionLevel(definitionLevel) } case 4: switch definitionLevel { @@ -421,6 +426,8 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[5] = 0 t[6] = 0 t[7] = 0 + default: + panicWhenInvalidDefinitionLevel(definitionLevel) } case 5: switch definitionLevel { @@ -463,6 +470,8 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { case 7: t[6] = 0 t[7] = 0 + default: + panicWhenInvalidDefinitionLevel(definitionLevel) } case 6: switch definitionLevel { @@ -503,6 +512,8 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[7] = -1 case 7: t[7] = 0 + default: + panicWhenInvalidDefinitionLevel(definitionLevel) } case 7: switch definitionLevel { @@ -541,12 +552,11 @@ func (t *RowNumber) Next(repetitionLevel, definitionLevel int) { t[7] = -1 case 6: t[7] = -1 + case 7: + default: + panicWhenInvalidDefinitionLevel(definitionLevel) } } - if definitionLevel > MaxDefinitionLevel || definitionLevel < 0 { - level.Error(log.Logger).Log("msg", "definition level out of bound: should be [0:7] but got %d", definitionLevel) - panic("invalid definition level") - } } // nextSlow is the original implementation of next. it is kept to test against @@ -2193,6 +2203,11 @@ func (a *KeyValueGroupPredicate) KeepGroup(group *IteratorResult) bool { return true } +func panicWhenInvalidDefinitionLevel(definitionLevel int) { + level.Error(log.Logger).Log("msg", "definition level out of bound: should be [0:7] but got %d", definitionLevel) + panic("invalid definition level") +} + /*func printGroup(g *iteratorResult) { fmt.Println("---group---") for _, e := range g.entries { diff --git a/pkg/parquetquery/iters_test.go b/pkg/parquetquery/iters_test.go index d36e1f0c194..71f0c0473d9 100644 --- a/pkg/parquetquery/iters_test.go +++ b/pkg/parquetquery/iters_test.go @@ -33,8 +33,8 @@ func TestNext(t *testing.T) { rn2 := RowNumber{0, 0, 0, 0, 0, 0, 0, 0} for i := 0; i < 1000; i++ { - r := rand.Intn(MaxDefinitionLevel + 1) - d := rand.Intn(MaxDefinitionLevel + 1) + r := rand.Intn(MaxDefinitionLevel) + d := rand.Intn(MaxDefinitionLevel) rn1.Next(r, d) rn2.nextSlow(r, d) @@ -46,18 +46,17 @@ func TestNext(t *testing.T) { // TestTruncate compares the unrolled TruncateRowNumber() with the original truncateRowNumberSlow() to // prevent drift func TestTruncateRowNumber(t *testing.T) { - for i := 0; i < 1000; i++ { + for i := 0; i <= MaxDefinitionLevel; i++ { rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} - d := rand.Intn(MaxDefinitionLevel + 1) - newR := TruncateRowNumber(d, rn) - oldR := truncateRowNumberSlow(d, rn) + newR := TruncateRowNumber(i, rn) + oldR := truncateRowNumberSlow(i, rn) require.Equal(t, newR, oldR) } } -func TestInvalidDefinitionLevel(t *testing.T) { +func TestInvalidDefinitionLevelTruncate(t *testing.T) { t.Run("TruncateRowNumber -1", func(t *testing.T) { assertPanic(t, func() { rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} @@ -72,6 +71,9 @@ func TestInvalidDefinitionLevel(t *testing.T) { TruncateRowNumber(d, rn) }) }) +} + +func TestInvalidDefinitionLevelNext(t *testing.T) { t.Run("Next -1", func(t *testing.T) { assertPanic(t, func() { rn := RowNumber{1, 2, 3, 4, 5, 6, 7, 8} From f2f8fa03c312345604e998c7107ab44368599019 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Thu, 27 Jun 2024 15:47:51 -0500 Subject: [PATCH 19/22] update test --- pkg/parquetquery/iters.go | 9 ++------- tempodb/tempodb_search_test.go | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/pkg/parquetquery/iters.go b/pkg/parquetquery/iters.go index f628fb68c14..b3753976b84 100644 --- a/pkg/parquetquery/iters.go +++ b/pkg/parquetquery/iters.go @@ -10,11 +10,8 @@ import ( "sync" "sync/atomic" - "github.com/go-kit/log/level" - "github.com/grafana/tempo/pkg/parquetquery/intern" "github.com/grafana/tempo/pkg/util" - "github.com/grafana/tempo/pkg/util/log" "github.com/opentracing/opentracing-go" pq "github.com/parquet-go/parquet-go" ) @@ -115,8 +112,7 @@ func TruncateRowNumber(definitionLevelToKeep int, t RowNumber) RowNumber { case 7: return RowNumber{t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]} default: - level.Error(log.Logger).Log("msg", "definition level out of bound: should be [0:7] but got %d", definitionLevelToKeep) - panic("invalid definition level") + panic(fmt.Sprintf("definition level out of bound: should be [0:7] but got %d", definitionLevelToKeep)) } } @@ -2204,8 +2200,7 @@ func (a *KeyValueGroupPredicate) KeepGroup(group *IteratorResult) bool { } func panicWhenInvalidDefinitionLevel(definitionLevel int) { - level.Error(log.Logger).Log("msg", "definition level out of bound: should be [0:7] but got %d", definitionLevel) - panic("invalid definition level") + panic(fmt.Sprintf("definition level out of bound: should be [0:7] but got %d %d", definitionLevel)) } /*func printGroup(g *iteratorResult) { diff --git a/tempodb/tempodb_search_test.go b/tempodb/tempodb_search_test.go index 4e657c7b039..366c8cbfa14 100644 --- a/tempodb/tempodb_search_test.go +++ b/tempodb/tempodb_search_test.go @@ -34,6 +34,7 @@ import ( "github.com/grafana/tempo/tempodb/encoding/common" v2 "github.com/grafana/tempo/tempodb/encoding/v2" "github.com/grafana/tempo/tempodb/encoding/vparquet2" + "github.com/grafana/tempo/tempodb/encoding/vparquet4" "github.com/grafana/tempo/tempodb/wal" ) @@ -1529,6 +1530,13 @@ func runCompleteBlockSearchTest(t *testing.T, blockVersion string, runners ...ru rw := r.(*readerWriter) wantID, wantTr, start, end, wantMeta, searchesThatMatch, searchesThatDontMatch := searchTestSuite() + if blockVersion == vparquet4.VersionString { + searchesThatMatch = append(searchesThatMatch, &tempopb.SearchRequest{ + Query: "{ event.exception.message = `random error` }", + }, &tempopb.SearchRequest{ + Query: "{ event:name = `event name` }", + }) + } // Write to wal wal := w.WAL() @@ -1706,6 +1714,15 @@ func searchTestSuite() ( stringKV("span-dedicated.01", "span-1a"), stringKV("span-dedicated.02", "span-2a"), }, + Events: []*v1.Span_Event{ + { + TimeUnixNano: uint64(1000 * time.Second) + 100, + Name: "event name", + Attributes: []*v1_common.KeyValue{ + stringKV("exception.message", "random error"), + }, + }, + }, }, }, }, From 5726599b08f75efb8d86253001b50b8fff0c43bc Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Thu, 27 Jun 2024 16:49:52 -0500 Subject: [PATCH 20/22] fix test and docs --- docs/sources/tempo/traceql/_index.md | 4 +- tempodb/tempodb_search_test.go | 138 ++++++++++++++++++++++++--- 2 files changed, 129 insertions(+), 13 deletions(-) diff --git a/docs/sources/tempo/traceql/_index.md b/docs/sources/tempo/traceql/_index.md index 753c465d8b3..76899cfa5a0 100644 --- a/docs/sources/tempo/traceql/_index.md +++ b/docs/sources/tempo/traceql/_index.md @@ -128,9 +128,9 @@ Find any database connection string that goes to a Postgres or MySQL database: { span.db.system =~ "postgresql|mysql" } ``` -You can query for an exception in your span event +You can query for an exception in your span event: ``` -{ event.exception.message =~ "something went wrong" } +{ event.exception.message =~ ".*something went wrong.*" } ``` ### Unscoped attribute fields diff --git a/tempodb/tempodb_search_test.go b/tempodb/tempodb_search_test.go index 366c8cbfa14..c6a31187212 100644 --- a/tempodb/tempodb_search_test.go +++ b/tempodb/tempodb_search_test.go @@ -57,6 +57,11 @@ func TestSearchCompleteBlock(t *testing.T) { autoComplete, ) }) + if (vers == vparquet4.VersionString){ + t.Run("event query", func(t *testing.T) { + runEventSearchTest(t, vers) + }) + } } } @@ -1529,14 +1534,8 @@ func runCompleteBlockSearchTest(t *testing.T, blockVersion string, runners ...ru r.EnablePolling(ctx, &mockJobSharder{}) rw := r.(*readerWriter) - wantID, wantTr, start, end, wantMeta, searchesThatMatch, searchesThatDontMatch := searchTestSuite() - if blockVersion == vparquet4.VersionString { - searchesThatMatch = append(searchesThatMatch, &tempopb.SearchRequest{ - Query: "{ event.exception.message = `random error` }", - }, &tempopb.SearchRequest{ - Query: "{ event:name = `event name` }", - }) - } + wantID, wantTr, start, end, wantMeta := makeExpectedTrace() + searchesThatMatch, searchesThatDontMatch := searchTestSuite() // Write to wal wal := w.WAL() @@ -1579,6 +1578,118 @@ func runCompleteBlockSearchTest(t *testing.T, blockVersion string, runners ...ru // todo: do some compaction and then call runner again } +func runEventSearchTest(t *testing.T, blockVersion string) { + // only run this test for vparquet4 + if blockVersion != vparquet4.VersionString { + return + } + + tempDir := t.TempDir() + + r, w, c, err := New(&Config{ + Backend: backend.Local, + Local: &local.Config{ + Path: path.Join(tempDir, "traces"), + }, + Block: &common.BlockConfig{ + IndexDownsampleBytes: 17, + BloomFP: .01, + BloomShardSizeBytes: 100_000, + Version: blockVersion, + IndexPageSizeBytes: 1000, + RowGroupSizeBytes: 10000, + }, + WAL: &wal.Config{ + Filepath: path.Join(tempDir, "wal"), + IngestionSlack: time.Since(time.Time{}), + }, + Search: &SearchConfig{ + ChunkSizeBytes: 1_000_000, + ReadBufferCount: 8, ReadBufferSizeBytes: 4 * 1024 * 1024, + }, + BlocklistPoll: 0, + }, nil, log.NewNopLogger()) + require.NoError(t, err) + + err = c.EnableCompaction(context.Background(), &CompactorConfig{ + ChunkSizeBytes: 10, + MaxCompactionRange: time.Hour, + BlockRetention: 0, + CompactedBlockRetention: 0, + }, &mockSharder{}, &mockOverrides{}) + require.NoError(t, err) + + ctx := context.Background() + r.EnablePolling(ctx, &mockJobSharder{}) + rw := r.(*readerWriter) + + wantID, wantTr, start, end, wantMeta := makeExpectedTrace() + + searchesThatMatch := []*tempopb.SearchRequest{ + { + Query: "{ event.exception.message = `random error` }", + }, + { + Query: "{ event:name = `event name` }", + }, + } + + // Write to wal + wal := w.WAL() + + meta := &backend.BlockMeta{BlockID: uuid.New(), TenantID: testTenantID} + head, err := wal.NewBlock(meta, model.CurrentEncoding) + require.NoError(t, err) + dec := model.MustNewSegmentDecoder(model.CurrentEncoding) + + totalTraces := 50 + wantTrIdx := rand.Intn(totalTraces) + for i := 0; i < totalTraces; i++ { + var tr *tempopb.Trace + var id []byte + if i == wantTrIdx { + tr = wantTr + id = wantID + } else { + id = test.ValidTraceID(nil) + tr = test.MakeTrace(10, id) + } + b1, err := dec.PrepareForWrite(tr, start, end) + require.NoError(t, err) + + b2, err := dec.ToObject([][]byte{b1}) + require.NoError(t, err) + err = head.Append(id, b2, start, end) + require.NoError(t, err) + } + + // Complete block + block, err := w.CompleteBlock(context.Background(), head) + require.NoError(t, err) + blockMeta := block.BlockMeta() + + e := traceql.NewEngine() + + for _, req := range searchesThatMatch { + fetcher := traceql.NewSpansetFetcherWrapper(func(ctx context.Context, req traceql.FetchSpansRequest) (traceql.FetchSpansResponse, error) { + return rw.Fetch(ctx, blockMeta, req, common.DefaultSearchOptions()) + }) + + res, err := e.ExecuteSearch(ctx, req, fetcher) + if errors.Is(err, common.ErrUnsupported) { + continue + } + + require.NoError(t, err, "search request: %+v", req) + actual := actualForExpectedMeta(wantMeta, res) + require.NotNil(t, actual, "search request: %v", req) + actual.SpanSet = nil // todo: add the matching spansets to wantmeta + actual.SpanSets = nil + actual.ServiceStats = nil + require.Equal(t, wantMeta, actual, "search request: %v", req) + } +} + func stringKV(k, v string) *v1_common.KeyValue { return &v1_common.KeyValue{ Key: k, @@ -1659,13 +1770,11 @@ func addTraceQL(req *tempopb.SearchRequest) { // - expected - The exact search result that should be returned for every matching request // - searchesThatMatch - List of search requests that are expected to match the trace // - searchesThatDontMatch - List of requests that don't match the trace -func searchTestSuite() ( +func makeExpectedTrace() ( id []byte, tr *tempopb.Trace, start, end uint32, expected *tempopb.TraceSearchMetadata, - searchesThatMatch []*tempopb.SearchRequest, - searchesThatDontMatch []*tempopb.SearchRequest, ) { id = test.ValidTraceID(nil) @@ -1819,6 +1928,13 @@ func searchTestSuite() ( RootServiceName: "RootService", RootTraceName: "RootSpan", } + return +} + +func searchTestSuite() ( + searchesThatMatch []*tempopb.SearchRequest, + searchesThatDontMatch []*tempopb.SearchRequest, +) { // Matches searchesThatMatch = []*tempopb.SearchRequest{ From da8405b5ac00c2a846ac34f01629f8af601ed258 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Thu, 27 Jun 2024 16:51:29 -0500 Subject: [PATCH 21/22] lint --- tempodb/tempodb_search_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tempodb/tempodb_search_test.go b/tempodb/tempodb_search_test.go index c6a31187212..d3e930fd0b7 100644 --- a/tempodb/tempodb_search_test.go +++ b/tempodb/tempodb_search_test.go @@ -57,7 +57,7 @@ func TestSearchCompleteBlock(t *testing.T) { autoComplete, ) }) - if (vers == vparquet4.VersionString){ + if vers == vparquet4.VersionString { t.Run("event query", func(t *testing.T) { runEventSearchTest(t, vers) }) @@ -1534,7 +1534,7 @@ func runCompleteBlockSearchTest(t *testing.T, blockVersion string, runners ...ru r.EnablePolling(ctx, &mockJobSharder{}) rw := r.(*readerWriter) - wantID, wantTr, start, end, wantMeta := makeExpectedTrace() + wantID, wantTr, start, end, wantMeta := makeExpectedTrace() searchesThatMatch, searchesThatDontMatch := searchTestSuite() // Write to wal @@ -1825,7 +1825,7 @@ func makeExpectedTrace() ( }, Events: []*v1.Span_Event{ { - TimeUnixNano: uint64(1000 * time.Second) + 100, + TimeUnixNano: uint64(1000*time.Second) + 100, Name: "event name", Attributes: []*v1_common.KeyValue{ stringKV("exception.message", "random error"), From 5b8572bd722740ae0355d5a6e8789ddc932f0c09 Mon Sep 17 00:00:00 2001 From: Jennie Pham Date: Thu, 27 Jun 2024 17:00:34 -0500 Subject: [PATCH 22/22] i love linting --- pkg/parquetquery/iters.go | 2 +- tempodb/tempodb_search_test.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/parquetquery/iters.go b/pkg/parquetquery/iters.go index b3753976b84..bcd62a380eb 100644 --- a/pkg/parquetquery/iters.go +++ b/pkg/parquetquery/iters.go @@ -2200,7 +2200,7 @@ func (a *KeyValueGroupPredicate) KeepGroup(group *IteratorResult) bool { } func panicWhenInvalidDefinitionLevel(definitionLevel int) { - panic(fmt.Sprintf("definition level out of bound: should be [0:7] but got %d %d", definitionLevel)) + panic(fmt.Sprintf("definition level out of bound: should be [0:7] but got %d", definitionLevel)) } /*func printGroup(g *iteratorResult) { diff --git a/tempodb/tempodb_search_test.go b/tempodb/tempodb_search_test.go index d3e930fd0b7..1e4acc33955 100644 --- a/tempodb/tempodb_search_test.go +++ b/tempodb/tempodb_search_test.go @@ -1935,7 +1935,6 @@ func searchTestSuite() ( searchesThatMatch []*tempopb.SearchRequest, searchesThatDontMatch []*tempopb.SearchRequest, ) { - // Matches searchesThatMatch = []*tempopb.SearchRequest{ {