...

Source file src/go.opentelemetry.io/otel/sdk/trace/span_processor_test.go

Documentation: go.opentelemetry.io/otel/sdk/trace

     1  // Copyright The OpenTelemetry Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package trace_test
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	"go.opentelemetry.io/otel/attribute"
    22  	sdktrace "go.opentelemetry.io/otel/sdk/trace"
    23  	"go.opentelemetry.io/otel/trace"
    24  )
    25  
    26  type testSpanProcessor struct {
    27  	name          string
    28  	spansStarted  []sdktrace.ReadWriteSpan
    29  	spansEnded    []sdktrace.ReadOnlySpan
    30  	shutdownCount int
    31  }
    32  
    33  func (t *testSpanProcessor) OnStart(parent context.Context, s sdktrace.ReadWriteSpan) {
    34  	if t == nil {
    35  		return
    36  	}
    37  	psc := trace.SpanContextFromContext(parent)
    38  	kv := []attribute.KeyValue{
    39  		{
    40  			Key:   "SpanProcessorName",
    41  			Value: attribute.StringValue(t.name),
    42  		},
    43  		// Store parent trace ID and span ID as attributes to be read later in
    44  		// tests so that we "do something" with the parent argument. Real
    45  		// SpanProcessor implementations will likely use the parent argument in
    46  		// a more meaningful way.
    47  		{
    48  			Key:   "ParentTraceID",
    49  			Value: attribute.StringValue(psc.TraceID().String()),
    50  		},
    51  		{
    52  			Key:   "ParentSpanID",
    53  			Value: attribute.StringValue(psc.SpanID().String()),
    54  		},
    55  	}
    56  	s.AddEvent("OnStart", trace.WithAttributes(kv...))
    57  	t.spansStarted = append(t.spansStarted, s)
    58  }
    59  
    60  func (t *testSpanProcessor) OnEnd(s sdktrace.ReadOnlySpan) {
    61  	if t == nil {
    62  		return
    63  	}
    64  	t.spansEnded = append(t.spansEnded, s)
    65  }
    66  
    67  func (t *testSpanProcessor) Shutdown(_ context.Context) error {
    68  	if t == nil {
    69  		return nil
    70  	}
    71  	t.shutdownCount++
    72  	return nil
    73  }
    74  
    75  func (t *testSpanProcessor) ForceFlush(context.Context) error {
    76  	if t == nil {
    77  		return nil
    78  	}
    79  	return nil
    80  }
    81  
    82  func TestRegisterSpanProcessor(t *testing.T) {
    83  	name := "Register span processor before span starts"
    84  	tp := basicTracerProvider(t)
    85  	spNames := []string{"sp1", "sp2", "sp3"}
    86  	sps := NewNamedTestSpanProcessors(spNames)
    87  
    88  	for _, sp := range sps {
    89  		tp.RegisterSpanProcessor(sp)
    90  	}
    91  
    92  	tid, _ := trace.TraceIDFromHex("01020304050607080102040810203040")
    93  	sid, _ := trace.SpanIDFromHex("0102040810203040")
    94  	parent := trace.NewSpanContext(trace.SpanContextConfig{
    95  		TraceID: tid,
    96  		SpanID:  sid,
    97  	})
    98  	ctx := trace.ContextWithRemoteSpanContext(context.Background(), parent)
    99  
   100  	tr := tp.Tracer("SpanProcessor")
   101  	_, span := tr.Start(ctx, "OnStart")
   102  	span.End()
   103  	wantCount := 1
   104  
   105  	for _, sp := range sps {
   106  		gotCount := len(sp.spansStarted)
   107  		if gotCount != wantCount {
   108  			t.Errorf("%s: started count: got %d, want %d\n", name, gotCount, wantCount)
   109  		}
   110  		gotCount = len(sp.spansEnded)
   111  		if gotCount != wantCount {
   112  			t.Errorf("%s: ended count: got %d, want %d\n", name, gotCount, wantCount)
   113  		}
   114  
   115  		c := 0
   116  		tidOK := false
   117  		sidOK := false
   118  		for _, e := range sp.spansStarted[0].Events() {
   119  			for _, kv := range e.Attributes {
   120  				switch kv.Key {
   121  				case "SpanProcessorName":
   122  					gotValue := kv.Value.AsString()
   123  					if gotValue != spNames[c] {
   124  						t.Errorf("%s: attributes: got %s, want %s\n", name, gotValue, spNames[c])
   125  					}
   126  					c++
   127  				case "ParentTraceID":
   128  					gotValue := kv.Value.AsString()
   129  					if gotValue != parent.TraceID().String() {
   130  						t.Errorf("%s: attributes: got %s, want %s\n", name, gotValue, parent.TraceID())
   131  					}
   132  					tidOK = true
   133  				case "ParentSpanID":
   134  					gotValue := kv.Value.AsString()
   135  					if gotValue != parent.SpanID().String() {
   136  						t.Errorf("%s: attributes: got %s, want %s\n", name, gotValue, parent.SpanID())
   137  					}
   138  					sidOK = true
   139  				default:
   140  					continue
   141  				}
   142  			}
   143  		}
   144  		if c != len(spNames) {
   145  			t.Errorf("%s: expected attributes(SpanProcessorName): got %d, want %d\n", name, c, len(spNames))
   146  		}
   147  		if !tidOK {
   148  			t.Errorf("%s: expected attributes(ParentTraceID)\n", name)
   149  		}
   150  		if !sidOK {
   151  			t.Errorf("%s: expected attributes(ParentSpanID)\n", name)
   152  		}
   153  	}
   154  }
   155  
   156  func TestUnregisterSpanProcessor(t *testing.T) {
   157  	name := "Start span after unregistering span processor"
   158  	tp := basicTracerProvider(t)
   159  	spNames := []string{"sp1", "sp2", "sp3"}
   160  	sps := NewNamedTestSpanProcessors(spNames)
   161  
   162  	for _, sp := range sps {
   163  		tp.RegisterSpanProcessor(sp)
   164  	}
   165  
   166  	tr := tp.Tracer("SpanProcessor")
   167  	_, span := tr.Start(context.Background(), "OnStart")
   168  	span.End()
   169  	for _, sp := range sps {
   170  		tp.UnregisterSpanProcessor(sp)
   171  	}
   172  
   173  	// start another span after unregistering span processor.
   174  	_, span = tr.Start(context.Background(), "Start span after unregister")
   175  	span.End()
   176  
   177  	for _, sp := range sps {
   178  		wantCount := 1
   179  		gotCount := len(sp.spansStarted)
   180  		if gotCount != wantCount {
   181  			t.Errorf("%s: started count: got %d, want %d\n", name, gotCount, wantCount)
   182  		}
   183  
   184  		gotCount = len(sp.spansEnded)
   185  		if gotCount != wantCount {
   186  			t.Errorf("%s: ended count: got %d, want %d\n", name, gotCount, wantCount)
   187  		}
   188  	}
   189  }
   190  
   191  func TestUnregisterSpanProcessorWhileSpanIsActive(t *testing.T) {
   192  	name := "Unregister span processor while span is active"
   193  	tp := basicTracerProvider(t)
   194  	sp := NewTestSpanProcessor("sp")
   195  	tp.RegisterSpanProcessor(sp)
   196  
   197  	tr := tp.Tracer("SpanProcessor")
   198  	_, span := tr.Start(context.Background(), "OnStart")
   199  	tp.UnregisterSpanProcessor(sp)
   200  
   201  	span.End()
   202  
   203  	wantCount := 1
   204  	gotCount := len(sp.spansStarted)
   205  	if gotCount != wantCount {
   206  		t.Errorf("%s: started count: got %d, want %d\n", name, gotCount, wantCount)
   207  	}
   208  
   209  	wantCount = 0
   210  	gotCount = len(sp.spansEnded)
   211  	if gotCount != wantCount {
   212  		t.Errorf("%s: ended count: got %d, want %d\n", name, gotCount, wantCount)
   213  	}
   214  }
   215  
   216  func TestSpanProcessorShutdown(t *testing.T) {
   217  	name := "Increment shutdown counter of a span processor"
   218  	tp := basicTracerProvider(t)
   219  	sp := NewTestSpanProcessor("sp")
   220  	tp.RegisterSpanProcessor(sp)
   221  
   222  	wantCount := 1
   223  	err := sp.Shutdown(context.Background())
   224  	if err != nil {
   225  		t.Error("Error shutting the testSpanProcessor down\n")
   226  	}
   227  
   228  	gotCount := sp.shutdownCount
   229  	if wantCount != gotCount {
   230  		t.Errorf("%s: wrong counter: got %d, want %d\n", name, gotCount, wantCount)
   231  	}
   232  }
   233  
   234  func TestMultipleUnregisterSpanProcessorCalls(t *testing.T) {
   235  	name := "Increment shutdown counter after first UnregisterSpanProcessor call"
   236  	tp := basicTracerProvider(t)
   237  	sp := NewTestSpanProcessor("sp")
   238  
   239  	wantCount := 1
   240  
   241  	tp.RegisterSpanProcessor(sp)
   242  	tp.UnregisterSpanProcessor(sp)
   243  
   244  	gotCount := sp.shutdownCount
   245  	if wantCount != gotCount {
   246  		t.Errorf("%s: wrong counter: got %d, want %d\n", name, gotCount, wantCount)
   247  	}
   248  
   249  	// Multiple UnregisterSpanProcessor should not trigger multiple Shutdown calls.
   250  	tp.UnregisterSpanProcessor(sp)
   251  
   252  	gotCount = sp.shutdownCount
   253  	if wantCount != gotCount {
   254  		t.Errorf("%s: wrong counter: got %d, want %d\n", name, gotCount, wantCount)
   255  	}
   256  }
   257  
   258  func NewTestSpanProcessor(name string) *testSpanProcessor {
   259  	return &testSpanProcessor{name: name}
   260  }
   261  
   262  func NewNamedTestSpanProcessors(names []string) []*testSpanProcessor {
   263  	tsp := []*testSpanProcessor{}
   264  	for _, n := range names {
   265  		tsp = append(tsp, NewTestSpanProcessor(n))
   266  	}
   267  	return tsp
   268  }
   269  

View as plain text