From 891393b6b73546e4795bdee100b842f48a89cd8b Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Wed, 21 Aug 2019 17:29:20 +0200 Subject: [PATCH 1/3] Add an extension interface for Tracer implementations The new TracerContextWithSpanExtension interface provides a way to hook into the ContextWithSpan function, so the implementation can put some extra information to the context. The opentracing to opentelemetry bridge needs the context to set the current opentelemetry span, so the opentelemetry API in the layer below the one using opentracing can still get the right parent span. --- ext.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 ext.go 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 +} From c848a0f0b804b94dd7757a7a9374a1bc258d9a8f Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Wed, 21 Aug 2019 17:33:44 +0200 Subject: [PATCH 2/3] Call the hook in the ContextWithSpan function if possible So the implementation can still affect the way the go context is set up. --- gocontext.go | 3 +++ 1 file changed, 3 insertions(+) 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) } From 60fbc0831c30de5b8fe54099de6da3c70f92bed5 Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Wed, 21 Aug 2019 17:39:20 +0200 Subject: [PATCH 3/3] Add a test for the TracerContextWithSpanExtension interface --- gocontext_test.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) 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{}