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

Commit

Permalink
Support "Self" Span Reference (#411)
Browse files Browse the repository at this point in the history
* POC: Self Referenced Span

refs #397

Signed-off-by: Daniel Mican <[email protected]>

* Self Ref Span: Moves SelfRef -> constants

Signed-off-by: Daniel Mican <[email protected]>

* SelfRef: removes extra pointer

Signed-off-by: Daniel Mican <[email protected]>

* SelfRef: README

Signed-off-by: Daniel Mican <[email protected]>

* SelfRef: README

Signed-off-by: Daniel Mican <[email protected]>

* SelfRef: startSpan unit test

Signed-off-by: Daniel Mican <[email protected]>

* SelfRef: startSpanWithOptions check for selRef before tracking references.

Provides a selfRef factory method hidningn constant/implementation details

Signed-off-by: Daniel Mican <[email protected]>

* SelfRef: Lint

Signed-off-by: Daniel Mican <[email protected]>

* SelfRef: README update

Signed-off-by: Daniel Mican <[email protected]>

* SelfRef: Rebuild, github timeout

Signed-off-by: Daniel Mican <[email protected]>

* SelfRef: Rebuild

Signed-off-by: Daniel Mican <[email protected]>
  • Loading branch information
dm03514 authored and yurishkuro committed Aug 7, 2019
1 parent 944042e commit 201832f
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 37 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,24 @@ by a lot of Zipkin tracers. This means that you can use Jaeger in conjunction wi

However it is not the default propagation format, see [here](zipkin/README.md#NewZipkinB3HTTPHeaderPropagator) how to set it up.

## SelfRef

Jaeger Tracer supports an additional [reference](https://github.com/opentracing/specification/blob/1.1/specification.md#references-between-spans)
type call `Self`. This allows a caller to provide an already established `SpanContext`.
This allows loading and continuing spans/traces from offline (ie log-based) storage. The `Self` reference
bypasses trace and span id generation.


Usage requires passing in a `SpanContext` and the jaeger `Self` reference type:
```
span := tracer.StartSpan(
"continued_span",
SelfRef(yourSpanContext),
)
...
defer span.finish()
```

## License

[Apache 2.0 License](LICENSE).
Expand Down
6 changes: 6 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package jaeger

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

const (
// JaegerClientVersion is the version of the client library reported as Span tag.
JaegerClientVersion = "Go-2.16.1dev"
Expand Down Expand Up @@ -85,4 +87,8 @@ const (

// DefaultMaxTagValueLength is the default max length of byte array or string allowed in the tag value.
DefaultMaxTagValueLength = 256

// SelfRefType is a jaeger specific reference type that supports creating a span
// with an already defined context.
selfRefType opentracing.SpanReferenceType = 99
)
95 changes: 58 additions & 37 deletions tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,20 +222,30 @@ func (t *Tracer) startSpanWithOptions(
var references []Reference
var parent SpanContext
var hasParent bool // need this because `parent` is a value, not reference
var ctx SpanContext
var isSelfRef bool
for _, ref := range options.References {
ctx, ok := ref.ReferencedContext.(SpanContext)
ctxRef, ok := ref.ReferencedContext.(SpanContext)
if !ok {
t.logger.Error(fmt.Sprintf(
"Reference contains invalid type of SpanReference: %s",
reflect.ValueOf(ref.ReferencedContext)))
continue
}
if !isValidReference(ctx) {
if !isValidReference(ctxRef) {
continue
}

if ref.Type == selfRefType {
isSelfRef = true
ctx = ctxRef
continue
}
references = append(references, Reference{Type: ref.Type, Context: ctx})

references = append(references, Reference{Type: ref.Type, Context: ctxRef})

if !hasParent {
parent = ctx
parent = ctxRef
hasParent = ref.Type == opentracing.ChildOfRef
}
}
Expand All @@ -251,42 +261,43 @@ func (t *Tracer) startSpanWithOptions(
}

var samplerTags []Tag
var ctx SpanContext
newTrace := false
if !hasParent || !parent.IsValid() {
newTrace = true
ctx.traceID.Low = t.randomID()
if t.options.gen128Bit {
ctx.traceID.High = t.options.highTraceIDGenerator()
}
ctx.spanID = SpanID(ctx.traceID.Low)
ctx.parentID = 0
ctx.flags = byte(0)
if hasParent && parent.isDebugIDContainerOnly() && t.isDebugAllowed(operationName) {
ctx.flags |= (flagSampled | flagDebug)
samplerTags = []Tag{{key: JaegerDebugHeader, value: parent.debugID}}
} else if sampled, tags := t.sampler.IsSampled(ctx.traceID, operationName); sampled {
ctx.flags |= flagSampled
samplerTags = tags
}
} else {
ctx.traceID = parent.traceID
if rpcServer && t.options.zipkinSharedRPCSpan {
// Support Zipkin's one-span-per-RPC model
ctx.spanID = parent.spanID
ctx.parentID = parent.parentID
if !isSelfRef {
if !hasParent || !parent.IsValid() {
newTrace = true
ctx.traceID.Low = t.randomID()
if t.options.gen128Bit {
ctx.traceID.High = t.options.highTraceIDGenerator()
}
ctx.spanID = SpanID(ctx.traceID.Low)
ctx.parentID = 0
ctx.flags = byte(0)
if hasParent && parent.isDebugIDContainerOnly() && t.isDebugAllowed(operationName) {
ctx.flags |= (flagSampled | flagDebug)
samplerTags = []Tag{{key: JaegerDebugHeader, value: parent.debugID}}
} else if sampled, tags := t.sampler.IsSampled(ctx.traceID, operationName); sampled {
ctx.flags |= flagSampled
samplerTags = tags
}
} else {
ctx.spanID = SpanID(t.randomID())
ctx.parentID = parent.spanID
ctx.traceID = parent.traceID
if rpcServer && t.options.zipkinSharedRPCSpan {
// Support Zipkin's one-span-per-RPC model
ctx.spanID = parent.spanID
ctx.parentID = parent.parentID
} else {
ctx.spanID = SpanID(t.randomID())
ctx.parentID = parent.spanID
}
ctx.flags = parent.flags
}
ctx.flags = parent.flags
}
if hasParent {
// copy baggage items
if l := len(parent.baggage); l > 0 {
ctx.baggage = make(map[string]string, len(parent.baggage))
for k, v := range parent.baggage {
ctx.baggage[k] = v
if hasParent {
// copy baggage items
if l := len(parent.baggage); l > 0 {
ctx.baggage = make(map[string]string, len(parent.baggage))
for k, v := range parent.baggage {
ctx.baggage[k] = v
}
}
}
}
Expand Down Expand Up @@ -453,3 +464,13 @@ func (t *Tracer) setBaggage(sp *Span, key, value string) {
func (t *Tracer) isDebugAllowed(operation string) bool {
return t.debugThrottler.IsAllowed(operation)
}

// SelfRef creates an opentracing compliant SpanReference from a jaeger
// SpanContext. This is a factory function in order to encapsulate jaeger specific
// types.
func SelfRef(ctx SpanContext) opentracing.SpanReference {
return opentracing.SpanReference{
Type: selfRefType,
ReferencedContext: ctx,
}
}
18 changes: 18 additions & 0 deletions tracer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,24 @@ func (s *tracerSuite) TestRandomIDNotZero() {
rng.Seed(1) // for test coverage
}

func (s *tracerSuite) TestReferenceSelfUsesProvidedContext() {
ctx := NewSpanContext(
TraceID{
High: 1,
Low: 2,
},
SpanID(2),
SpanID(1),
false,
nil,
)
sp1 := s.tracer.StartSpan(
"continued_span",
SelfRef(ctx),
)
s.Equal(ctx, sp1.(*Span).context)
}

func TestTracerOptions(t *testing.T) {
t1, e := time.Parse(time.RFC3339, "2012-11-01T22:08:41+00:00")
assert.NoError(t, e)
Expand Down

0 comments on commit 201832f

Please sign in to comment.