Skip to content

Commit

Permalink
Merge pull request #172 from ymtdzzz/feature/refresh_service_root_span
Browse files Browse the repository at this point in the history
Add feature of refreshing service root spans
  • Loading branch information
ymtdzzz authored Dec 16, 2024
2 parents 7c04d57 + f0667cd commit aa884af
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 5 deletions.
10 changes: 8 additions & 2 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ cloud.google.com/go/workflows v1.12.8/go.mod h1:b7akG38W6lHmyPc+WYJxIYl1rEv79bBM
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20221208032759-85de2813cf6b/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.sr.ht/~sbinet/gg v0.5.0/go.mod h1:G2C0eRESqlKhS7ErsNey6HHrqU1PwsnCQlekFi9Q2Oo=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/IBM/sarama v1.43.2/go.mod h1:Kyo4WkF24Z+1nz7xeVUFWIuKVV8RS3wM8mkvPKMdXFQ=
github.com/IBM/sarama v1.43.3/go.mod h1:FVIRaLrhK3Cla/9FfRF5X9Zua2KpS3SYIXxhac1H+FQ=
Expand Down Expand Up @@ -261,8 +262,10 @@ github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUg
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM=
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0=
github.com/containerd/containerd v1.7.15/go.mod h1:ISzRRTMF8EXNpJlTzyr2XMhN+j9K302C21/+cr3kUnY=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/crossdock/crossdock-go v0.0.0-20160816171116-049aabb0122b/go.mod h1:v9FBN7gdVTpiD/+LZ7Po0UKvROyT87uLVxTHVky/dlQ=
github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
Expand Down Expand Up @@ -352,6 +355,7 @@ github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YO
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8=
Expand Down Expand Up @@ -388,6 +392,7 @@ github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.108.0/go
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.109.0/go.mod h1:P7e6ch+uoSfxK+lMwfcndkHE6gWUqvWKpr7mD04KIAA=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.110.0/go.mod h1:eazQnU3D7Xwyctq8Yfig4ws5HcnD3G+ygWrG9H03JjE=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.112.0/go.mod h1:G4KniRkewEl7JaT1EVTczTWi1nfYk2bD5GAn4aqBh4o=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.115.0/go.mod h1:mtxUxJEIQy27MaGR1yzcn/OK8NoddEgb7fumpEbKYss=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/kafka/topic v0.111.0/go.mod h1:Lqc5Me0HU2a/DAESI//0UuKnGszTwuDnV+oVOLRkfio=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl v0.111.0/go.mod h1:GQHN6IbBsaGmMJIOQcqA7RXiJi55rXldP3di5YJ1IYA=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.106.1/go.mod h1:St0VVFKzA0fNxo5RmzI4fg7ucGttd840OZ56a+ZECZs=
Expand All @@ -396,6 +401,7 @@ github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.108.0
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.109.0/go.mod h1:KvJWxR0bDk9Qh0ktw4gOFsd/ZrJ7p5KTAQueEJsaK9Q=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.110.0/go.mod h1:nn/ktwLdZ6O9mtnRuak8NQEfGRow3VI3l+YqAroJX7g=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.112.0/go.mod h1:dQCrspUDJRs7P6pXRALwj/yKIMzTYCvLa7XlzNycVFY=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.115.0/go.mod h1:R8AkVWe9G5Q0oMOapvm9HNS076E3Min8SVlmhBL3QD0=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.106.1/go.mod h1:ehzaiDdkrww7l1Stvse5GCOAsAZOpFcgeIbB/2PqFs4=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.107.0/go.mod h1:/RtBag3LuHIkqN4bo8Erd3jCzA3gea70l9WyJ9TncXM=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.110.0 h1:KYBzbgQyCz4i5zjzs0iBOFuNh2vagaw2seqvZ7Lftxk=
Expand Down Expand Up @@ -463,6 +469,7 @@ github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cA
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/testcontainers/testcontainers-go v0.31.0/go.mod h1:D2lAoA0zUFiSY+eAflqK5mcUx/A5hrrORaEQrd0SefI=
github.com/testcontainers/testcontainers-go v0.34.0/go.mod h1:6P/kMkQe8yqPHfPWNulFGdFHTD8HB2vLq/231xY2iPQ=
github.com/tilinna/clock v1.1.0/go.mod h1:ZsP7BcY7sEEz7ktc0IVy8Us6boDrK8VradlKRUGfOao=
github.com/ua-parser/uap-go v0.0.0-20240611065828-3a4781585db6/go.mod h1:BUbeWZiieNxAuuADTBNb3/aeje6on3DhU3rpWsQSB1E=
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
Expand Down Expand Up @@ -549,6 +556,7 @@ go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.106.1/go.mod h
go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.111.0/go.mod h1:s42Gm7LMqietFs0Cpl+ma2sEYZP3RWHIlXlWimGW2cQ=
go.opentelemetry.io/collector/receiver/otlpreceiver v0.110.0 h1:F1TsgyWimClOvAfP7nUbKChPfoNt8tThI64WNCutkAE=
go.opentelemetry.io/collector/receiver/otlpreceiver v0.110.0/go.mod h1:MuLDagbS+v3iUwMSN/iJPWiDMLPEYxeYolzc+T2ElU0=
go.opentelemetry.io/collector/scraper v0.115.0/go.mod h1:7YoCO6/4PeExLiX1FokcydJGCQUa7lUqZsqXokJ5VZ4=
go.opentelemetry.io/collector/semconv v0.110.0 h1:KHQnOHe3gUz0zsxe8ph9kN5OTypCFD4V+06AiBTfeNk=
go.opentelemetry.io/collector/semconv v0.110.0/go.mod h1:zCJ5njhWpejR+A40kiEoeFm1xq1uzyZwMnRNX6/D82A=
go.opentelemetry.io/collector/service v0.110.0 h1:jeGdUi+5HQuH0Ho/Gd+VusY77MYJAUxUm0Vxh7aNbjQ=
Expand Down Expand Up @@ -595,8 +603,6 @@ golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5D
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/exp/shiny v0.0.0-20230817173708-d852ddb80c63/go.mod h1:UH99kUObWAZkDnWqppdQe5ZhPYESUw8I0zVV1uWBR+0=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
Expand Down
23 changes: 21 additions & 2 deletions tuiexporter/internal/telemetry/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,17 @@ type TraceServiceSpanDataMap map[string]map[string][]*SpanData
// the spans have any error status
type TraceServiceHasErrorMap map[string]map[string]bool

