From fa0b39b7fd2b193d259913ee2c673c42b7e45b4f Mon Sep 17 00:00:00 2001 From: Greg Kalapos Date: Wed, 16 Apr 2025 11:39:20 +0200 Subject: [PATCH] Fix handling of non root span that represent a dependency --- enrichments/trace/internal/elastic/span.go | 2 +- .../trace/internal/elastic/span_test.go | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/enrichments/trace/internal/elastic/span.go b/enrichments/trace/internal/elastic/span.go index 6d6f5f1..30de8af 100644 --- a/enrichments/trace/internal/elastic/span.go +++ b/enrichments/trace/internal/elastic/span.go @@ -220,7 +220,7 @@ func (s *spanEnrichmentContext) enrich(span ptrace.Span, cfg config.Config) { // In OTel, a local root span can represent an outgoing call or a producer span. // In such cases, the span is still mapped into a transaction, but enriched // with additional attributes that are specific to the outgoing call or producer span. - isExitRootSpan := s.isTransaction && span.Kind() == ptrace.SpanKindClient || span.Kind() == ptrace.SpanKindProducer + isExitRootSpan := s.isTransaction && (span.Kind() == ptrace.SpanKindClient || span.Kind() == ptrace.SpanKindProducer) if s.isTransaction { s.enrichTransaction(span, cfg.Transaction) diff --git a/enrichments/trace/internal/elastic/span_test.go b/enrichments/trace/internal/elastic/span_test.go index 6e538fe..52460bb 100644 --- a/enrichments/trace/internal/elastic/span_test.go +++ b/enrichments/trace/internal/elastic/span_test.go @@ -570,6 +570,41 @@ func TestRootSpanAsDependencyEnrich(t *testing.T) { elasticattr.SpanRepresentativeCount: float64(1), }, }, + // This one is a non root span representing a dependency. The test asserts that such spans are not + // accidentally mapped into a transaction. + { + name: "producer_messaging_non_root_span", + input: func() ptrace.Span { + span := ptrace.NewSpan() + span.SetName("rootClientSpan") + span.SetSpanID([8]byte{1}) + span.SetKind(ptrace.SpanKindProducer) + // Adding parent id to make sure this is not a root span. + span.SetParentSpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) + span.Attributes().PutStr(semconv25.AttributeServerAddress, "myServer") + span.Attributes().PutStr(semconv25.AttributeServerPort, "1234") + span.Attributes().PutStr(semconv25.AttributeMessagingSystem, "rabbitmq") + span.Attributes().PutStr(semconv25.AttributeMessagingDestinationName, "T") + span.Attributes().PutStr(semconv25.AttributeMessagingOperation, "publish") + span.Attributes().PutStr(semconv25.AttributeMessagingClientID, "a") + return span + }(), + config: config.Enabled(), + enrichedAttrs: map[string]any{ + elasticattr.TimestampUs: int64(0), + elasticattr.ProcessorEvent: "span", + elasticattr.SpanType: "messaging", + elasticattr.SpanSubtype: "rabbitmq", + elasticattr.SpanDestinationServiceResource: "rabbitmq/T", + elasticattr.SpanName: "rootClientSpan", + elasticattr.EventOutcome: "success", + elasticattr.SuccessCount: int64(1), + elasticattr.ServiceTargetName: "T", + elasticattr.ServiceTargetType: "rabbitmq", + elasticattr.SpanDurationUs: int64(0), + elasticattr.SpanRepresentativeCount: float64(1), + }, + }, } { t.Run(tc.name, func(t *testing.T) { expectedSpan := ptrace.NewSpan()