Tempo: Represent OTLP Span Intrinsics correctly (#69394)

* Span intrinsics

* Update intrinsics and add to span details

* Remove intrinsics section

* Update tests

* Update status code text

* Self review

* Move previously intrinsic values to span

* Remove few methods
This commit is contained in:
Joey
2023-06-21 11:39:12 +01:00
committed by GitHub
parent e9d42a6395
commit 00ec9fceb9
23 changed files with 635 additions and 245 deletions

View File

@@ -46,6 +46,12 @@ func TraceToFrame(td pdata.Traces) (*data.Frame, error) {
data.NewField("parentSpanID", nil, []string{}),
data.NewField("operationName", nil, []string{}),
data.NewField("serviceName", nil, []string{}),
data.NewField("kind", nil, []string{}),
data.NewField("statusCode", nil, []int64{}),
data.NewField("statusMessage", nil, []string{}),
data.NewField("instrumentationLibraryName", nil, []string{}),
data.NewField("instrumentationLibraryVersion", nil, []string{}),
data.NewField("traceState", nil, []string{}),
data.NewField("serviceTags", nil, []json.RawMessage{}),
data.NewField("startTime", nil, []float64{}),
data.NewField("duration", nil, []float64{}),
@@ -119,12 +125,20 @@ func spanToSpanRow(span pdata.Span, libraryTags pdata.InstrumentationLibrary, re
startTime := float64(span.StartTimestamp()) / 1_000_000
serviceName, serviceTags := resourceToProcess(resource)
status := span.Status()
statusCode := int64(status.Code())
statusMessage := status.Message()
libraryName := libraryTags.Name()
libraryVersion := libraryTags.Version()
traceState := getTraceState(span.TraceState())
serviceTagsJson, err := json.Marshal(serviceTags)
if err != nil {
return nil, fmt.Errorf("failed to marshal service tags: %w", err)
}
spanTags, err := json.Marshal(getSpanTags(span, libraryTags))
spanTags, err := json.Marshal(getSpanTags(span))
if err != nil {
return nil, fmt.Errorf("failed to marshal span tags: %w", err)
}
@@ -147,6 +161,12 @@ func spanToSpanRow(span pdata.Span, libraryTags pdata.InstrumentationLibrary, re
parentSpanID,
span.Name(),
serviceName,
getSpanKind(span.Kind()),
statusCode,
statusMessage,
libraryName,
libraryVersion,
traceState,
json.RawMessage(serviceTagsJson),
startTime,
float64(span.EndTimestamp()-span.StartTimestamp()) / 1_000_000,
@@ -192,56 +212,16 @@ func getAttributeVal(attr pdata.AttributeValue) interface{} {
}
}
func getSpanTags(span pdata.Span, instrumentationLibrary pdata.InstrumentationLibrary) []*KeyValue {
func getSpanTags(span pdata.Span) []*KeyValue {
var tags []*KeyValue
libraryTags := getTagsFromInstrumentationLibrary(instrumentationLibrary)
if libraryTags != nil {
tags = append(tags, libraryTags...)
}
span.Attributes().Range(func(key string, attr pdata.AttributeValue) bool {
tags = append(tags, &KeyValue{Key: key, Value: getAttributeVal(attr)})
return true
})
status := span.Status()
possibleNilTags := []*KeyValue{
getTagFromSpanKind(span.Kind()),
getTagFromStatusCode(status.Code()),
getErrorTagFromStatusCode(status.Code()),
getTagFromStatusMsg(status.Message()),
getTagFromTraceState(span.TraceState()),
}
for _, tag := range possibleNilTags {
if tag != nil {
tags = append(tags, tag)
}
}
return tags
}
func getTagsFromInstrumentationLibrary(il pdata.InstrumentationLibrary) []*KeyValue {
var keyValues []*KeyValue
if ilName := il.Name(); ilName != "" {
kv := &KeyValue{
Key: conventions.InstrumentationLibraryName,
Value: ilName,
}
keyValues = append(keyValues, kv)
}
if ilVersion := il.Version(); ilVersion != "" {
kv := &KeyValue{
Key: conventions.InstrumentationLibraryVersion,
Value: ilVersion,
}
keyValues = append(keyValues, kv)
}
return keyValues
}
func getTagFromSpanKind(spanKind pdata.SpanKind) *KeyValue {
func getSpanKind(spanKind pdata.SpanKind) string {
var tagStr string
switch spanKind {
case pdata.SpanKindClient:
@@ -255,50 +235,17 @@ func getTagFromSpanKind(spanKind pdata.SpanKind) *KeyValue {
case pdata.SpanKindInternal:
tagStr = string(tracetranslator.OpenTracingSpanKindInternal)
default:
return nil
return ""
}
return &KeyValue{
Key: tracetranslator.TagSpanKind,
Value: tagStr,
}
return tagStr
}
func getTagFromStatusCode(statusCode pdata.StatusCode) *KeyValue {
return &KeyValue{
Key: tracetranslator.TagStatusCode,
Value: int64(statusCode),
}
}
func getErrorTagFromStatusCode(statusCode pdata.StatusCode) *KeyValue {
if statusCode == pdata.StatusCodeError {
return &KeyValue{
Key: tracetranslator.TagError,
Value: true,
}
}
return nil
}
func getTagFromStatusMsg(statusMsg string) *KeyValue {
if statusMsg == "" {
return nil
}
return &KeyValue{
Key: tracetranslator.TagStatusMsg,
Value: statusMsg,
}
}
func getTagFromTraceState(traceState pdata.TraceState) *KeyValue {
func getTraceState(traceState pdata.TraceState) string {
if traceState != pdata.TraceStateEmpty {
return &KeyValue{
Key: tracetranslator.TagW3CTraceState,
Value: string(traceState),
}
return string(traceState)
}
return nil
return ""
}
func spanEventsToLogs(events pdata.SpanEventSlice) []*TraceLog {

View File

@@ -40,7 +40,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%22traceID%22\\u0026start=1616070921000000000\\u0026end=1616072722000000000\\u0026step=2\",\"key\":\"http.url\"},{\"value\":\"net/http\",\"key\":\"component\"},{\"value\":\"server\",\"key\":\"span.kind\"},{\"value\":0,\"key\":\"status.code\"}]"), 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%22traceID%22\\u0026start=1616070921000000000\\u0026end=1616072722000000000\\u0026step=2\",\"key\":\"http.url\"},{\"value\":\"net/http\",\"key\":\"component\"}]"), root["tags"])
span := bFrame.FindRowWithValue("spanID", "7198307df9748606")
@@ -50,7 +50,6 @@ func TestTraceToFrame(t *testing.T) {
require.Equal(t, 1616072924072.852, span["startTime"])
require.Equal(t, 0.094, span["duration"])
require.Equal(t, json.RawMessage("[{\"timestamp\":1616072924072.856,\"fields\":[{\"value\":1,\"key\":\"chunks requested\"}]},{\"timestamp\":1616072924072.9448,\"fields\":[{\"value\":1,\"key\":\"chunks fetched\"}]}]"), span["logs"])
require.Equal(t, json.RawMessage("[{\"value\":0,\"key\":\"status.code\"}]"), span["tags"])
})
t.Run("should transform correct traceID", func(t *testing.T) {
@@ -141,6 +140,12 @@ var fields = []string{
"parentSpanID",
"operationName",
"serviceName",
"kind",
"statusCode",
"statusMessage",
"instrumentationLibraryName",
"instrumentationLibraryVersion",
"traceState",
"serviceTags",
"startTime",
"duration",