// TraceServiceParentIDMap is a map of trace id and service name to a parent span id
// This is used to update service root spans in the trace list.
type TraceServiceParentIDMap map[string]map[string]*SpanData

// TraceCache is a cache of trace spans
type TraceCache struct {
spanid2span SpanDataMap
traceid2spans TraceSpanDataMap
tracesvc2spans TraceServiceSpanDataMap
tracesvc2haserror TraceServiceHasErrorMap
tracesvc2parent TraceServiceParentIDMap
}

// NewTraceCache returns a new trace cache
Expand All @@ -33,34 +38,46 @@ func NewTraceCache() *TraceCache {
traceid2spans: TraceSpanDataMap{},
tracesvc2spans: TraceServiceSpanDataMap{},
tracesvc2haserror: TraceServiceHasErrorMap{},
tracesvc2parent: TraceServiceParentIDMap{},
}
}

// UpdateCache updates the cache with a new span
func (c *TraceCache) UpdateCache(sname string, data *SpanData) (newtracesvc bool) {
func (c *TraceCache) UpdateCache(sname string, data *SpanData) (newtracesvc bool, replaceSpanID string) {
c.spanid2span[data.Span.SpanID().String()] = data
traceID := data.Span.TraceID().String()
hasError := spanHasError(data.Span)
if ts, ok := c.traceid2spans[traceID]; ok {
c.traceid2spans[traceID] = append(ts, data)
if _, ok := c.tracesvc2spans[traceID][sname]; ok {
c.tracesvc2spans[traceID][sname] = append(c.tracesvc2spans[traceID][sname], data)
if c.tracesvc2parent[traceID][sname].Span.ParentSpanID().String() == data.Span.SpanID().String() {
// This span is higher parent span
// NOTE: In this process, for performance reasons, only adjacent parent-child relationships
// between spans are evaluated. For example, if the parent-child order of spans is 1, 2, 3, and
// the arrival order is 3, 1, 2, span 2 will be recognized as the service root span. To recalculate
// the specific parent-child relationship, use `R` key to trigger deep refreshing
replaceSpanID = c.tracesvc2parent[traceID][sname].Span.SpanID().String()
c.tracesvc2parent[traceID][sname] = data
}
if hasError {
c.tracesvc2haserror[traceID][sname] = hasError
}
} else {
c.tracesvc2spans[traceID][sname] = []*SpanData{data}
c.tracesvc2haserror[traceID][sname] = hasError
c.tracesvc2parent[traceID][sname] = data
newtracesvc = true
}
} else {
c.traceid2spans[traceID] = []*SpanData{data}
c.tracesvc2spans[traceID] = map[string][]*SpanData{sname: {data}}
c.tracesvc2haserror[traceID] = map[string]bool{sname: hasError}
c.tracesvc2parent[traceID] = map[string]*SpanData{sname: data}
newtracesvc = true
}

return newtracesvc
return newtracesvc, replaceSpanID
}

// DeleteCache deletes a list of spans from the cache
Expand All @@ -77,9 +94,11 @@ func (c *TraceCache) DeleteCache(serviceSpans []*SpanData) {
}
delete(c.tracesvc2spans[traceID], sname.AsString())
delete(c.tracesvc2haserror[traceID], sname.AsString())
delete(c.tracesvc2parent[traceID], sname.AsString())
if len(c.tracesvc2spans[traceID]) == 0 {
delete(c.tracesvc2spans, traceID)
delete(c.tracesvc2haserror, traceID)
delete(c.tracesvc2parent, traceID)
// delete spans in traceid2spans only if there are no spans left in tracesvc2spans
// for better performance
delete(c.traceid2spans, traceID)
Expand Down
49 changes: 48 additions & 1 deletion tuiexporter/internal/telemetry/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ func (sd *SpanData) IsRoot() bool {
// This is a slice of one span of a single service
type SvcSpans []*SpanData

func (ss *SvcSpans) replaceBySpanID(replaceSpanID string, data *SpanData) {
for i, s := range *ss {
if s.Span.SpanID().String() == replaceSpanID {
(*ss)[i] = data
return
}
}
}

// MetricData is a struct to represent a metric
type MetricData struct {
Metric *pmetric.Metric
Expand Down Expand Up @@ -249,6 +258,41 @@ func (s *Store) GetFilteredServiceSpansByIdx(idx int) []*SpanData {
return spans
}

// RecalculateServiceRootSpanByIdx recalculates service root span of the specified index
func (s *Store) RecalculateServiceRootSpanByIdx(idx int) {
s.mut.Lock()
defer func() {
s.updatedAt = time.Now()
s.mut.Unlock()
}()

if idx < 0 || idx >= len(s.svcspansFiltered) {
return
}
traceID := s.svcspansFiltered[idx].Span.TraceID().String()
currentSpanID := s.svcspansFiltered[idx].Span.SpanID().String()
sname, ok := s.svcspansFiltered[idx].ResourceSpan.Resource().Attributes().Get("service.name")
if !ok {
return
}

spans := s.tracecache.tracesvc2spans[traceID][sname.AsString()]
spanMemo := make(map[string]bool)
for _, span := range spans {
spanMemo[span.Span.SpanID().String()] = true
}
for _, span := range spans {
parentSpanID := span.Span.ParentSpanID().String()
spanID := span.Span.SpanID().String()
if _, ok := spanMemo[parentSpanID]; !ok {
// TODO: Condider orphan span?
sd := s.tracecache.spanid2span[spanID]
s.svcspansFiltered[idx] = sd
s.svcspans.replaceBySpanID(currentSpanID, sd)
}
}
}

// GetFilteredMetricByIdx returns the metric at the given index
func (s *Store) GetFilteredMetricByIdx(idx int) *MetricData {
if idx < 0 || idx >= len(s.metricsFiltered) {
Expand Down Expand Up @@ -291,9 +335,12 @@ func (s *Store) AddSpan(traces *ptrace.Traces) {
ScopeSpans: &ss,
ReceivedAt: time.Now(),
}
newtracesvc := s.tracecache.UpdateCache(sname.AsString(), sd)
newtracesvc, replaceSpanID := s.tracecache.UpdateCache(sname.AsString(), sd)
if newtracesvc {
s.svcspans = append(s.svcspans, sd)
} else if len(replaceSpanID) > 0 {
// FIXME: More efficient logic is needed
s.svcspans.replaceBySpanID(replaceSpanID, sd)
}
}
}
Expand Down
123 changes: 123 additions & 0 deletions tuiexporter/internal/telemetry/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,129 @@ func TestStoreAddSpanWithRotation(t *testing.T) {
}
}

func TestStoreAddSpanServiceSpanCalculation(t *testing.T) {
// traceid: 1
// └- resource: test-service-1
// └- scope: test-scope-1-1
// └- span: span-1-1-2
// └- span: span-1-1-3
// traceid: 1 (the same trace)
// └- resource: test-service-1
// └- scope: test-scope-1-1
// └- span: span-1-1-1
store := NewStore()
store.maxServiceSpanCount = 1
payload1, _ := test.GenerateOTLPTracesPayload(t, 1, 1, []int{3}, [][]int{{3, 0, 0}})
payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).SetParentSpanID(
payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).SpanID(),
)
payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(2).SetParentSpanID(
payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).SpanID(),
)
payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().RemoveIf(func(s ptrace.Span) bool {
return s.Name() == "span-0-0-0"
})
payload2, _ := test.GenerateOTLPTracesPayload(t, 1, 1, []int{3}, [][]int{{3, 0, 0}})
payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).SetParentSpanID(
payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).SpanID(),
)
payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(2).SetParentSpanID(
payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).SpanID(),
)
payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().RemoveIf(func(s ptrace.Span) bool {
return s.Name() == "span-0-0-1" || s.Name() == "span-0-0-2"
})

