Skip to content
This repository has been archived by the owner on May 23, 2024. It is now read-only.

Upgrade to OpenTracing API with SpanContext #20

Merged
merged 7 commits into from
Jul 9, 2016
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
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ THRIFT=docker run -v "${PWD}:/data" $(THRIFT_IMG) thrift
THRIFT_GO_ARGS=thrift_import="github.com/apache/thrift/lib/go/thrift"
THRIFT_GEN_DIR=thrift-gen

PASS=$(shell printf "\033[32mPASS\033[0m")
FAIL=$(shell printf "\033[31mFAIL\033[0m")
COLORIZE=sed ''/PASS/s//$(PASS)/'' | sed ''/FAIL/s//$(FAIL)/''

.PHONY: test
test:
$(GOTEST) $(PACKAGES)

$(GOTEST) $(PACKAGES) | $(COLORIZE)

.PHONY: fmt
fmt:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ this interface can be set on the `Config` object before calling the

Since this tracer is fully compliant with OpenTracing API 1.0,
all code instrumentation should only use the API itself, as described
in [opentracing-go]
in the [opentracing-go]
(https://github.com/opentracing/opentracing-go) documentation.

## Features
Expand Down
3 changes: 2 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ func (c Configuration) New(
serviceName,
sampler,
reporter,
jaeger.TracerOptions.Metrics(metrics))
jaeger.TracerOptions.Metrics(metrics),
jaeger.TracerOptions.Logger(c.Logger))

