From 65b50b67c4c3ce4026c5cfbf0674ece942884b8f Mon Sep 17 00:00:00 2001 From: Andre Pereira Date: Fri, 15 Nov 2024 09:35:41 +0000 Subject: [PATCH] Tempo: Fix trace kvlist and array transformations (#96388) * Fix kvlist and array transformations * Log transformation errors --- pkg/tsdb/tempo/testData/trace.json | 36 ++++++++++++ pkg/tsdb/tempo/trace_transform.go | 78 ++++++++++++++++++++++---- pkg/tsdb/tempo/trace_transform_test.go | 2 +- 3 files changed, 103 insertions(+), 13 deletions(-) diff --git a/pkg/tsdb/tempo/testData/trace.json b/pkg/tsdb/tempo/testData/trace.json index a0533a5cfd2..81c6f06c46f 100644 --- a/pkg/tsdb/tempo/testData/trace.json +++ b/pkg/tsdb/tempo/testData/trace.json @@ -1342,6 +1342,42 @@ "value": { "string_value": "net/http" } + }, + { + "key": "arrayAttribute", + "value": { + "array_value": { + "values": [ + { + "string_value": "value1" + }, + { + "string_value": "value2" + } + ] + } + } + }, + { + "key": "kvlistAttribute", + "value": { + "kvlist_value": { + "values": [ + { + "key": "key1", + "value": { + "string_value": "value1" + } + }, + { + "key": "key2", + "value": { + "string_value": "value2" + } + } + ] + } + } } ], "status": {} diff --git a/pkg/tsdb/tempo/trace_transform.go b/pkg/tsdb/tempo/trace_transform.go index 13b5e79fae7..047db53adf0 100644 --- a/pkg/tsdb/tempo/trace_transform.go +++ b/pkg/tsdb/tempo/trace_transform.go @@ -194,33 +194,79 @@ func resourceToProcess(resource *v1.Resource) (string, []*KeyValue) { if attribute.Key(attr.Key) == semconv.ServiceNameKey { serviceName = attr.GetValue().GetStringValue() } - tags = append(tags, &KeyValue{Key: attr.Key, Value: getAttributeVal(attr.Value)}) + val, err := getAttributeVal(attr.Value) + if err != nil { + logger.Debug("error transforming resource to process", "err", err) + } + tags = append(tags, &KeyValue{Key: attr.Key, Value: val}) } return serviceName, tags } -func getAttributeVal(attr *commonv11.AnyValue) any { +func getAttributeVal(attr *commonv11.AnyValue) (any, error) { switch attr.GetValue().(type) { case *commonv11.AnyValue_StringValue: - return attr.GetStringValue() + return attr.GetStringValue(), nil case *commonv11.AnyValue_IntValue: - return attr.GetIntValue() + return attr.GetIntValue(), nil case *commonv11.AnyValue_BoolValue: - return attr.GetBoolValue() + return attr.GetBoolValue(), nil case *commonv11.AnyValue_DoubleValue: - return attr.GetDoubleValue() - case *commonv11.AnyValue_KvlistValue, *commonv11.AnyValue_ArrayValue: - return attr.GetStringValue() + return attr.GetDoubleValue(), nil + case *commonv11.AnyValue_KvlistValue: + return kvListAsString(attr.GetKvlistValue()) + case *commonv11.AnyValue_ArrayValue: + return arrayAsString(attr.GetArrayValue()) default: - return nil + return attr.GetStringValue(), nil } } +func arrayAsString(list *commonv11.ArrayValue) (string, error) { + vals := make([]any, len(list.GetValues())) + + for i, val := range list.GetValues() { + v, err := getAttributeVal(val) + if err != nil { + return "", fmt.Errorf("failed to get attribute value: %w", err) + } + vals[i] = v + } + + res, err := json.Marshal(vals) + if err != nil { + return "", fmt.Errorf("failed to marshal array: %w", err) + } + return string(res), nil +} + +func kvListAsString(list *commonv11.KeyValueList) (string, error) { + vals := make(map[string]any, len(list.GetValues())) + + for _, val := range list.GetValues() { + v, err := getAttributeVal(val.GetValue()) + if err != nil { + return "", fmt.Errorf("failed to get attribute value: %w", err) + } + vals[val.GetKey()] = v + } + + res, err := json.Marshal(vals) + if err != nil { + return "", fmt.Errorf("failed to marshal kvlist: %w", err) + } + return string(res), nil +} + func getSpanTags(span *tracev11.Span) []*KeyValue { tags := make([]*KeyValue, len(span.Attributes)) for i, attr := range span.Attributes { - tags[i] = &KeyValue{Key: attr.Key, Value: getAttributeVal(attr.Value)} + val, err := getAttributeVal(attr.Value) + if err != nil { + logger.Debug("error transforming span tags", "err", err) + } + tags[i] = &KeyValue{Key: attr.Key, Value: val} } return tags } @@ -255,7 +301,11 @@ func spanEventsToLogs(events []*tracev11.Span_Event) []*TraceLog { event := events[i] fields := make([]*KeyValue, 0, len(event.Attributes)+1) for _, attr := range event.Attributes { - fields = append(fields, &KeyValue{Key: attr.Key, Value: getAttributeVal(attr.Value)}) + val, err := getAttributeVal(attr.Value) + if err != nil { + logger.Debug("error transforming span events to logs", "err", err) + } + fields = append(fields, &KeyValue{Key: attr.Key, Value: val}) } logs = append(logs, &TraceLog{ Timestamp: float64(event.TimeUnixNano) / 1_000_000, @@ -285,7 +335,11 @@ func spanLinksToReferences(links []*tracev11.Span_Link) []*TraceReference { tags := make([]*KeyValue, 0, len(link.Attributes)) for _, attr := range link.Attributes { - tags = append(tags, &KeyValue{Key: attr.Key, Value: getAttributeVal(attr.Value)}) + val, err := getAttributeVal(attr.Value) + if err != nil { + logger.Debug("error transforming span links to references", "err", err) + } + tags = append(tags, &KeyValue{Key: attr.Key, Value: val}) } references = append(references, &TraceReference{ diff --git a/pkg/tsdb/tempo/trace_transform_test.go b/pkg/tsdb/tempo/trace_transform_test.go index 8fd69f64ca8..64cee9584a8 100644 --- a/pkg/tsdb/tempo/trace_transform_test.go +++ b/pkg/tsdb/tempo/trace_transform_test.go @@ -45,7 +45,7 @@ func TestTraceToFrame(t *testing.T) { require.Equal(t, 1616072924070.497, root["startTime"]) require.Equal(t, 8.421, root["duration"]) require.Equal(t, json.RawMessage("null"), root["logs"]) - require.Equal(t, json.RawMessage("[{\"value\":\"const\",\"key\":\"sampler.type\"},{\"value\":true,\"key\":\"sampler.param\"},{\"value\":200,\"key\":\"http.status_code\"},{\"value\":\"GET\",\"key\":\"http.method\"},{\"value\":\"/loki/api/v1/query_range?direction=BACKWARD\\u0026limit=1000\\u0026query=%7Bcompose_project%3D%22devenv%22%7D%20%7C%3D%22trace_id%22\\u0026start=1616070921000000000\\u0026end=1616072722000000000\\u0026step=2\",\"key\":\"http.url\"},{\"value\":\"net/http\",\"key\":\"component\"}]"), root["tags"]) + require.Equal(t, json.RawMessage("[{\"value\":\"const\",\"key\":\"sampler.type\"},{\"value\":true,\"key\":\"sampler.param\"},{\"value\":200,\"key\":\"http.status_code\"},{\"value\":\"GET\",\"key\":\"http.method\"},{\"value\":\"/loki/api/v1/query_range?direction=BACKWARD\\u0026limit=1000\\u0026query=%7Bcompose_project%3D%22devenv%22%7D%20%7C%3D%22trace_id%22\\u0026start=1616070921000000000\\u0026end=1616072722000000000\\u0026step=2\",\"key\":\"http.url\"},{\"value\":\"net/http\",\"key\":\"component\"},{\"value\":\"[\\\"value1\\\",\\\"value2\\\"]\",\"key\":\"arrayAttribute\"},{\"value\":\"{\\\"key1\\\":\\\"value1\\\",\\\"key2\\\":\\\"value2\\\"}\",\"key\":\"kvlistAttribute\"}]"), root["tags"]) span := bFrame.FindRowWithValue("spanID", "7198307df9748606")