diff --git a/ext.go b/ext.go new file mode 100644 index 0000000..e11977e --- /dev/null +++ b/ext.go @@ -0,0 +1,24 @@ +package opentracing + +import ( + "context" +) + +// TracerContextWithSpanExtension is an extension interface that the +// implementation of the Tracer interface may want to implement. It +// allows to have some control over the go context when the +// ContextWithSpan is invoked. +// +// The primary purpose of this extension are adapters from opentracing +// API to some other tracing API. +type TracerContextWithSpanExtension interface { + // ContextWithSpanHook gets called by the ContextWithSpan + // function, when the Tracer implementation also implements + // this interface. It allows to put extra information into the + // context and make it available to the callers of the + // ContextWithSpan. + // + // This hook is invoked before the ContextWithSpan function + // actually puts the span into the context. + ContextWithSpanHook(ctx context.Context, span Span) context.Context +} diff --git a/gocontext.go b/gocontext.go index 08c00c0..8865e75 100644 --- a/gocontext.go +++ b/gocontext.go @@ -9,6 +9,9 @@ var activeSpanKey = contextKey{} // ContextWithSpan returns a new `context.Context` that holds a reference to // `span`'s SpanContext. func ContextWithSpan(ctx context.Context, span Span) context.Context { + if tracerWithHook, ok := span.Tracer().(TracerContextWithSpanExtension); ok { + ctx = tracerWithHook.ContextWithSpanHook(ctx, span) + } return context.WithValue(ctx, activeSpanKey, span) } diff --git a/gocontext_test.go b/gocontext_test.go index 65ca1c4..a5b1aed 100644 --- a/gocontext_test.go +++ b/gocontext_test.go @@ -29,6 +29,41 @@ func TestContextWithSpan(t *testing.T) { } } +type noopExtTracer struct { + NoopTracer +} + +type noopExtTracerCtxType struct{} + +func (noopExtTracer) ContextWithSpanHook(ctx context.Context, span Span) context.Context { + return context.WithValue(ctx, noopExtTracerCtxType{}, noopExtTracerCtxType{}) +} + +var _ Tracer = noopExtTracer{} +var _ TracerContextWithSpanExtension = noopExtTracer{} + +type noopExtSpan struct { + noopSpan +} + +func (noopExtSpan) Tracer() Tracer { + return noopExtTracer{} +} + +var _ Span = noopExtSpan{} + +func TestContextWithSpanWithExtension(t *testing.T) { + span := &noopExtSpan{} + ctx := ContextWithSpan(context.Background(), span) + span2 := SpanFromContext(ctx) + if span != span2 { + t.Errorf("Not the same span returned from context, expected=%+v, actual=%+v", span, span2) + } + if _, ok := ctx.Value(noopExtTracerCtxType{}).(noopExtTracerCtxType); !ok { + t.Error("ContextWithSpanHook was not called") + } +} + func TestStartSpanFromContext(t *testing.T) { testTracer := testTracer{}