return tracer, closer, nil
}
Expand Down
97 changes: 79 additions & 18 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import (
"fmt"
"strconv"
"strings"
"sync"

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

const (
Expand All @@ -37,8 +40,10 @@ var (
errMalformedTracerStateString = errors.New("String does not match tracer state format")
)

// TraceContext represents propagated span identity and state
type TraceContext struct {
// SpanContext represents propagated span identity and state
type SpanContext struct {
sync.RWMutex

// traceID represents globally unique ID of the trace.
// Usually generated as a random number.
traceID uint64
Expand All @@ -53,70 +58,126 @@ type TraceContext struct {

// flags is a bitmap containing such bits as 'sampled' and 'debug'.
flags byte

// Distributed Context baggage
baggage map[string]string
}

// SetBaggageItem implements SetBaggageItem() of opentracing.SpanContext
func (c *SpanContext) SetBaggageItem(key, value string) opentracing.SpanContext {
key = normalizeBaggageKey(key)
c.Lock()
defer c.Unlock()
if c.baggage == nil {
c.baggage = make(map[string]string)
}
c.baggage[key] = value
return c
}

// BaggageItem implements BaggageItem() of opentracing.SpanContext
func (c *SpanContext) BaggageItem(key string) string {
key = normalizeBaggageKey(key)
c.RLock()
defer c.RUnlock()
return c.baggage[key]
}

// ForeachBaggageItem implements ForeachBaggageItem() of opentracing.SpanContext
func (c *SpanContext) ForeachBaggageItem(handler func(k, v string) bool) {
c.RLock()
defer c.RUnlock()
for k, v := range c.baggage {
if !handler(k, v) {
break
}
}
}

// IsSampled returns whether this trace was chosen for permanent storage
// by the sampling mechanism of the tracer.
func (c *TraceContext) IsSampled() bool {
func (c *SpanContext) IsSampled() bool {
return (c.flags & flagSampled) == flagSampled
}

func (c *TraceContext) String() string {
func (c *SpanContext) String() string {
return fmt.Sprintf("%x:%x:%x:%x", c.traceID, c.spanID, c.parentID, c.flags)
}

// ContextFromString reconstructs the Context encoded in a string
func ContextFromString(value string) (TraceContext, error) {
var context TraceContext
func ContextFromString(value string) (*SpanContext, error) {
var context = new(SpanContext)
if value == "" {
return context, errEmptyTracerStateString
return nil, errEmptyTracerStateString
}
parts := strings.Split(value, ":")
if len(parts) != 4 {
return context, errMalformedTracerStateString
return nil, errMalformedTracerStateString
}
var err error
if context.traceID, err = strconv.ParseUint(parts[0], 16, 64); err != nil {
return context, err
return nil, err
}
if context.spanID, err = strconv.ParseUint(parts[1], 16, 64); err != nil {
return context, err
return nil, err
}
if context.parentID, err = strconv.ParseUint(parts[2], 16, 64); err != nil {
return context, err
return nil, err
}
flags, err := strconv.ParseUint(parts[3], 10, 8)
if err != nil {
return context, err
return nil, err
}
context.flags = byte(flags)
return context, nil
}

// TraceID implements TraceID() of SpanID
func (c TraceContext) TraceID() uint64 {
func (c *SpanContext) TraceID() uint64 {
return c.traceID
}

// SpanID implements SpanID() of SpanID
func (c TraceContext) SpanID() uint64 {
func (c *SpanContext) SpanID() uint64 {
return c.spanID
}

// ParentID implements ParentID() of SpanID
func (c TraceContext) ParentID() uint64 {
func (c *SpanContext) ParentID() uint64 {
return c.parentID
}

// NewTraceContext creates a new instance of TraceContext
func NewTraceContext(traceID, spanID, parentID uint64, sampled bool) *TraceContext {
// NewSpanContext creates a new instance of SpanContext
func NewSpanContext(traceID, spanID, parentID uint64, sampled bool) *SpanContext {
flags := byte(0)
if sampled {
flags = flagSampled
}
return &TraceContext{
return &SpanContext{
traceID: traceID,
spanID: spanID,
parentID: parentID,
flags: flags}
}

// CopyFrom copies data from ctx into this context, including span identity and baggage.
func (c *SpanContext) CopyFrom(ctx *SpanContext) {
c.Lock()
defer c.Unlock()

ctx.RLock()
defer ctx.RUnlock()

c.traceID = ctx.traceID
c.spanID = ctx.spanID
c.parentID = ctx.parentID
c.flags = ctx.flags
if l := len(ctx.baggage); l > 0 {
c.baggage = make(map[string]string, l)
for k, v := range ctx.baggage {
c.baggage[k] = v
}
} else {
c.baggage = nil
}
}
2 changes: 1 addition & 1 deletion context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestContextFromString(t *testing.T) {
assert.EqualValues(t, 1, ctx.spanID)
assert.EqualValues(t, 1, ctx.parentID)
assert.EqualValues(t, 1, ctx.flags)
ctx = *NewTraceContext(1, 1, 1, true)
ctx = NewSpanContext(1, 1, 1, true)
assert.EqualValues(t, 1, ctx.traceID)
assert.EqualValues(t, 1, ctx.spanID)
assert.EqualValues(t, 1, ctx.parentID)
Expand Down
6 changes: 3 additions & 3 deletions crossdock/common/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ func injectSpan(ctx context.Context, req *http.Request) (opentracing.Span, error
if span == nil {
return nil, nil
}
span = opentracing.StartChildSpan(span, "post")
ext.SpanKind.Set(span, ext.SpanKindRPCClient)
span = span.Tracer().StartSpan("post", opentracing.ChildOf(span.Context()))
ext.SpanKindRPCClient.Set(span)
c := opentracing.HTTPHeaderTextMapCarrier(req.Header)
err := span.Tracer().Inject(span, opentracing.TextMap, c)
err := span.Tracer().Inject(span.Context(), opentracing.TextMap, c)
return span, err
}
12 changes: 4 additions & 8 deletions crossdock/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,18 +126,14 @@ func (s *Server) handleJSON(
newReq func() interface{},
handle func(ctx context.Context, req interface{}) (interface{}, error),
) {
span, err := s.Tracer.Join("post", opentracing.TextMap, opentracing.HTTPHeaderTextMapCarrier(r.Header))
if err != nil && err != opentracing.ErrTraceNotFound {
spanCtx, err := s.Tracer.Extract(opentracing.TextMap, opentracing.HTTPHeaderTextMapCarrier(r.Header))
if err != nil && err != opentracing.ErrSpanContextNotFound {
http.Error(w, fmt.Sprintf("Cannot read request body: %+v", err), http.StatusBadRequest)
return
}
if span != nil {
ext.SpanKind.Set(span, ext.SpanKindRPCServer)
}
span := s.Tracer.StartSpan("post", ext.RPCServerOption(spanCtx))
ctx := opentracing.ContextWithSpan(context.Background(), span)
if span != nil {
defer span.Finish()
}
defer span.Finish()

body, err := ioutil.ReadAll(r.Body)
if err != nil {
Expand Down
22 changes: 12 additions & 10 deletions crossdock/server/tchannel.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"time"

"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"github.com/uber/tchannel-go"
"github.com/uber/tchannel-go/thrift"
"golang.org/x/net/context"
Expand Down Expand Up @@ -115,15 +116,15 @@ func convertOpenTracingSpan(ctx context.Context, builder *tchannel.ContextBuilde
if span == nil {
return
}
carrier := &jaeger.TraceContextCarrier{}
if err := span.Tracer().Inject(span, jaeger.TraceContextFormat, carrier); err != nil {
sc := new(jaeger.SpanContext)
if err := span.Tracer().Inject(span.Context(), jaeger.TraceContextFormat, sc); err != nil {
return
}
sc := carrier.TraceContext
builder.SetExternalSpan(sc.TraceID(), sc.SpanID(), sc.ParentID(), sc.IsSampled())
for k, v := range carrier.Baggage {
sc.ForeachBaggageItem(func(k, v string) bool {
builder.AddHeader(k, v)
}
return true
})
}

// setupOpenTracingContext extracts a TChannel tracing Span from the context, converts
Expand All @@ -143,15 +144,16 @@ func setupOpenTracingContext(tracer opentracing.Tracer, ctx context.Context, met
tSpan := tchannel.CurrentSpan(ctx)
if tSpan != nil {
// populate a fake carrier and try to create OpenTracing Span
carrier := &jaeger.TraceContextCarrier{Baggage: headers}
carrier.TraceContext = *jaeger.NewTraceContext(
sc := jaeger.NewSpanContext(
tSpan.TraceID(), tSpan.SpanID(), tSpan.ParentID(), tSpan.TracingEnabled())
for k, v := range headers {
sc.SetBaggageItem(k, v)
}
if tracer == nil {
tracer = opentracing.GlobalTracer()
}
if span, err := tracer.Join(method, jaeger.TraceContextFormat, carrier); err == nil {
ctx = opentracing.ContextWithSpan(ctx, span)
}
span := tracer.StartSpan(method, ext.RPCServerOption(sc))
ctx = opentracing.ContextWithSpan(ctx, span)
}
return thrift.WithHeaders(ctx, headers)
}
13 changes: 5 additions & 8 deletions crossdock/server/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (s *Server) doStartTrace(req *tracetest.StartTraceRequest) (*tracetest.Trac
if req.Sampled {
ext.SamplingPriority.Set(span, 1)
}
span.SetBaggageItem(BaggageKey, req.Baggage)
span.Context().SetBaggageItem(BaggageKey, req.Baggage)
defer span.Finish()

ctx := opentracing.ContextWithSpan(context.Background(), span)
Expand Down Expand Up @@ -98,13 +98,10 @@ func observeSpan(ctx context.Context, tracer opentracing.Tracer) (*tracetest.Obs
if span == nil {
return nil, errNoSpanObserved
}
c := jaeger.TraceContextCarrier{}
if err := tracer.Inject(span, jaeger.TraceContextFormat, &c); err != nil {
return nil, err
}
sc := span.Context().(*jaeger.SpanContext)
observedSpan := tracetest.NewObservedSpan()
observedSpan.TraceId = fmt.Sprintf("%x", c.TraceContext.TraceID())
observedSpan.Sampled = c.TraceContext.IsSampled()
observedSpan.Baggage = span.BaggageItem(BaggageKey)
observedSpan.TraceId = fmt.Sprintf("%x", sc.TraceID())
observedSpan.Sampled = sc.IsSampled()
observedSpan.Baggage = sc.BaggageItem(BaggageKey)
return observedSpan, nil
}
6 changes: 3 additions & 3 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import:
subpackages:
- lib/go/thrift
- package: github.com/opentracing/opentracing-go
version: d5b9be1fcf7d467664d3b8f9cb4f3c8c5ac0a753
version: 4281ca32dbd11726bca3581fc06a9bc94365ec85
subpackages:
- ext
- package: golang.org/x/net
Expand Down
Loading