Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Removed

### Fixed
- Adds `trace.Link`'s own MarshalJSON method to marshal all fields, not just fields under embedded struct `trace.SpanContext` (#1820)

### Security

Expand Down
19 changes: 16 additions & 3 deletions trace/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func decodeHex(h string, b []byte) error {
//
// Trace state must be valid according to the W3C Trace Context specification at all times. All
// mutating operations validate their input and, in case of valid parameters, return a new TraceState.
type TraceState struct { //nolint:golint
type TraceState struct { // nolint:golint
// TODO @matej-g: Consider implementing this as attribute.Set, see
// comment https://github.com/open-telemetry/opentelemetry-go/pull/1340#discussion_r540599226
kvs []attribute.KeyValue
Expand Down Expand Up @@ -278,7 +278,7 @@ func (ts TraceState) copyKVsAndDeleteEntry(key attribute.Key) []attribute.KeyVal

// TraceStateFromKeyValues is a convenience method to create a new TraceState from
// provided key/value pairs.
func TraceStateFromKeyValues(kvs ...attribute.KeyValue) (TraceState, error) { //nolint:golint
func TraceStateFromKeyValues(kvs ...attribute.KeyValue) (TraceState, error) { // nolint:golint
if len(kvs) == 0 {
return TraceState{}, nil
}
Expand Down Expand Up @@ -314,7 +314,7 @@ func isTraceStateKeyValueValid(kv attribute.KeyValue) bool {
}

// TraceFlags contains flags that can be set on a SpanContext
type TraceFlags byte //nolint:golint
type TraceFlags byte // nolint:golint

// IsSampled returns if the sampling bit is set in the TraceFlags.
func (tf TraceFlags) IsSampled() bool {
Expand Down Expand Up @@ -582,6 +582,19 @@ type Link struct {
DroppedAttributeCount int
}

// Implements MarshalJSON to marshal all fields of link not just SpanContext
func (l Link) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
SpanContext SpanContext
Attributes []attribute.KeyValue
DroppedAttributeCount int
}{
SpanContext: l.SpanContext,
Attributes: l.Attributes,
DroppedAttributeCount: l.DroppedAttributeCount,
})
}

// SpanKind is the role a Span plays in a Trace.
type SpanKind int

Expand Down
36 changes: 32 additions & 4 deletions trace/trace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package trace

import (
"bytes"
"encoding/json"
"fmt"
"testing"

Expand Down Expand Up @@ -128,7 +130,7 @@ func TestHasTraceID(t *testing.T) {
},
} {
t.Run(testcase.name, func(t *testing.T) {
//proto: func (sc SpanContext) HasTraceID() bool{}
// proto: func (sc SpanContext) HasTraceID() bool{}
sc := SpanContext{traceID: testcase.tid}
have := sc.HasTraceID()
if have != testcase.want {
Expand All @@ -155,7 +157,7 @@ func TestHasSpanID(t *testing.T) {
},
} {
t.Run(testcase.name, func(t *testing.T) {
//proto: func (sc SpanContext) HasSpanID() bool {}
// proto: func (sc SpanContext) HasSpanID() bool {}
have := testcase.sc.HasSpanID()
if have != testcase.want {
t.Errorf("Want: %v, but have: %v", testcase.want, have)
Expand Down Expand Up @@ -254,7 +256,7 @@ func TestStringTraceID(t *testing.T) {
},
} {
t.Run(testcase.name, func(t *testing.T) {
//proto: func (t TraceID) String() string {}
// proto: func (t TraceID) String() string {}
have := testcase.tid.String()
if have != testcase.want {
t.Errorf("Want: %s, but have: %s", testcase.want, have)
Expand All @@ -281,7 +283,7 @@ func TestStringSpanID(t *testing.T) {
},
} {
t.Run(testcase.name, func(t *testing.T) {
//proto: func (t TraceID) String() string {}
// proto: func (t TraceID) String() string {}
have := testcase.sid.String()
if have != testcase.want {
t.Errorf("Want: %s, but have: %s", testcase.want, have)
Expand Down Expand Up @@ -1023,3 +1025,29 @@ func TestSpanContextDerivation(t *testing.T) {
t.Fatalf("WithTraceState: Unexpected context created: %s", cmp.Diff(modified, to))
}
}

func TestTraceLinkMarshalJSON(t *testing.T) {
link := Link{
SpanContext: SpanContext{
traceID: TraceID([16]byte{1}),
spanID: SpanID([8]byte{42}),
traceFlags: 0x0,
traceState: TraceState{},
},
Attributes: []attribute.KeyValue{
attribute.String("foo", "8"),
attribute.String("bar", "22"),
},
DroppedAttributeCount: 1,
}

expected := "{\"SpanContext\":{\"TraceID\":\"01000000000000000000000000000000\",\"SpanID\":\"2a00000000000000\",\"TraceFlags\":\"00\",\"TraceState\":null,\"Remote\":false},\"Attributes\":[{\"Key\":\"foo\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"8\"}},{\"Key\":\"bar\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"22\"}}],\"DroppedAttributeCount\":1}"

m, err := json.Marshal(link)
if err != nil {
t.Fatalf("Link MarshalJSON() err: %v", err)
}
if !bytes.Equal(m, []byte(expected)) {
t.Errorf("Link MarshalJSON() expected %s, got %s", expected, string(m))
}
}