go.undefinedlabs.com/scopeagent@v0.4.2/tracer/span_test.go (about) 1 package tracer 2 3 import ( 4 "reflect" 5 "strconv" 6 "testing" 7 8 "github.com/google/uuid" 9 opentracing "github.com/opentracing/opentracing-go" 10 "github.com/opentracing/opentracing-go/ext" 11 "github.com/opentracing/opentracing-go/log" 12 "github.com/stretchr/testify/assert" 13 ) 14 15 func TestSpan_Baggage(t *testing.T) { 16 recorder := NewInMemoryRecorder() 17 tracer := NewWithOptions(Options{ 18 Recorder: recorder, 19 ShouldSample: func(traceID uuid.UUID) bool { return true }, // always sample 20 }) 21 span := tracer.StartSpan("x") 22 span.SetBaggageItem("x", "y") 23 assert.Equal(t, "y", span.BaggageItem("x")) 24 span.Finish() 25 spans := recorder.GetSpans() 26 assert.Equal(t, 1, len(spans)) 27 assert.Equal(t, map[string]string{"x": "y"}, spans[0].Context.Baggage) 28 29 recorder.Reset() 30 span = tracer.StartSpan("x") 31 span.SetBaggageItem("x", "y") 32 baggage := make(map[string]string) 33 span.Context().ForeachBaggageItem(func(k, v string) bool { 34 baggage[k] = v 35 return true 36 }) 37 assert.Equal(t, map[string]string{"x": "y"}, baggage) 38 39 span.SetBaggageItem("a", "b") 40 baggage = make(map[string]string) 41 span.Context().ForeachBaggageItem(func(k, v string) bool { 42 baggage[k] = v 43 return false // exit early 44 }) 45 assert.Equal(t, 1, len(baggage)) 46 span.Finish() 47 spans = recorder.GetSpans() 48 assert.Equal(t, 1, len(spans)) 49 assert.Equal(t, 2, len(spans[0].Context.Baggage)) 50 } 51 52 func TestSpan_Sampling(t *testing.T) { 53 recorder := NewInMemoryRecorder() 54 tracer := NewWithOptions(Options{ 55 Recorder: recorder, 56 ShouldSample: func(traceID uuid.UUID) bool { return true }, 57 }) 58 span := tracer.StartSpan("x") 59 span.Finish() 60 assert.Equal(t, 1, len(recorder.GetSampledSpans()), "by default span should be sampled") 61 62 recorder.Reset() 63 span = tracer.StartSpan("x") 64 ext.SamplingPriority.Set(span, 0) 65 span.Finish() 66 assert.Equal(t, 0, len(recorder.GetSampledSpans()), "SamplingPriority=0 should turn off sampling") 67 68 tracer = NewWithOptions(Options{ 69 Recorder: recorder, 70 ShouldSample: func(traceID uuid.UUID) bool { return false }, 71 }) 72 73 recorder.Reset() 74 span = tracer.StartSpan("x") 75 span.Finish() 76 assert.Equal(t, 0, len(recorder.GetSampledSpans()), "by default span should not be sampled") 77 78 recorder.Reset() 79 span = tracer.StartSpan("x") 80 ext.SamplingPriority.Set(span, 1) 81 span.Finish() 82 assert.Equal(t, 1, len(recorder.GetSampledSpans()), "SamplingPriority=1 should turn on sampling") 83 } 84 85 func TestSpan_SingleLoggedTaggedSpan(t *testing.T) { 86 recorder := NewInMemoryRecorder() 87 tracer := NewWithOptions(Options{ 88 Recorder: recorder, 89 ShouldSample: func(traceID uuid.UUID) bool { return true }, // always sample 90 }) 91 span := tracer.StartSpan("x") 92 span.LogEventWithPayload("event", "payload") 93 span.LogFields(log.String("key_str", "value"), log.Uint32("32bit", 4294967295)) 94 span.SetTag("tag", "value") 95 span.Finish() 96 spans := recorder.GetSpans() 97 assert.Equal(t, 1, len(spans)) 98 assert.Equal(t, "x", spans[0].Operation) 99 assert.Equal(t, 2, len(spans[0].Logs)) 100 assert.Equal(t, opentracing.Tags{"tag": "value"}, spans[0].Tags) 101 fv := NewLogFieldValidator(t, spans[0].Logs[0].Fields) 102 fv. 103 ExpectNextFieldEquals("event", reflect.String, "event"). 104 ExpectNextFieldEquals("payload", reflect.Interface, "payload") 105 fv = NewLogFieldValidator(t, spans[0].Logs[1].Fields) 106 fv. 107 ExpectNextFieldEquals("key_str", reflect.String, "value"). 108 ExpectNextFieldEquals("32bit", reflect.Uint32, "4294967295") 109 } 110 111 func TestSpan_TrimUnsampledSpans(t *testing.T) { 112 recorder := NewInMemoryRecorder() 113 // Tracer that trims only unsampled but always samples 114 tracer := NewWithOptions(Options{ 115 Recorder: recorder, 116 ShouldSample: func(traceID uuid.UUID) bool { return true }, // always sample 117 TrimUnsampledSpans: true, 118 }) 119 120 span := tracer.StartSpan("x") 121 span.LogFields(log.String("key_str", "value"), log.Uint32("32bit", 4294967295)) 122 span.SetTag("tag", "value") 123 span.Finish() 124 spans := recorder.GetSpans() 125 assert.Equal(t, 1, len(spans)) 126 assert.Equal(t, 1, len(spans[0].Logs)) 127 assert.Equal(t, opentracing.Tags{"tag": "value"}, spans[0].Tags) 128 fv := NewLogFieldValidator(t, spans[0].Logs[0].Fields) 129 fv. 130 ExpectNextFieldEquals("key_str", reflect.String, "value"). 131 ExpectNextFieldEquals("32bit", reflect.Uint32, "4294967295") 132 133 recorder.Reset() 134 // Tracer that trims only unsampled and never samples 135 tracer = NewWithOptions(Options{ 136 Recorder: recorder, 137 ShouldSample: func(traceID uuid.UUID) bool { return false }, // never sample 138 TrimUnsampledSpans: true, 139 }) 140 141 span = tracer.StartSpan("x") 142 span.LogFields(log.String("key_str", "value"), log.Uint32("32bit", 4294967295)) 143 span.SetTag("tag", "value") 144 span.Finish() 145 spans = recorder.GetSpans() 146 assert.Equal(t, 1, len(spans)) 147 assert.Equal(t, 0, len(spans[0].Logs)) 148 assert.Equal(t, 0, len(spans[0].Tags)) 149 } 150 151 func TestSpan_DropAllLogs(t *testing.T) { 152 recorder := NewInMemoryRecorder() 153 // Tracer that drops logs 154 tracer := NewWithOptions(Options{ 155 Recorder: recorder, 156 ShouldSample: func(traceID uuid.UUID) bool { return true }, // always sample 157 DropAllLogs: true, 158 }) 159 160 span := tracer.StartSpan("x") 161 span.LogFields(log.String("key_str", "value"), log.Uint32("32bit", 4294967295)) 162 span.SetTag("tag", "value") 163 span.Finish() 164 spans := recorder.GetSpans() 165 assert.Equal(t, 1, len(spans)) 166 assert.Equal(t, "x", spans[0].Operation) 167 assert.Equal(t, opentracing.Tags{"tag": "value"}, spans[0].Tags) 168 // Only logs are dropped 169 assert.Equal(t, 0, len(spans[0].Logs)) 170 } 171 172 func TestSpan_MaxLogSperSpan(t *testing.T) { 173 for _, limit := range []int{1, 2, 3, 5, 10, 15, 20} { 174 for _, numLogs := range []int{1, 2, 3, 5, 10, 15, 20, 30, 40, 50} { 175 recorder := NewInMemoryRecorder() 176 // Tracer that only retains the last <limit> logs. 177 tracer := NewWithOptions(Options{ 178 Recorder: recorder, 179 ShouldSample: func(traceID uuid.UUID) bool { return true }, // always sample 180 MaxLogsPerSpan: limit, 181 }) 182 183 span := tracer.StartSpan("x") 184 for i := 0; i < numLogs; i++ { 185 span.LogKV("eventIdx", i) 186 } 187 span.Finish() 188 189 spans := recorder.GetSpans() 190 assert.Equal(t, 1, len(spans)) 191 assert.Equal(t, "x", spans[0].Operation) 192 193 logs := spans[0].Logs 194 var firstLogs, lastLogs []opentracing.LogRecord 195 if numLogs <= limit { 196 assert.Equal(t, numLogs, len(logs)) 197 firstLogs = logs 198 } else { 199 assert.Equal(t, limit, len(logs)) 200 if len(logs) > 0 { 201 numOld := (len(logs) - 1) / 2 202 firstLogs = logs[:numOld] 203 lastLogs = logs[numOld+1:] 204 205 fv := NewLogFieldValidator(t, logs[numOld].Fields) 206 fv = fv.ExpectNextFieldEquals("event", reflect.String, "dropped Span logs") 207 fv = fv.ExpectNextFieldEquals( 208 "dropped_log_count", reflect.Int, strconv.Itoa(numLogs-limit+1), 209 ) 210 fv.ExpectNextFieldEquals("component", reflect.String, "basictracer") 211 } 212 } 213 214 for i, lr := range firstLogs { 215 fv := NewLogFieldValidator(t, lr.Fields) 216 fv.ExpectNextFieldEquals("eventIdx", reflect.Int, strconv.Itoa(i)) 217 } 218 219 for i, lr := range lastLogs { 220 fv := NewLogFieldValidator(t, lr.Fields) 221 fv.ExpectNextFieldEquals("eventIdx", reflect.Int, strconv.Itoa(numLogs-len(lastLogs)+i)) 222 } 223 } 224 } 225 }