Skip to content

Commit

Permalink
Merge pull request #103 from instana/type_dependent_span_kinds
Browse files Browse the repository at this point in the history
Refactor span kind detection
  • Loading branch information
Andrew Slotin authored Apr 7, 2020
2 parents aa3857f + b68b4b2 commit be8a329
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 110 deletions.
8 changes: 4 additions & 4 deletions instrumentation/instagrpc/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func TestUnaryClientInterceptor(t *testing.T) {
require.NoError(t, err)

assert.Equal(t, "rpc-client", span.Name)
assert.Equal(t, 2, span.Kind)
assert.EqualValues(t, instana.ExitSpanKind, span.Kind)
assert.Equal(t, 0, span.Ec)

host, port, err := net.SplitHostPort(addr)
Expand Down Expand Up @@ -121,7 +121,7 @@ func TestUnaryClientInterceptor_ErrorHandling(t *testing.T) {
require.NoError(t, err)

assert.Equal(t, "rpc-client", span.Name)
assert.Equal(t, 2, span.Kind)
assert.EqualValues(t, instana.ExitSpanKind, span.Kind)
assert.Equal(t, 1, span.Ec)

assert.Equal(t, serverErr.Error(), span.Data.RPC.Error)
Expand Down Expand Up @@ -186,7 +186,7 @@ func TestStreamClientInterceptor(t *testing.T) {
require.NoError(t, err)

assert.Equal(t, "rpc-client", span.Name)
assert.Equal(t, 2, span.Kind)
assert.EqualValues(t, instana.ExitSpanKind, span.Kind)
assert.Equal(t, 0, span.Ec)

host, port, err := net.SplitHostPort(addr)
Expand Down Expand Up @@ -255,7 +255,7 @@ func TestStreamClientInterceptor_ErrorHandling(t *testing.T) {
require.NoError(t, err)

assert.Equal(t, "rpc-client", span.Name)
assert.Equal(t, 2, span.Kind)
assert.EqualValues(t, instana.ExitSpanKind, span.Kind)
assert.Equal(t, 1, span.Ec)

assert.Equal(t, serverErr.Error(), span.Data.RPC.Error)
Expand Down
12 changes: 6 additions & 6 deletions instrumentation/instagrpc/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestUnaryServerInterceptor(t *testing.T) {
require.NoError(t, err)

assert.Equal(t, "rpc-server", span.Name)
assert.Equal(t, 1, span.Kind)
assert.EqualValues(t, instana.EntrySpanKind, span.Kind)
assert.Equal(t, 0, span.Ec)

host, port, err := net.SplitHostPort(addr)
Expand Down Expand Up @@ -127,7 +127,7 @@ func TestUnaryServerInterceptor_ErrorHandling(t *testing.T) {
require.NoError(t, err)

assert.Equal(t, "rpc-server", span.Name)
assert.Equal(t, 1, span.Kind)
assert.EqualValues(t, instana.EntrySpanKind, span.Kind)
assert.Equal(t, 1, span.Ec)

assert.Equal(t, serverErr.Error(), span.Data.RPC.Error)
Expand Down Expand Up @@ -159,7 +159,7 @@ func TestUnaryServerInterceptor_PanicHandling(t *testing.T) {
require.NoError(t, err)

assert.Equal(t, "rpc-server", span.Name)
assert.Equal(t, 1, span.Kind)
assert.EqualValues(t, instana.EntrySpanKind, span.Kind)
assert.Equal(t, 1, span.Ec)

assert.Equal(t, "something went wrong", span.Data.RPC.Error)
Expand Down Expand Up @@ -201,7 +201,7 @@ func TestStreamServerInterceptor(t *testing.T) {
require.NoError(t, err)

assert.Equal(t, "rpc-server", span.Name)
assert.Equal(t, 1, span.Kind)
assert.EqualValues(t, instana.EntrySpanKind, span.Kind)
assert.Equal(t, 0, span.Ec)

host, port, err := net.SplitHostPort(addr)
Expand Down Expand Up @@ -292,7 +292,7 @@ func TestStreamServerInterceptor_ErrorHandling(t *testing.T) {
require.NoError(t, err)

assert.Equal(t, "rpc-server", span.Name)
assert.Equal(t, 1, span.Kind)
assert.EqualValues(t, instana.EntrySpanKind, span.Kind)
assert.Equal(t, 1, span.Ec)

assert.Equal(t, serverErr.Error(), span.Data.RPC.Error)
Expand Down Expand Up @@ -331,7 +331,7 @@ func TestStreamServerInterceptor_PanicHandling(t *testing.T) {
require.NoError(t, err)

assert.Equal(t, "rpc-server", span.Name)
assert.Equal(t, 1, span.Kind)
assert.EqualValues(t, instana.EntrySpanKind, span.Kind)
assert.Equal(t, 1, span.Ec)

assert.Equal(t, "something went wrong", span.Data.RPC.Error)
Expand Down
12 changes: 6 additions & 6 deletions instrumentation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestTracingHandlerFunc_Write(t *testing.T) {

span := spans[0]
assert.Equal(t, 0, span.Ec)
assert.Equal(t, 1, span.Kind)
assert.EqualValues(t, instana.EntrySpanKind, span.Kind)

require.IsType(t, instana.HTTPSpanData{}, span.Data)
data := span.Data.(instana.HTTPSpanData)
Expand Down Expand Up @@ -74,7 +74,7 @@ func TestTracingHandlerFunc_WriteHeaders(t *testing.T) {

span := spans[0]
assert.Equal(t, 0, span.Ec)
assert.Equal(t, 1, span.Kind)
assert.EqualValues(t, instana.EntrySpanKind, span.Kind)

require.IsType(t, instana.HTTPSpanData{}, span.Data)
data := span.Data.(instana.HTTPSpanData)
Expand Down Expand Up @@ -105,7 +105,7 @@ func TestTracingHandlerFunc_PanicHandling(t *testing.T) {

span := spans[0]
assert.Equal(t, 1, span.Ec)
assert.Equal(t, 1, span.Kind)
assert.EqualValues(t, instana.EntrySpanKind, span.Kind)

require.IsType(t, instana.HTTPSpanData{}, span.Data)
data := span.Data.(instana.HTTPSpanData)
Expand Down Expand Up @@ -142,7 +142,7 @@ func TestRoundTripper(t *testing.T) {

span := spans[0]
assert.Equal(t, 0, span.Ec)
assert.Equal(t, 2, span.Kind)
assert.EqualValues(t, instana.ExitSpanKind, span.Kind)

require.IsType(t, instana.HTTPSpanData{}, span.Data)
data := span.Data.(instana.HTTPSpanData)
Expand Down Expand Up @@ -213,7 +213,7 @@ func TestRoundTripper_Error(t *testing.T) {

span := spans[0]
assert.Equal(t, 1, span.Ec)
assert.Equal(t, 2, span.Kind)
assert.EqualValues(t, instana.ExitSpanKind, span.Kind)

require.IsType(t, instana.HTTPSpanData{}, span.Data)
data := span.Data.(instana.HTTPSpanData)
Expand Down Expand Up @@ -253,7 +253,7 @@ func TestRoundTripper_DefaultTransport(t *testing.T) {

span := spans[0]
assert.Equal(t, 0, span.Ec)
assert.Equal(t, 2, span.Kind)
assert.EqualValues(t, instana.ExitSpanKind, span.Kind)

require.IsType(t, instana.HTTPSpanData{}, span.Data)
data := span.Data.(instana.HTTPSpanData)
Expand Down
79 changes: 73 additions & 6 deletions json_span.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package instana

import "github.com/opentracing/opentracing-go/ext"
import (
"time"

"github.com/opentracing/opentracing-go/ext"
)

type typedSpanData interface {
Type() RegisteredSpanType
Kind() SpanKind
}

// Registered types supported by Instana. The span type is determined based on
Expand Down Expand Up @@ -45,6 +50,33 @@ func (st RegisteredSpanType) ExtractData(span *spanS) typedSpanData {
}
}

// SpanKind represents values of field `k` in OpenTracing span representation. It represents
// the direction of the call associated with a span.
type SpanKind uint8

// Valid span kinds
const (
// The kind of a span associated with an inbound call, this must be the first span in the trace.
EntrySpanKind SpanKind = iota + 1
// The kind of a span associated with an outbound call, e.g. an HTTP client request, posting to a message bus, etc.
ExitSpanKind
// The default kind for a span that is associated with a call within the same service.
IntermediateSpanKind
)

// String returns string representation of a span kind suitable for use as a value for `data.sdk.type`
// tag of an SDK span. By default all spans are intermediate unless they are explicitly set to be "entry" or "exit"
func (k SpanKind) String() string {
switch k {
case EntrySpanKind:
return "entry"
case ExitSpanKind:
return "exit"
default:
return "intermediate"
}
}

// Span represents the OpenTracing span document to be sent to the agent
type Span struct {
TraceID int64 `json:"t"`
Expand All @@ -64,13 +96,15 @@ type Span struct {
type SpanData struct {
Service string `json:"service,omitempty"`
st RegisteredSpanType
sk interface{}
}

// NewSpanData initializes a new span data from tracer span
func NewSpanData(span *spanS, st RegisteredSpanType) SpanData {
return SpanData{
Service: span.Service,
st: st,
sk: span.Tags[string(ext.SpanKind)],
}
}

Expand All @@ -79,6 +113,23 @@ func (d SpanData) Type() RegisteredSpanType {
return d.st
}

// Kind returns the kind of the span. It handles the github.com/opentracing/opentracing-go/ext.SpanKindEnum
// values as well as generic "entry" and "exit"
func (d SpanData) Kind() SpanKind {
switch d.sk {
case ext.SpanKindRPCServerEnum, string(ext.SpanKindRPCServerEnum),
ext.SpanKindConsumerEnum, string(ext.SpanKindConsumerEnum),
"entry":
return EntrySpanKind
case ext.SpanKindRPCClientEnum, string(ext.SpanKindRPCClientEnum),
ext.SpanKindProducerEnum, string(ext.SpanKindProducerEnum),
"exit":
return ExitSpanKind
default:
return IntermediateSpanKind
}
}

// SDKSpanData represents the `data` section of an SDK span sent within an OT span document
type SDKSpanData struct {
SpanData
Expand All @@ -87,9 +138,10 @@ type SDKSpanData struct {

// NewSDKSpanData initializes a new SDK span data from tracer span
func NewSDKSpanData(span *spanS) SDKSpanData {
d := NewSpanData(span, SDKSpanType)
return SDKSpanData{
SpanData: NewSpanData(span, SDKSpanType),
Tags: NewSDKSpanTags(span),
SpanData: d,
Tags: NewSDKSpanTags(span, d.Kind().String()),
}
}

Expand All @@ -103,18 +155,18 @@ type SDKSpanTags struct {
}

// NewSDKSpanTags extracts SDK span tags from a tracer span
func NewSDKSpanTags(span *spanS) SDKSpanTags {
func NewSDKSpanTags(span *spanS, spanType string) SDKSpanTags {
tags := SDKSpanTags{
Name: span.Operation,
Type: span.Kind().String(),
Type: spanType,
Custom: map[string]interface{}{},
}

if len(span.Tags) != 0 {
tags.Custom["tags"] = span.Tags
}

if logs := span.collectLogs(); len(logs) > 0 {
if logs := collectTracerSpanLogs(span); len(logs) > 0 {
tags.Custom["logs"] = logs
}

Expand Down Expand Up @@ -313,3 +365,18 @@ func readIntTag(dst *int, tag interface{}) {
*dst = int(n)
}
}

func collectTracerSpanLogs(span *spanS) map[uint64]map[string]interface{} {
logs := make(map[uint64]map[string]interface{})
for _, l := range span.Logs {
if _, ok := logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)]; !ok {
logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)] = make(map[string]interface{})
}

for _, f := range l.Fields {
logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)][f.Key()] = f.Value()
}
}

return logs
}
30 changes: 30 additions & 0 deletions json_span_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,33 @@ func TestRegisteredSpanType_ExtractData(t *testing.T) {
})
}
}

func TestSpanKind_String(t *testing.T) {
examples := map[string]struct {
Kind instana.SpanKind
Expected string
}{
"entry": {
Kind: instana.EntrySpanKind,
Expected: "entry",
},
"exit": {
Kind: instana.ExitSpanKind,
Expected: "exit",
},
"intermediate": {
Kind: instana.IntermediateSpanKind,
Expected: "intermediate",
},
"unknown": {
Kind: instana.SpanKind(0),
Expected: "intermediate",
},
}

for name, example := range examples {
t.Run(name, func(t *testing.T) {
assert.Equal(t, example.Expected, example.Kind.String())
})
}
}
2 changes: 1 addition & 1 deletion recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (r *Recorder) RecordSpan(span *spanS) {
Name: string(data.Type()),
Ec: span.ErrorCount,
From: sensor.agent.from,
Kind: int(span.Kind()),
Kind: int(data.Kind()),
Data: data,
})

Expand Down
36 changes: 0 additions & 36 deletions recorder_internal_test.go

This file was deleted.

Loading

0 comments on commit be8a329

Please sign in to comment.