assert.Equal(t, 2, payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().Len())
assert.Equal(t, 1, payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().Len())

store.AddSpan(&payload1)

// The service root span should be span-1-1-2
assert.Equal(t, 1, len(store.svcspans))
assert.Equal(t, "span-0-0-1", store.svcspans[0].Span.Name())

store.AddSpan(&payload2)

// Now, The service root span should be span-1-1-1
assert.Equal(t, 1, len(store.svcspans))
assert.Equal(t, "span-0-0-0", store.svcspans[0].Span.Name())
}

func TestStoreAddSpanServiceSpanCalculationLimitation(t *testing.T) {
// traceid: 1
// └- resource: test-service-1
// └- scope: test-scope-1-1
// └- span: span-1-1-3
// traceid: 1 (the same trace)
// └- resource: test-service-1
// └- scope: test-scope-1-1
// └- span: span-1-1-1
// traceid: 1 (the same trace)
// └- resource: test-service-1
// └- scope: test-scope-1-1
// └- span: span-1-1-2
store := NewStore()
store.maxServiceSpanCount = 1
payload1, _ := test.GenerateOTLPTracesPayload(t, 1, 1, []int{3}, [][]int{{3, 0, 0}})
payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).SetParentSpanID(
payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).SpanID(),
)
payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(2).SetParentSpanID(
payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).SpanID(),
)
payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().RemoveIf(func(s ptrace.Span) bool {
return s.Name() == "span-0-0-0" || s.Name() == "span-0-0-1"
})
payload2, _ := test.GenerateOTLPTracesPayload(t, 1, 1, []int{3}, [][]int{{3, 0, 0}})
payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).SetParentSpanID(
payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).SpanID(),
)
payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(2).SetParentSpanID(
payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).SpanID(),
)
payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().RemoveIf(func(s ptrace.Span) bool {
return s.Name() == "span-0-0-1" || s.Name() == "span-0-0-2"
})
payload3, _ := test.GenerateOTLPTracesPayload(t, 1, 1, []int{3}, [][]int{{3, 0, 0}})
payload3.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).SetParentSpanID(
payload3.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).SpanID(),
)
payload3.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(2).SetParentSpanID(
payload3.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).SpanID(),
)
payload3.ResourceSpans().At(0).ScopeSpans().At(0).Spans().RemoveIf(func(s ptrace.Span) bool {
return s.Name() == "span-0-0-0" || s.Name() == "span-0-0-2"
})

