Skip to content

Commit

Permalink
refactor SpanKind2Type and update tests to keep V1 logic intact
Browse files Browse the repository at this point in the history
  • Loading branch information
jackgopack4 committed Jan 9, 2025
1 parent 08b9fd7 commit c39e720
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 80 deletions.
26 changes: 1 addition & 25 deletions pkg/trace/api/otlp.go
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ func (o *OTLPReceiver) convertSpan(rattr map[string]string, lib pcommon.Instrume
}
}
if span.Type == "" {
span.Type = spanKind2Type(in.Kind(), span)
span.Type = traceutil.SpanKind2Type(in, rattr)
}
return span
}
Expand Down Expand Up @@ -696,30 +696,6 @@ func resourceFromTags(meta map[string]string) string {
return ""
}

// spanKind2Type returns a span's type based on the given kind and other present properties.
func spanKind2Type(kind ptrace.SpanKind, span *pb.Span) string {
var typ string
switch kind {
case ptrace.SpanKindServer:
typ = "web"
case ptrace.SpanKindClient:
typ = "http"
db, ok := span.Meta[string(semconv.AttributeDBSystem)]
if !ok {
break
}
switch db {
case "redis", "memcached":
typ = "cache"
default:
typ = "db"
}
default:
typ = "custom"
}
return typ
}

// computeTopLevelAndMeasured updates the span's top-level and measured attributes.
//
// An OTLP span is considered top-level if it is a root span or has a span kind of server or consumer.
Expand Down
50 changes: 1 addition & 49 deletions pkg/trace/api/otlp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1590,55 +1590,7 @@ func TestOTLPHelpers(t *testing.T) {
}
})

t.Run("spanKind2Type", func(t *testing.T) {
for _, tt := range []struct {
kind ptrace.SpanKind
meta map[string]string
out string
}{
{
kind: ptrace.SpanKindServer,
out: "web",
},
{
kind: ptrace.SpanKindClient,
out: "http",
},
{
kind: ptrace.SpanKindClient,
meta: map[string]string{"db.system": "redis"},
out: "cache",
},
{
kind: ptrace.SpanKindClient,
meta: map[string]string{"db.system": "memcached"},
out: "cache",
},
{
kind: ptrace.SpanKindClient,
meta: map[string]string{"db.system": "other"},
out: "db",
},
{
kind: ptrace.SpanKindProducer,
out: "custom",
},
{
kind: ptrace.SpanKindConsumer,
out: "custom",
},
{
kind: ptrace.SpanKindInternal,
out: "custom",
},
{
kind: ptrace.SpanKindUnspecified,
out: "custom",
},
} {
assert.Equal(t, tt.out, spanKind2Type(tt.kind, &pb.Span{Meta: tt.meta}))
}
})
// test spanKind2Type moved to pkg/trace/traceutil/otel_util_test.go

