Skip to content
This repository has been archived by the owner on Dec 20, 2021. It is now read-only.

Transcribe attributes from span links to events #96

Merged
merged 1 commit into from
Dec 28, 2020
Merged
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
42 changes: 22 additions & 20 deletions honeycomb/honeycomb.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/honeycombio/libhoney-go/transmission"

"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/label"
"go.opentelemetry.io/otel/sdk/export/trace"
)

Expand Down Expand Up @@ -328,6 +329,12 @@ const (
traceIDLongLength = 16
)

func transcribeAttributesTo(ev *libhoney.Event, attrs []label.KeyValue) {
for _, kv := range attrs {
ev.AddField(string(kv.Key), kv.Value.AsInterface())
}
}

// span is the format of trace events that Honeycomb accepts.
type span struct {
TraceID string `json:"trace.trace_id"`
Expand Down Expand Up @@ -496,35 +503,29 @@ func (e *Exporter) exportSpan(ctx context.Context, data *trace.SpanData) {

applyResourceAttributes := func(ev *libhoney.Event) {
if data.Resource != nil {
for _, kv := range data.Resource.Attributes() {
ev.AddField(string(kv.Key), kv.Value.AsInterface())
}
transcribeAttributesTo(ev, data.Resource.Attributes())
}
if len(e.serviceName) != 0 {
ev.AddField("service_name", e.serviceName)
}
}
transcribeLayeredAttributesTo := func(ev *libhoney.Event, attrs []label.KeyValue) {
// Treat resource-defined attributes as underlays, with any same-keyed message event
// attributes taking precedence. Apply them first.
applyResourceAttributes(ev)
transcribeAttributesTo(ev, attrs)
}

// Treat resource-defined attributes as underlays, with any same-keyed span attributes taking
// precedence. Apply them first.
applyResourceAttributes(ev)
if len(e.serviceName) != 0 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove adding service_nameto the event here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See lines 508-511 above. It still happens as part of the call to applyResourceAttributes at line 521.

ev.AddField("service_name", e.serviceName)
}

ev.Timestamp = data.StartTime
ev.Add(honeycombSpan(data))

// We send these message events as zero-duration spans.
for _, a := range data.MessageEvents {
spanEv := e.client.NewEvent()
// Treat resource-defined attributes as underlays, with any same-keyed message event
// attributes taking precedence. Apply them first.
applyResourceAttributes(spanEv)
if len(e.serviceName) != 0 {
spanEv.AddField("service_name", e.serviceName)
}

for _, kv := range a.Attributes {
spanEv.AddField(string(kv.Key), kv.Value.AsInterface())
}
transcribeLayeredAttributesTo(spanEv, a.Attributes)
spanEv.Timestamp = a.Time

spanEv.Add(spanEvent{
Expand All @@ -540,7 +541,8 @@ func (e *Exporter) exportSpan(ctx context.Context, data *trace.SpanData) {
}

// link represents a link to a trace and span that lives elsewhere.
// TraceID and ParentID are used to identify the span with which the trace is associated
//
// TraceID and ParentID are used to identify the span with which the trace is associated.
// We are modeling Links for now as child spans rather than properties of the event.
type link struct {
TraceID string `json:"trace.trace_id"`
Expand All @@ -553,6 +555,8 @@ func (e *Exporter) exportSpan(ctx context.Context, data *trace.SpanData) {

for _, spanLink := range data.Links {
linkEv := e.client.NewEvent()
transcribeLayeredAttributesTo(linkEv, spanLink.Attributes)

linkEv.Add(link{
TraceID: getHoneycombTraceID(data.SpanContext.TraceID[:]),
ParentID: data.SpanContext.SpanID.String(),
Expand All @@ -562,8 +566,6 @@ func (e *Exporter) exportSpan(ctx context.Context, data *trace.SpanData) {
// TODO(akvanhar): properly set the reference type when specs are defined
// see https://github.com/open-telemetry/opentelemetry-specification/issues/65
RefType: spanRefTypeChildOf,

// TODO(akvanhar) add support for link.Attributes
})
if err := linkEv.Send(); err != nil {
e.onError(err)
Expand Down
20 changes: 18 additions & 2 deletions honeycomb/honeycomb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,15 +347,26 @@ func TestHoneycombOutputWithLinks(t *testing.T) {
mockHoneycomb := &transmission.MockSender{}
assert := assert.New(t)

tr, err := setUpTestExporter(mockHoneycomb)
exporter, err := makeTestExporter(mockHoneycomb)
assert.Nil(err)
assert.NotNil(exporter)

tr, err := setUpTestProvider(exporter,
sdktrace.WithResource(resource.NewWithAttributes(
label.Int("zero", 0),
label.Int("one", 99), // NB: Deliberately not 1, to be overwritten later.
)))
assert.Nil(err)

_, span := tr.Start(context.TODO(), "myTestSpan", apitrace.WithLinks(apitrace.Link{
SpanContext: apitrace.SpanContext{
TraceID: linkTraceID,
SpanID: linkSpanID,
},
Attributes: nil,
Attributes: []label.KeyValue{
label.Int("one", 1),
label.Int("two", 2),
},
}))

span.End()
Expand All @@ -381,6 +392,10 @@ func TestHoneycombOutputWithLinks(t *testing.T) {
assert.Equal("0102030405060709", hclinkSpanID)
linkAnnotationType := linkFields["meta.annotation_type"]
assert.Equal("link", linkAnnotationType)

assert.Equal(int64(0), linkFields["zero"])
assert.Equal(int64(1), linkFields["one"])
assert.Equal(int64(2), linkFields["two"])
}

func TestHoneycombConfigValidation(t *testing.T) {
Expand Down Expand Up @@ -652,6 +667,7 @@ func TestHoneycombOutputWithResource(t *testing.T) {
label.Int64("a", middle),
label.Int64("c", middle),
)))
assert.Nil(err)

_, span := tr.Start(context.TODO(), "myTestSpan")
assert.Nil(err)
Expand Down