assert.Equal(t, 1, payload1.ResourceSpans().At(0).ScopeSpans().At(0).Spans().Len())
assert.Equal(t, 1, payload2.ResourceSpans().At(0).ScopeSpans().At(0).Spans().Len())
assert.Equal(t, 1, payload3.ResourceSpans().At(0).ScopeSpans().At(0).Spans().Len())

store.AddSpan(&payload1)

// The service root span should be span-1-1-3
assert.Equal(t, 1, len(store.svcspans))
assert.Equal(t, "span-0-0-2", store.svcspans[0].Span.Name())

store.AddSpan(&payload2)

// The service root span should still be span-1-1-3
assert.Equal(t, 1, len(store.svcspans))
assert.Equal(t, "span-0-0-2", store.svcspans[0].Span.Name())

store.AddSpan(&payload3)

// Finally, The service root span should be span-1-1-2
assert.Equal(t, 1, len(store.svcspans))
assert.Equal(t, "span-0-0-1", store.svcspans[0].Span.Name())

// By RecalculateServiceRootSpanByIdx, we can get span-1-1-1 as the root span
store.RecalculateServiceRootSpanByIdx(0)
assert.Equal(t, 1, len(store.svcspans))
assert.Equal(t, "span-0-0-0", store.svcspans[0].Span.Name())
}

func TestStoreAddMetricWithoutRotation(t *testing.T) {
// metric: 1
// └- resource: test-service-1
Expand Down
12 changes: 12 additions & 0 deletions tuiexporter/internal/tui/component/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,14 @@ func (p *TUIPages) createTracePage(store *telemetry.Store) *tview.Flex {
}
log.Printf("sortType: %s", sortType)
store.ApplyFilterTraces(inputConfirmed, sortType)
return nil
} else if event.Rune() == 'r' {
row, _ := table.GetSelection()
if row == 0 {
return nil
}
store.RecalculateServiceRootSpanByIdx(row - 1)

return nil
}
return event
Expand All @@ -208,6 +216,10 @@ func (p *TUIPages) createTracePage(store *telemetry.Store) *tview.Flex {
key: tcell.NewEventKey(tcell.KeyRune, 'S', tcell.ModCtrl),
description: "Toggle sort (Latency)",
},
{
key: tcell.NewEventKey(tcell.KeyRune, 'R', tcell.ModNone),
description: "Recalculate service root span",
},
{
key: tcell.NewEventKey(tcell.KeyRune, 'L', tcell.ModCtrl),
description: "Clear all data",
Expand Down

0 comments on commit aa884af

Please sign in to comment.