Skip to content

Commit

Permalink
[TraceQL] Add Support for Kind (grafana#2217)
Browse files Browse the repository at this point in the history
* kind added to the language

Signed-off-by: Joe Elliott <[email protected]>

* added to fetch layer

Signed-off-by: Joe Elliott <[email protected]>

* todo

Signed-off-by: Joe Elliott <[email protected]>

* todos

Signed-off-by: Joe Elliott <[email protected]>

* combined status, kind and int preds

Signed-off-by: Joe Elliott <[email protected]>

* todos

Signed-off-by: Joe Elliott <[email protected]>

* changelog

Signed-off-by: Joe Elliott <[email protected]>

* Added kind to tempodb search tests. Fixed false duration condition

Signed-off-by: Joe Elliott <[email protected]>

* improve docs

Signed-off-by: Joe Elliott <[email protected]>

---------

Signed-off-by: Joe Elliott <[email protected]>
  • Loading branch information
joe-elliott authored Mar 20, 2023
1 parent 970588d commit 70272b8
Show file tree
Hide file tree
Showing 24 changed files with 611 additions and 394 deletions.
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
docs/
example/
integration/
operations/
opentelemetry-proto/
tools/
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* [FEATURE] Add support for Azure Workload Identity authentication [#2195](https://github.com/grafana/tempo/pull/2195) (@LambArchie)
* [FEATURE] Add flag to check configuration [#2131](https://github.com/grafana/tempo/issues/2131) (@robertscherbarth @agrib-01)
* [FEATURE] Add flag to optionally enable all available Go runtime metrics [#2005](https://github.com/grafana/tempo/pull/2005) (@andreasgerstmayr)
* [FEATURE] Add support for span `kind` to TraceQL [#2217](https://github.com/grafana/tempo/pull/2217) (@joe-elliott)
* [CHANGE] Add support for s3 session token in static config [#2093](https://github.com/grafana/tempo/pull/2093) (@farodin91)
* [CHANGE] **Breaking Change** Remove support for search on v2 blocks. [#2159](https://github.com/grafana/tempo/pull/2062) (@joe-elliott)
Removed config options:
Expand Down
12 changes: 6 additions & 6 deletions docs/sources/tempo/traceql/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ Intrinsic fields are fundamental to spans. These fields can be referenced when s

The following table shows the current intrinsic fields:


| **Operation** | **Type** | **Definition** | **Example** |
|---------------|----------|---------------------------------------|------------------------|
| status | string | status values are error, ok, or unset | { status = ok } |
| duration | duration | end - start time of the span | { duration > 100ms } |
| name | string | operation or span name | { name = "HTTP POST" } |
| **Field** | **Type** | **Definition** | **Example** |
|---------------|-------------|-----------------------------------------------------------------|------------------------|
| status | status enum | status: error, ok, or unset | { status = ok } |
| duration | duration | end - start time of the span | { duration > 100ms } |
| name | string | operation or span name | { name = "HTTP POST" } |
| kind | kind enum | kind: server, client, producer, consumer, internal, unspecified | { kind = server } |

### Attribute fields

Expand Down
19 changes: 19 additions & 0 deletions pkg/model/trace/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,22 @@ func StatusToString(s v1trace.Status_StatusCode) string {
}
return status
}

func KindToString(k v1trace.Span_SpanKind) string {
var kind string
switch k {
case v1trace.Span_SPAN_KIND_UNSPECIFIED:
kind = "unspecified"
case v1trace.Span_SPAN_KIND_INTERNAL:
kind = "internal"
case v1trace.Span_SPAN_KIND_SERVER:
kind = "server"
case v1trace.Span_SPAN_KIND_CLIENT:
kind = "client"
case v1trace.Span_SPAN_KIND_PRODUCER:
kind = "producer"
case v1trace.Span_SPAN_KIND_CONSUMER:
kind = "consumer"
}
return kind
}
9 changes: 9 additions & 0 deletions pkg/search/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ func GetVirtualTagValuesV2(tagName string) []tempopb.TagValue {
{Type: "keyword", Value: traceql.StatusError.String()},
{Type: "keyword", Value: traceql.StatusUnset.String()},
}
case traceql.IntrinsicKind.String():
return []tempopb.TagValue{
{Type: "keyword", Value: traceql.KindClient.String()},
{Type: "keyword", Value: traceql.KindServer.String()},
{Type: "keyword", Value: traceql.KindProducer.String()},
{Type: "keyword", Value: traceql.KindConsumer.String()},
{Type: "keyword", Value: traceql.KindInternal.String()},
{Type: "keyword", Value: traceql.KindUnspecified.String()},
}
}

return nil
Expand Down
12 changes: 11 additions & 1 deletion pkg/traceql/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,8 @@ type Static struct {
S string
B bool
D time.Duration
Status Status
Status Status // todo: can we just use the N member for status and kind?
Kind Kind
}

// nolint: revive
Expand Down Expand Up @@ -503,6 +504,13 @@ func NewStaticStatus(s Status) Static {
}
}

func NewStaticKind(k Kind) Static {
return Static{
Type: TypeKind,
Kind: k,
}
}

// **********************
// Attributes
// **********************
Expand Down Expand Up @@ -537,6 +545,8 @@ func (a Attribute) impliedType() StaticType {
return TypeString
case IntrinsicStatus:
return TypeStatus
case IntrinsicKind:
return TypeKind
case IntrinsicParent:
return TypeNil
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/traceql/ast_stringer.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ func (n Static) EncodeToString(quotes bool) string {
return n.D.String()
case TypeStatus:
return n.Status.String()
case TypeKind:
return n.Kind.String()
}

return fmt.Sprintf("static(%d)", n.Type)
Expand Down
2 changes: 2 additions & 0 deletions pkg/traceql/ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func TestStatic_Equals(t *testing.T) {
{NewStaticBool(true), NewStaticBool(true)},
{NewStaticDuration(1 * time.Second), NewStaticDuration(1000 * time.Millisecond)},
{NewStaticStatus(StatusOk), NewStaticStatus(StatusOk)},
{NewStaticKind(KindClient), NewStaticKind(KindClient)},
{NewStaticDuration(0), NewStaticInt(0)},
// Status and int comparison
{NewStaticStatus(StatusError), NewStaticInt(0)},
Expand All @@ -32,6 +33,7 @@ func TestStatic_Equals(t *testing.T) {
{NewStaticInt(1), NewStaticInt(2)},
{NewStaticBool(true), NewStaticInt(1)},
{NewStaticString("foo"), NewStaticString("bar")},
{NewStaticKind(KindClient), NewStaticKind(KindConsumer)},
{NewStaticStatus(StatusError), NewStaticStatus(StatusOk)},
{NewStaticStatus(StatusOk), NewStaticInt(0)},
{NewStaticStatus(StatusError), NewStaticFloat(0)},
Expand Down
6 changes: 6 additions & 0 deletions pkg/traceql/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,12 @@ func (s Static) asAnyValue() *common_v1.AnyValue {
StringValue: "nil",
},
}
case TypeKind:
return &common_v1.AnyValue{
Value: &common_v1.AnyValue_StringValue{
StringValue: s.Kind.String(),
},
}
}

return &common_v1.AnyValue{
Expand Down
10 changes: 10 additions & 0 deletions pkg/traceql/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ func TestEngine_asTraceSearchMetadata(t *testing.T) {
attributes: map[Attribute]Static{
NewIntrinsic(IntrinsicName): NewStaticString("HTTP GET"),
NewIntrinsic(IntrinsicStatus): NewStaticStatus(StatusOk),
NewIntrinsic(IntrinsicKind): NewStaticKind(KindClient),
NewAttribute("cluster"): NewStaticString("prod"),
NewAttribute("count"): NewStaticInt(5),
NewAttribute("count_but_float"): NewStaticFloat(5.0),
Expand Down Expand Up @@ -225,6 +226,14 @@ func TestEngine_asTraceSearchMetadata(t *testing.T) {
},
},
},
{
Key: "kind",
Value: &v1.AnyValue{
Value: &v1.AnyValue_StringValue{
StringValue: KindClient.String(),
},
},
},
{
Key: "status",
Value: &v1.AnyValue{
Expand Down Expand Up @@ -319,6 +328,7 @@ func TestStatic_AsAnyValue(t *testing.T) {
{NewStaticBool(true), &v1.AnyValue{Value: &v1.AnyValue_BoolValue{BoolValue: true}}},
{NewStaticDuration(5 * time.Second), &v1.AnyValue{Value: &v1.AnyValue_StringValue{StringValue: "5s"}}},
{NewStaticStatus(StatusOk), &v1.AnyValue{Value: &v1.AnyValue_StringValue{StringValue: "ok"}}},
{NewStaticKind(KindInternal), &v1.AnyValue{Value: &v1.AnyValue_StringValue{StringValue: "internal"}}},
{NewStaticNil(), &v1.AnyValue{Value: &v1.AnyValue_StringValue{StringValue: "nil"}}},
}
for _, tc := range tt {
Expand Down
5 changes: 5 additions & 0 deletions pkg/traceql/enum_attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const (
IntrinsicChildCount
IntrinsicName
IntrinsicStatus
IntrinsicKind
IntrinsicParent
)

Expand All @@ -44,6 +45,8 @@ func (i Intrinsic) String() string {
return "name"
case IntrinsicStatus:
return "status"
case IntrinsicKind:
return "kind"
case IntrinsicChildCount:
return "childCount"
case IntrinsicParent:
Expand All @@ -62,6 +65,8 @@ func intrinsicFromString(s string) Intrinsic {
return IntrinsicName
case "status":
return IntrinsicStatus
case "kind":
return IntrinsicKind
case "childCount":
return IntrinsicChildCount
case "parent":
Expand Down
2 changes: 2 additions & 0 deletions pkg/traceql/enum_operators.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ func binaryTypeValid(op Operator, t StaticType) bool {
fallthrough
case TypeStatus:
return op == OpEqual || op == OpNotEqual
case TypeKind:
return op == OpEqual || op == OpNotEqual
}

return false
Expand Down
5 changes: 5 additions & 0 deletions pkg/traceql/enum_operators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func TestOperatorBinaryTypesValid(t *testing.T) {
{OpMod, TypeStatus, false},
{OpMult, TypeNil, false},
{OpPower, TypeBoolean, false},
{OpMult, TypeKind, false},
// equality
{OpEqual, TypeDuration, true},
{OpNotEqual, TypeStatus, true},
Expand All @@ -71,6 +72,8 @@ func TestOperatorBinaryTypesValid(t *testing.T) {
{OpNotEqual, TypeAttribute, true},
{OpEqual, TypeBoolean, true},
{OpNotEqual, TypeFloat, true},
{OpEqual, TypeKind, true},
{OpNotEqual, TypeKind, true},

{OpEqual, TypeSpanset, false},
// range comparison
Expand All @@ -80,6 +83,7 @@ func TestOperatorBinaryTypesValid(t *testing.T) {
{OpLessEqual, TypeDuration, true},

{OpGreater, TypeStatus, false},
{OpLessEqual, TypeKind, false},
{OpGreaterEqual, TypeNil, false},
{OpLess, TypeString, false},
{OpLessEqual, TypeBoolean, false},
Expand All @@ -88,6 +92,7 @@ func TestOperatorBinaryTypesValid(t *testing.T) {
{OpNotRegex, TypeAttribute, true},
{OpRegex, TypeString, true},

{OpRegex, TypeKind, false},
{OpRegex, TypeInt, false},
{OpNotRegex, TypeInt, false},
// boolean
Expand Down
31 changes: 31 additions & 0 deletions pkg/traceql/enum_statics.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
TypeBoolean
TypeDuration
TypeStatus
TypeKind
)

// isMatchingOperand returns whether two types can be combined with a binary operator. the kind of operator is
Expand Down Expand Up @@ -60,3 +61,33 @@ func (s Status) String() string {

return fmt.Sprintf("status(%d)", s)
}

type Kind int

const (
KindUnspecified Kind = iota
KindInternal
KindClient
KindServer
KindProducer
KindConsumer
)

func (k Kind) String() string {
switch k {
case KindUnspecified:
return "unspecified"
case KindInternal:
return "internal"
case KindClient:
return "client"
case KindServer:
return "server"
case KindProducer:
return "producer"
case KindConsumer:
return "consumer"
}

return fmt.Sprintf("kind(%d)", k)
}
30 changes: 19 additions & 11 deletions pkg/traceql/expr.y
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ import (
%token <staticDuration> DURATION
%token <val> DOT OPEN_BRACE CLOSE_BRACE OPEN_PARENS CLOSE_PARENS
NIL TRUE FALSE STATUS_ERROR STATUS_OK STATUS_UNSET
IDURATION CHILDCOUNT NAME STATUS PARENT
KIND_UNSPECIFIED KIND_INTERNAL KIND_SERVER KIND_CLIENT KIND_PRODUCER KIND_CONSUMER
IDURATION CHILDCOUNT NAME STATUS PARENT KIND
PARENT_DOT RESOURCE_DOT SPAN_DOT
COUNT AVG MAX MIN SUM
BY COALESCE
Expand Down Expand Up @@ -236,23 +237,30 @@ fieldExpression:
// Statics
// **********************
static:
STRING { $$ = NewStaticString($1) }
| INTEGER { $$ = NewStaticInt($1) }
| FLOAT { $$ = NewStaticFloat($1) }
| TRUE { $$ = NewStaticBool(true) }
| FALSE { $$ = NewStaticBool(false) }
| NIL { $$ = NewStaticNil() }
| DURATION { $$ = NewStaticDuration($1) }
| STATUS_OK { $$ = NewStaticStatus(StatusOk) }
| STATUS_ERROR { $$ = NewStaticStatus(StatusError) }
| STATUS_UNSET { $$ = NewStaticStatus(StatusUnset) }
STRING { $$ = NewStaticString($1) }
| INTEGER { $$ = NewStaticInt($1) }
| FLOAT { $$ = NewStaticFloat($1) }
| TRUE { $$ = NewStaticBool(true) }
| FALSE { $$ = NewStaticBool(false) }
| NIL { $$ = NewStaticNil() }
| DURATION { $$ = NewStaticDuration($1) }
| STATUS_OK { $$ = NewStaticStatus(StatusOk) }
| STATUS_ERROR { $$ = NewStaticStatus(StatusError) }
| STATUS_UNSET { $$ = NewStaticStatus(StatusUnset) }
| KIND_UNSPECIFIED { $$ = NewStaticKind(KindUnspecified)}
| KIND_INTERNAL { $$ = NewStaticKind(KindInternal) }
| KIND_SERVER { $$ = NewStaticKind(KindServer) }
| KIND_CLIENT { $$ = NewStaticKind(KindClient) }
| KIND_PRODUCER { $$ = NewStaticKind(KindProducer) }
| KIND_CONSUMER { $$ = NewStaticKind(KindConsumer) }
;

intrinsicField:
IDURATION { $$ = NewIntrinsic(IntrinsicDuration) }
| CHILDCOUNT { $$ = NewIntrinsic(IntrinsicChildCount) }
| NAME { $$ = NewIntrinsic(IntrinsicName) }
| STATUS { $$ = NewIntrinsic(IntrinsicStatus) }
| KIND { $$ = NewIntrinsic(IntrinsicKind) }
| PARENT { $$ = NewIntrinsic(IntrinsicParent) }
;

Expand Down
Loading

0 comments on commit 70272b8

Please sign in to comment.