Skip to content

Commit

Permalink
[v2][adjuster] Implement adjuster for sorting attributes and events (#…
Browse files Browse the repository at this point in the history
…6389)

## Which problem is this PR solving?
- Towards #6344

## Description of the changes
- Implemented an adjuster to sort attributes and events that operates
natively on the OTLP data format. This is analogous to the
`SortTagsAndLogFields` adjuster in v1.

## How was this change tested?
- Added a unit test

## Checklist
- [x] I have read
https://github.com/jaegertracing/jaeger/blob/master/CONTRIBUTING_GUIDELINES.md
- [x] I have signed all commits
- [x] I have added unit tests for the new functionality
- [x] I have run lint and test steps successfully
  - for `jaeger`: `make lint test`
  - for `jaeger-ui`: `npm run lint` and `npm run test`

---------

Signed-off-by: Mahad Zaryab <[email protected]>
  • Loading branch information
mahadzaryab1 authored Dec 20, 2024
1 parent 5ab3d26 commit 6032db9
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 0 deletions.
81 changes: 81 additions & 0 deletions cmd/query/app/querysvc/adjuster/sort.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) 2024 The Jaeger Authors.
// SPDX-License-Identifier: Apache-2.0

package adjuster

import (
"sort"

"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/ptrace"
)

var _ Adjuster = (*SortAttributesAndEventsAdjuster)(nil)

// SortAttributesAndEvents creates an adjuster that standardizes trace data by sorting elements:
// - Resource attributes are sorted lexicographically by their keys.
// - Span attributes are sorted lexicographically by their keys.
// - Span events are sorted lexicographically by their names.
// - Attributes within each span event are sorted lexicographically by their keys.
func SortAttributesAndEvents() SortAttributesAndEventsAdjuster {
return SortAttributesAndEventsAdjuster{}
}

type SortAttributesAndEventsAdjuster struct{}

func (s SortAttributesAndEventsAdjuster) Adjust(traces ptrace.Traces) {
resourceSpans := traces.ResourceSpans()
for i := 0; i < resourceSpans.Len(); i++ {
rs := resourceSpans.At(i)
resource := rs.Resource()
s.sortAttributes(resource.Attributes())
scopeSpans := rs.ScopeSpans()
for j := 0; j < scopeSpans.Len(); j++ {
ss := scopeSpans.At(j)
s.sortAttributes(ss.Scope().Attributes())
spans := ss.Spans()
for k := 0; k < spans.Len(); k++ {
span := spans.At(k)
s.sortAttributes(span.Attributes())
s.sortEvents(span.Events())
links := span.Links()
for l := 0; l < links.Len(); l++ {
link := links.At(l)
s.sortAttributes(link.Attributes())
}
}
}
}
}

func (SortAttributesAndEventsAdjuster) sortAttributes(attributes pcommon.Map) {
entries := make([]struct {
key string
value pcommon.Value
}, 0, attributes.Len())
attributes.Range(func(k string, v pcommon.Value) bool {
entries = append(entries, struct {
key string
value pcommon.Value
}{key: k, value: v})
return true
})
sort.Slice(entries, func(i, j int) bool {
return entries[i].key < entries[j].key
})
newAttributes := pcommon.NewMap()
for _, entry := range entries {
entry.value.CopyTo(newAttributes.PutEmpty(entry.key))
}
newAttributes.CopyTo(attributes)
}

func (s SortAttributesAndEventsAdjuster) sortEvents(events ptrace.SpanEventSlice) {
events.Sort(func(a, b ptrace.SpanEvent) bool {
return a.Name() < b.Name()
})
for i := 0; i < events.Len(); i++ {
event := events.At(i)
s.sortAttributes(event.Attributes())
}
}
97 changes: 97 additions & 0 deletions cmd/query/app/querysvc/adjuster/sort_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) 2024 The Jaeger Authors.
// SPDX-License-Identifier: Apache-2.0

package adjuster

import (
"testing"

"github.com/stretchr/testify/assert"
"go.opentelemetry.io/collector/pdata/ptrace"
)

func TestSortAttributesAndEventsAdjuster(t *testing.T) {
adjuster := SortAttributesAndEvents()
input := func() ptrace.Traces {
traces := ptrace.NewTraces()
rs := traces.ResourceSpans().AppendEmpty()

resource := rs.Resource()
resource.Attributes().PutStr("attributeZ", "valA")
resource.Attributes().PutStr("attributeA", "valB")
resource.Attributes().PutInt("attributeY", 1)
resource.Attributes().PutStr("attributeX", "valC")

ss := rs.ScopeSpans().AppendEmpty()
ss.Scope().Attributes().PutStr("attributeH", "valI")
ss.Scope().Attributes().PutStr("attributeF", "valG")

span := ss.Spans().AppendEmpty()
span.Attributes().PutStr("attributeW", "valD")
span.Attributes().PutStr("attributeB", "valZ")
span.Attributes().PutInt("attributeV", 2)

event2 := span.Events().AppendEmpty()
event2.SetName("event2")
event2.Attributes().PutStr("attributeU", "valE")
event2.Attributes().PutStr("attributeT", "valF")

event1 := span.Events().AppendEmpty()
event1.SetName("event1")
event1.Attributes().PutStr("attributeR", "valE")
event1.Attributes().PutStr("attributeS", "valF")

link1 := span.Links().AppendEmpty()
link1.Attributes().PutStr("attributeA", "valB")
link1.Attributes().PutStr("attributeB", "valC")

link2 := span.Links().AppendEmpty()
link2.Attributes().PutStr("attributeD", "valE")
link2.Attributes().PutStr("attributeC", "valD")

return traces
}
expected := func() ptrace.Traces {
traces := ptrace.NewTraces()
rs := traces.ResourceSpans().AppendEmpty()

resource := rs.Resource()
resource.Attributes().PutStr("attributeA", "valB")
resource.Attributes().PutStr("attributeX", "valC")
resource.Attributes().PutInt("attributeY", 1)
resource.Attributes().PutStr("attributeZ", "valA")

ss := rs.ScopeSpans().AppendEmpty()
ss.Scope().Attributes().PutStr("attributeF", "valG")
ss.Scope().Attributes().PutStr("attributeH", "valI")

span := ss.Spans().AppendEmpty()
span.Attributes().PutStr("attributeB", "valZ")
span.Attributes().PutInt("attributeV", 2)
span.Attributes().PutStr("attributeW", "valD")

event1 := span.Events().AppendEmpty()
event1.SetName("event1")
event1.Attributes().PutStr("attributeR", "valE")
event1.Attributes().PutStr("attributeS", "valF")

event2 := span.Events().AppendEmpty()
event2.SetName("event2")
event2.Attributes().PutStr("attributeT", "valF")
event2.Attributes().PutStr("attributeU", "valE")

link1 := span.Links().AppendEmpty()
link1.Attributes().PutStr("attributeA", "valB")
link1.Attributes().PutStr("attributeB", "valC")

link2 := span.Links().AppendEmpty()
link2.Attributes().PutStr("attributeC", "valD")
link2.Attributes().PutStr("attributeD", "valE")

return traces
}

i := input()
adjuster.Adjust(i)
assert.Equal(t, expected(), i)
}

0 comments on commit 6032db9

Please sign in to comment.