Repository: open-telemetry/opentelemetry-go (go)

Issue:
SDK ignores "FollowsFrom" relationships
[Currently](https://github.com/open-telemetry/opentelemetry-go/blob/384b4bb86af69eed21dc9e29579894576be9ce50/sdk/trace/tracer.go#L50), the SDK only propagates the parent through the context or if the provided reference is explicitly set to `ChildOfRelationshipType`. `FollowsFromRelationshipType` parents thus get ignored, which seems unexpected.

Pull request:
Propagate `FollowsFrom` span relationships in SDK
[Closes #189]

Patch:
diff --git a/sdk/trace/tracer.go b/sdk/trace/tracer.go
index fd54c362..098bd614 100644
--- a/sdk/trace/tracer.go
+++ b/sdk/trace/tracer.go
@@ -39,17 +39,15 @@ func (tr *tracer) Start(ctx context.Context, name string, o ...apitrace.SpanOpti
 		op(&opts)
 	}
 
-	// TODO: [rghetia] ChildOfRelationship is used to indicate that the parent is remote
-	// and its context is received as part of a request. There are two possibilities
-	// 1. Remote is trusted. So continue using same trace.
-	//      tracer.Start(ctx, "some name", ChildOf(remote_span_context))
-	// 2. Remote is not trusted. In this case create a root span and then add the remote as link
-	//      span := tracer.Start(ctx, "some name")
-	//      span.Link(remote_span_context, ChildOfRelationship)
-	if opts.Reference.SpanContext != core.EmptySpanContext() &&
-		opts.Reference.RelationshipType == apitrace.ChildOfRelationship {
-		parent = opts.Reference.SpanContext
-		remoteParent = true
+	if reference := opts.Reference; reference.SpanContext != core.EmptySpanContext() {
+		switch reference.RelationshipType {
+		case apitrace.ChildOfRelationship, apitrace.FollowsFromRelationship:
+			parent = opts.Reference.SpanContext
+			remoteParent = true
+		default:
+			// Future relationship types may have different behavior,
+			// e.g., adding a `Link` instead of setting the `parent`
+		}
 	} else {
 		if p := apitrace.CurrentSpan(ctx); p != nil {
 			if sdkSpan, ok := p.(*span); ok {


Test patch:
diff --git a/sdk/trace/trace_test.go b/sdk/trace/trace_test.go
index 9e9f88e0..f0e3ce77 100644
--- a/sdk/trace/trace_test.go
+++ b/sdk/trace/trace_test.go
@@ -172,6 +172,45 @@ func TestStartSpanWithChildOf(t *testing.T) {
 	}
 }
 
+func TestStartSpanWithFollowsFrom(t *testing.T) {
+	sc1 := core.SpanContext{
+		TraceID:    tid,
+		SpanID:     sid,
+		TraceFlags: 0x0,
+	}
+	_, s1 := apitrace.GlobalTracer().Start(context.Background(), "span1-unsampled-parent1", apitrace.FollowsFrom(sc1))
+	if err := checkChild(sc1, s1); err != nil {
+		t.Error(err)
+	}
+
+	_, s2 := apitrace.GlobalTracer().Start(context.Background(), "span2-unsampled-parent1", apitrace.FollowsFrom(sc1))
+	if err := checkChild(sc1, s2); err != nil {
+		t.Error(err)
+	}
+
+	sc2 := core.SpanContext{
+		TraceID:    tid,
+		SpanID:     sid,
+		TraceFlags: 0x1,
+		//Tracestate:   testTracestate,
+	}
+	_, s3 := apitrace.GlobalTracer().Start(context.Background(), "span3-sampled-parent2", apitrace.FollowsFrom(sc2))
+	if err := checkChild(sc2, s3); err != nil {
+		t.Error(err)
+	}
+
+	ctx, s4 := apitrace.GlobalTracer().Start(context.Background(), "span4-sampled-parent2", apitrace.FollowsFrom(sc2))
+	if err := checkChild(sc2, s4); err != nil {
+		t.Error(err)
+	}
+
+	s4Sc := s4.SpanContext()
+	_, s5 := apitrace.GlobalTracer().Start(ctx, "span5-implicit-childof-span4")
+	if err := checkChild(s4Sc, s5); err != nil {
+		t.Error(err)
+	}
+}
+
 // TODO: [rghetia] Equivalent of SpanKind Test.
 
 func TestSetSpanAttributes(t *testing.T) {