t.Run("tagsFromHeaders", func(t *testing.T) {
out := tagsFromHeaders(http.Header(map[string][]string{
Expand Down
5 changes: 3 additions & 2 deletions pkg/trace/stats/otel_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import (
"testing"
"time"

pb "github.com/DataDog/datadog-agent/pkg/proto/pbgo/trace"
"github.com/DataDog/datadog-agent/pkg/trace/config"
"github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/attributes"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
Expand All @@ -20,6 +18,9 @@ import (
semconv "go.opentelemetry.io/collector/semconv/v1.17.0"
"go.opentelemetry.io/otel/metric/noop"
"google.golang.org/protobuf/testing/protocmp"

pb "github.com/DataDog/datadog-agent/pkg/proto/pbgo/trace"
"github.com/DataDog/datadog-agent/pkg/trace/config"
)

var (
Expand Down
30 changes: 30 additions & 0 deletions pkg/trace/traceutil/otel_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,37 @@ func GetOTelAttrValInResAndSpanAttrs(span ptrace.Span, res pcommon.Resource, nor
return GetOTelAttrVal(span.Attributes(), normalize, keys...)
}

// SpanKind2Type returns a span's type based on the given kind and other present properties.
// This function is used in Resource V1 logic only. See GetOtelSpanType for Resource V2 logic.
func SpanKind2Type(span ptrace.Span, rattr map[string]string) string {
var typ string
switch span.Kind() {
case ptrace.SpanKindServer:
typ = "web"
case ptrace.SpanKindClient:
typ = "http"
res := pcommon.NewResource()
for k, v := range rattr {
res.Attributes().PutStr(k, v)
}
db := GetOTelAttrValInResAndSpanAttrs(span, res, true, semconv.AttributeDBSystem)
if db == "" {
break
}
switch db {
case "redis", "memcached":
typ = "cache"
default:
typ = "db"
}
default:
typ = "custom"
}
return typ
}

// GetOTelSpanType returns the DD span type based on OTel span kind and attributes.
// This uses Resource and operation V2 logic
func GetOTelSpanType(span ptrace.Span, res pcommon.Resource) string {
typ := GetOTelAttrValInResAndSpanAttrs(span, res, false, "span.type")
if typ != "" {
Expand Down
55 changes: 55 additions & 0 deletions pkg/trace/traceutil/otel_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,61 @@ func TestGetOTelSpanType(t *testing.T) {
}
}

func TestSpanKind2Type(t *testing.T) {
for _, tt := range []struct {
kind ptrace.SpanKind
meta map[string]string
out string
}{
{
kind: ptrace.SpanKindServer,
out: "web",
},
{
kind: ptrace.SpanKindClient,
out: "http",
},
{
kind: ptrace.SpanKindClient,
meta: map[string]string{"db.system": "redis"},
out: "cache",
},
{
kind: ptrace.SpanKindClient,
meta: map[string]string{"db.system": "memcached"},
out: "cache",
},
{
kind: ptrace.SpanKindClient,
meta: map[string]string{"db.system": "other"},
out: "db",
},
{
kind: ptrace.SpanKindProducer,
out: "custom",
},
{
kind: ptrace.SpanKindConsumer,
out: "custom",
},
{
kind: ptrace.SpanKindInternal,
out: "custom",
},
{
kind: ptrace.SpanKindUnspecified,
out: "custom",
},
} {
t.Run(tt.out, func(t *testing.T) {
span := ptrace.NewSpan()
span.SetKind(tt.kind)
actual := SpanKind2Type(span, tt.meta)
assert.Equal(t, tt.out, actual)
})
}
}

func TestGetOTelService(t *testing.T) {
for _, tt := range []struct {
name string
Expand Down
21 changes: 17 additions & 4 deletions pkg/trace/transform/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ import (
"strconv"
"strings"

"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/ptrace"
semconv "go.opentelemetry.io/collector/semconv/v1.6.1"

pb "github.com/DataDog/datadog-agent/pkg/proto/pbgo/trace"
"github.com/DataDog/datadog-agent/pkg/trace/config"
"github.com/DataDog/datadog-agent/pkg/trace/sampler"
"github.com/DataDog/datadog-agent/pkg/trace/traceutil"
"github.com/DataDog/datadog-agent/pkg/util/log"
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/ptrace"
semconv "go.opentelemetry.io/collector/semconv/v1.6.1"
)

// OperationAndResourceNameV2Enabled checks if the new operation and resource name logic should be used
Expand All @@ -41,12 +42,24 @@ func OtelSpanToDDSpanMinimal(
) *pb.Span {
var operationName string
var resourceName string
var spanType string
if OperationAndResourceNameV2Enabled(conf) {
operationName = traceutil.GetOTelOperationNameV2(otelspan)
resourceName = traceutil.GetOTelResourceV2(otelspan, otelres)
spanType = traceutil.GetOTelSpanType(otelspan, otelres)
} else {
operationName = traceutil.GetOTelOperationNameV1(otelspan, otelres, lib, conf.OTLPReceiver.SpanNameAsResourceName, conf.OTLPReceiver.SpanNameRemappings, true)
resourceName = traceutil.GetOTelResourceV1(otelspan, otelres)
attr := otelres.Attributes()
rattr := make(map[string]string, attr.Len())
attr.Range(func(k string, v pcommon.Value) bool {
rattr[k] = v.AsString()
return true
})
spanType = traceutil.GetOTelAttrVal(otelspan.Attributes(), true, "span.type")
if spanType == "" {
spanType = traceutil.SpanKind2Type(otelspan, rattr)
}
}

ddspan := &pb.Span{
Expand All @@ -58,7 +71,7 @@ func OtelSpanToDDSpanMinimal(
ParentID: traceutil.OTelSpanIDToUint64(otelspan.ParentSpanID()),
Start: int64(otelspan.StartTimestamp()),
Duration: int64(otelspan.EndTimestamp()) - int64(otelspan.StartTimestamp()),
Type: traceutil.GetOTelSpanType(otelspan, otelres),
Type: spanType,
Meta: make(map[string]string, otelres.Attributes().Len()+otelspan.Attributes().Len()),
Metrics: map[string]float64{},
}
Expand Down

0 comments on commit c39e720

Please sign in to comment.