This is an automated email from the ASF dual-hosted git repository.

liuhan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-go.git


The following commit(s) were added to refs/heads/main by this push:
     new 5510aef  Fix wrong tracing context when trace have been sampled (#161)
5510aef is described below

commit 5510aef8b575a2bd87e1d851fb6531e73c6f7d92
Author: mrproliu <[email protected]>
AuthorDate: Thu Jan 11 18:54:37 2024 +0800

    Fix wrong tracing context when trace have been sampled (#161)
---
 CHANGES.md                   |  1 +
 plugins/core/span_noop.go    | 26 +++++++++++++++++++++++++-
 plugins/core/span_tracing.go |  5 ++++-
 plugins/core/tracing.go      | 11 +++++++----
 plugins/core/tracing_test.go | 36 ++++++++++++++++++++++++++++++++++++
 5 files changed, 73 insertions(+), 6 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 4e98f9c..b4c2a70 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -19,6 +19,7 @@ Release Notes.
 * Fix SW_AGENT_REPORTER_GRPC_MAX_SEND_QUEUE not working on metricsSendCh & 
logSendCh chans of gRPC reporter.
 * Fix ParseVendorModule error for special case in vendor/modules.txt.
 * Fix enhance method error when unknown parameter type.
+* Fix wrong tracing context when trace have been sampled.
 
 #### Issues and PR
 - All issues are 
[here](https://github.com/apache/skywalking/milestone/197?closed=1)
diff --git a/plugins/core/span_noop.go b/plugins/core/span_noop.go
index 85cff00..4fc0beb 100644
--- a/plugins/core/span_noop.go
+++ b/plugins/core/span_noop.go
@@ -24,6 +24,20 @@ import (
 const noopContextValue = "N/A"
 
 type NoopSpan struct {
+       stackCount int
+}
+
+func newSnapshotNoopSpan() *NoopSpan {
+       // snapshot noop span is not a real span
+       return &NoopSpan{
+               stackCount: 0,
+       }
+}
+
+func newNoopSpan() *NoopSpan {
+       return &NoopSpan{
+               stackCount: 1,
+       }
 }
 
 func (*NoopSpan) GetTraceID() string {
@@ -75,7 +89,17 @@ func (*NoopSpan) Log(...string) {
 func (*NoopSpan) Error(...string) {
 }
 
-func (*NoopSpan) End() {
+func (n *NoopSpan) enterNoSpan() {
+       n.stackCount++
+}
+
+func (n *NoopSpan) End() {
+       n.stackCount--
+       if n.stackCount == 0 {
+               if ctx := getTracingContext(); ctx != nil {
+                       ctx.SaveActiveSpan(nil)
+               }
+       }
 }
 
 func (*NoopSpan) IsEntry() bool {
diff --git a/plugins/core/span_tracing.go b/plugins/core/span_tracing.go
index 2368c7e..2871e37 100644
--- a/plugins/core/span_tracing.go
+++ b/plugins/core/span_tracing.go
@@ -368,10 +368,13 @@ func newSegmentRoot(segmentSpan *SegmentSpanImpl) 
*RootSegmentSpan {
        return s
 }
 
-func newSnapshotSpan(current TracingSpan) *SnapshotSpan {
+func newSnapshotSpan(current TracingSpan) TracingSpan {
        if current == nil {
                return nil
        }
+       if _, isNoop := current.(*NoopSpan); isNoop {
+               return newSnapshotNoopSpan()
+       }
        segmentSpan, ok := current.(SegmentSpan)
        if !ok || !segmentSpan.IsValid() { // is not segment span or segment is 
invalid(Executed End() method
                return nil
diff --git a/plugins/core/tracing.go b/plugins/core/tracing.go
index c3e493f..fb7b132 100644
--- a/plugins/core/tracing.go
+++ b/plugins/core/tracing.go
@@ -227,12 +227,16 @@ func (s *ContextSnapshot) IsValid() bool {
 
 func (t *Tracer) createNoop() (*TracingContext, TracingSpan, bool) {
        if !t.InitSuccess() || t.Reporter.ConnectionStatus() == 
reporter.ConnectionStatusDisconnect {
-               return nil, &NoopSpan{}, true
+               return nil, newNoopSpan(), true
        }
        ctx := getTracingContext()
        if ctx != nil {
                span := ctx.ActiveSpan()
-               _, ok := span.(*NoopSpan)
+               noop, ok := span.(*NoopSpan)
+               if ok {
+                       // increase the stack count for ensure the noop span 
can be clear in the context
+                       noop.enterNoSpan()
+               }
                return ctx, span, ok
        }
        ctx = NewTracingContext()
@@ -255,8 +259,7 @@ func (t *Tracer) createSpan0(ctx *TracingContext, parent 
TracingSpan, pluginOpts
                sampled := t.Sampler.IsSampled(ds.OperationName)
                if !sampled {
                        // Filter by sample just return noop span
-                       s = &NoopSpan{}
-                       return s, nil
+                       return newNoopSpan(), nil
                }
        }
        // process the opts from agent core for prepare building segment span
diff --git a/plugins/core/tracing_test.go b/plugins/core/tracing_test.go
index 86b2573..a7b464c 100644
--- a/plugins/core/tracing_test.go
+++ b/plugins/core/tracing_test.go
@@ -419,6 +419,42 @@ func TestContext(t *testing.T) {
        assert.Nil(t, tracing.ActiveSpan(), "active span should be nil")
 }
 
+func TestNoopSpan(t *testing.T) {
+       defer ResetTracingContext()
+       Tracing.Sampler = NewConstSampler(false)
+       var err error
+       // create multiple noop span
+       span, err := tracing.CreateLocalSpan("test")
+       assert.Nil(t, err, "create span error")
+       assert.NotNil(t, span, "span should not be nil")
+       span1, err := tracing.CreateLocalSpan("test2")
+       assert.Nil(t, err, "create span error")
+       assert.NotNil(t, span, "span should not be nil")
+       activeSpan := tracing.ActiveSpan()
+       assert.NotNil(t, activeSpan, "active span should not be nil")
+       context := tracing.CaptureContext()
+       assert.NotNil(t, context, "context should not be nil")
+       oldGLS := GetGLS()
+
+       // switch to a new GLS(continue context and create span test)
+       SetAsNewGoroutine()
+       tracing.ContinueContext(context)
+       assert.NotNil(t, tracing.ActiveSpan(), "active span should not be nil")
+       test3span, err := tracing.CreateLocalSpan("test3")
+       assert.Nil(t, err, "create span error")
+       assert.NotNil(t, test3span, "span should not be nil")
+       test3span.End()
+       activeSpan = tracing.ActiveSpan()
+       assert.Nil(t, activeSpan, "active span should be nil")
+
+       // switch back to the GLS(check the active span should be nil, make 
sure context is clean)
+       SetGLS(oldGLS)
+       span1.End()
+       span.End()
+       activeSpan = tracing.ActiveSpan()
+       assert.Nil(t, activeSpan, "active span should be nil")
+}
+
 func validateSpanOperation(t *testing.T, cases []spanOperationTestCase) {
        for _, tt := range cases {
                spans := make([]tracing.Span, 0)

Reply via email to