Skip to content

Commit

Permalink
Add span start attributes to the SDK data (#1133)
Browse files Browse the repository at this point in the history
* Add start attributes

* Process attributes from probe

* Fix spelling

* Remove TODO comment
  • Loading branch information
MrAlias authored Oct 2, 2024
1 parent e90b842 commit 047952b
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package sdk
import (
"bytes"
"encoding/binary"
"fmt"
"log/slog"

"github.com/cilium/ebpf/perf"
Expand All @@ -15,6 +16,7 @@ import (
"go.opentelemetry.io/auto/internal/pkg/instrumentation/probe"
"go.opentelemetry.io/auto/internal/pkg/structfield"

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
)

Expand Down Expand Up @@ -151,10 +153,84 @@ func (c *converter) convertEvent(e *event) []*probe.SpanEvent {
TracerName: ss.Scope().Name(),
TracerVersion: ss.Scope().Version(),
TracerSchema: ss.SchemaUrl(),
Attributes: attributes(span.Attributes()),
// TODO: Status.
// TODO: Attributes.
// TODO: Events.
// TODO: Links.
// TODO: Span Kind.
}}
}

func attributes(m pcommon.Map) []attribute.KeyValue {
out := make([]attribute.KeyValue, 0, m.Len())
m.Range(func(key string, val pcommon.Value) bool {
out = append(out, attribute.KeyValue{
Key: attribute.Key(key),
Value: attributeValue(val),
})
return true
})
return out
}

func attributeValue(val pcommon.Value) (out attribute.Value) {
switch val.Type() {
case pcommon.ValueTypeEmpty:
case pcommon.ValueTypeStr:
out = attribute.StringValue(val.AsString())
case pcommon.ValueTypeInt:
out = attribute.Int64Value(val.Int())
case pcommon.ValueTypeDouble:
out = attribute.Float64Value(val.Double())
case pcommon.ValueTypeBool:
out = attribute.BoolValue(val.Bool())
case pcommon.ValueTypeSlice:
s := val.Slice()
if s.Len() == 0 {
// Undetectable slice type.
out = attribute.StringValue("<empty slice>")
return out
}

// Validate homogeneity before allocating.
t := s.At(0).Type()
for i := 1; i < s.Len(); i++ {
if s.At(i).Type() != t {
out = attribute.StringValue("<inhomogeneous slice>")
return out
}
}

switch t {
case pcommon.ValueTypeBool:
v := make([]bool, s.Len())
for i := 0; i < s.Len(); i++ {
v[i] = s.At(i).Bool()
}
out = attribute.BoolSliceValue(v)
case pcommon.ValueTypeStr:
v := make([]string, s.Len())
for i := 0; i < s.Len(); i++ {
v[i] = s.At(i).Str()
}
out = attribute.StringSliceValue(v)
case pcommon.ValueTypeInt:
v := make([]int64, s.Len())
for i := 0; i < s.Len(); i++ {
v[i] = s.At(i).Int()
}
out = attribute.Int64SliceValue(v)
case pcommon.ValueTypeDouble:
v := make([]float64, s.Len())
for i := 0; i < s.Len(); i++ {
v[i] = s.At(i).Double()
}
out = attribute.Float64SliceValue(v)
default:
out = attribute.StringValue(fmt.Sprintf("<invalid slice type %s>", t.String()))
}
default:
out = attribute.StringValue(fmt.Sprintf("<unknown: %#v>", val.AsRaw()))
}
return out
}
8 changes: 4 additions & 4 deletions internal/test/e2e/autosdk/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ usage() {
OPTIONS:
-t --tag Docker tag to use ["sample-app"]
-h --help Show this help message
EOF
EOF
}

parse_opts() {
# Make sure getopts starts at the begining
# Make sure getopts starts at the beginning
OPTIND=1

local deliminator option
Expand Down Expand Up @@ -100,9 +100,9 @@ main() {

# Check dependencies
hash git 2>/dev/null\
|| { echo >&2 "Requrired git client not found"; exit 1; }
|| { echo >&2 "Required git client not found"; exit 1; }
hash docker 2>/dev/null\
|| { echo >&2 "Requrired docker client not found"; exit 1; }
|| { echo >&2 "Required docker client not found"; exit 1; }

parse_opts "$@"

Expand Down
16 changes: 15 additions & 1 deletion internal/test/e2e/autosdk/traces.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,21 @@
"kind": 3,
"startTimeUnixNano": "946684800500000000",
"endTimeUnixNano": "946684801000000000",
"status": {}
"attributes": [
{
"key": "user",
"value": {
"stringValue": "Alice"
}
},
{
"key": "admin",
"value": {
"boolValue": true
}
}
],
"status": {},
},
{
"traceId": "xxxxx",
Expand Down
10 changes: 10 additions & 0 deletions internal/test/e2e/autosdk/verify.bats
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,13 @@ SCOPE="go.opentelemetry.io/auto/internal/test/e2e/autosdk"
timestamp=$(spans_from_scope_named ${SCOPE} | jq "select(.name == \"Run\")" | jq ".endTimeUnixNano")
assert_regex "$timestamp" "946684801000000000"
}

@test "autosdk :: Run span :: attribute :: user" {
result=$(span_attributes_for ${SCOPE} | jq "select(.key == \"user\").value.stringValue")
assert_equal "$result" '"Alice"'
}

@test "autosdk :: Run span :: attribute :: admin" {
result=$(span_attributes_for ${SCOPE} | jq "select(.key == \"admin\").value.boolValue")
assert_equal "$result" 'true'
}
2 changes: 1 addition & 1 deletion sdk/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func (t tracer) traces(ctx context.Context, name string, cfg trace.SpanConfig, s
}
span.SetStartTimestamp(start)

// TODO: Set Attributes.
setAttributes(span.Attributes(), cfg.Attributes())
// TODO: Add Links.

return traces, span
Expand Down
10 changes: 10 additions & 0 deletions sdk/trace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,16 @@ func TestSpanCreation(t *testing.T) {
assert.Equal(t, pcommon.NewTimestampFromTime(ts), s.span.StartTimestamp())
},
},
{
TestName: "WithAttributes",
Options: []trace.SpanStartOption{
trace.WithAttributes(attrs...),
},
Eval: func(t *testing.T, _ context.Context, s *span) {
assertTracer(s.traces)
assert.Equal(t, pAttrs, s.span.Attributes())
},
},
}

ctx := context.Background()
Expand Down

0 comments on commit 047952b

Please sign in to comment.