2020-03-23 22:41:10 -07:00
|
|
|
// Copyright The OpenTelemetry Authors
|
2019-10-01 13:50:51 -07:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package trace_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-10-23 03:01:33 -03:00
|
|
|
"encoding/binary"
|
2021-04-01 10:42:19 -07:00
|
|
|
"errors"
|
2019-10-01 13:50:51 -07:00
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2021-01-14 09:14:03 +08:00
|
|
|
"github.com/stretchr/testify/assert"
|
2021-04-06 17:54:26 -04:00
|
|
|
"github.com/stretchr/testify/require"
|
2021-01-14 09:14:03 +08:00
|
|
|
|
2020-11-06 23:13:31 +01:00
|
|
|
"go.opentelemetry.io/otel/trace"
|
|
|
|
|
2019-11-01 11:40:29 -07:00
|
|
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
2019-10-01 13:50:51 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
type testBatchExporter struct {
|
2021-01-14 09:14:03 +08:00
|
|
|
mu sync.Mutex
|
2021-04-07 15:03:43 +00:00
|
|
|
spans []*sdktrace.SpanSnapshot
|
2021-01-14 09:14:03 +08:00
|
|
|
sizes []int
|
|
|
|
batchCount int
|
|
|
|
shutdownCount int
|
2021-04-05 19:38:03 +02:00
|
|
|
delay time.Duration
|
|
|
|
err error
|
2019-10-01 13:50:51 -07:00
|
|
|
}
|
|
|
|
|
2021-04-07 15:03:43 +00:00
|
|
|
func (t *testBatchExporter) ExportSpans(ctx context.Context, ss []*sdktrace.SpanSnapshot) error {
|
2019-10-01 13:50:51 -07:00
|
|
|
t.mu.Lock()
|
|
|
|
defer t.mu.Unlock()
|
2019-10-08 20:56:58 +02:00
|
|
|
|
2021-04-05 19:38:03 +02:00
|
|
|
time.Sleep(t.delay)
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
t.err = ctx.Err()
|
|
|
|
return ctx.Err()
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
2020-12-11 06:15:44 +01:00
|
|
|
t.spans = append(t.spans, ss...)
|
|
|
|
t.sizes = append(t.sizes, len(ss))
|
2019-10-01 13:50:51 -07:00
|
|
|
t.batchCount++
|
2020-09-09 10:19:03 -07:00
|
|
|
return nil
|
2019-10-01 13:50:51 -07:00
|
|
|
}
|
|
|
|
|
2021-01-14 09:14:03 +08:00
|
|
|
func (t *testBatchExporter) Shutdown(context.Context) error {
|
|
|
|
t.shutdownCount++
|
|
|
|
return nil
|
|
|
|
}
|
2020-09-09 10:19:03 -07:00
|
|
|
|
2019-10-01 13:50:51 -07:00
|
|
|
func (t *testBatchExporter) len() int {
|
|
|
|
t.mu.Lock()
|
|
|
|
defer t.mu.Unlock()
|
|
|
|
return len(t.spans)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *testBatchExporter) getBatchCount() int {
|
|
|
|
t.mu.Lock()
|
|
|
|
defer t.mu.Unlock()
|
|
|
|
return t.batchCount
|
|
|
|
}
|
|
|
|
|
2021-04-07 15:03:43 +00:00
|
|
|
var _ sdktrace.SpanExporter = (*testBatchExporter)(nil)
|
2019-10-01 13:50:51 -07:00
|
|
|
|
|
|
|
func TestNewBatchSpanProcessorWithNilExporter(t *testing.T) {
|
2020-12-11 06:15:44 +01:00
|
|
|
tp := basicTracerProvider(t)
|
2020-09-09 10:19:03 -07:00
|
|
|
bsp := sdktrace.NewBatchSpanProcessor(nil)
|
2020-12-11 06:15:44 +01:00
|
|
|
tp.RegisterSpanProcessor(bsp)
|
|
|
|
tr := tp.Tracer("NilExporter")
|
|
|
|
|
|
|
|
_, span := tr.Start(context.Background(), "foo")
|
|
|
|
span.End()
|
|
|
|
|
2020-09-09 10:19:03 -07:00
|
|
|
// These should not panic.
|
2020-12-11 06:15:44 +01:00
|
|
|
bsp.OnStart(context.Background(), span.(sdktrace.ReadWriteSpan))
|
|
|
|
bsp.OnEnd(span.(sdktrace.ReadOnlySpan))
|
2021-03-08 19:12:13 +00:00
|
|
|
if err := bsp.ForceFlush(context.Background()); err != nil {
|
|
|
|
t.Errorf("failed to ForceFlush the BatchSpanProcessor: %v", err)
|
|
|
|
}
|
|
|
|
if err := bsp.Shutdown(context.Background()); err != nil {
|
|
|
|
t.Errorf("failed to Shutdown the BatchSpanProcessor: %v", err)
|
2020-10-27 05:06:55 +03:00
|
|
|
}
|
2019-10-01 13:50:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
type testOption struct {
|
2021-04-05 19:38:03 +02:00
|
|
|
name string
|
|
|
|
o []sdktrace.BatchSpanProcessorOption
|
|
|
|
wantNumSpans int
|
|
|
|
wantBatchCount int
|
|
|
|
wantExportTimeout bool
|
|
|
|
genNumSpans int
|
|
|
|
delayExportBy time.Duration
|
|
|
|
parallel bool
|
2019-10-01 13:50:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewBatchSpanProcessorWithOptions(t *testing.T) {
|
2019-12-09 13:03:11 -08:00
|
|
|
schDelay := 200 * time.Millisecond
|
2021-04-05 19:38:03 +02:00
|
|
|
exportTimeout := time.Millisecond
|
2019-10-01 13:50:51 -07:00
|
|
|
options := []testOption{
|
|
|
|
{
|
|
|
|
name: "default BatchSpanProcessorOptions",
|
2020-05-14 14:02:22 +03:00
|
|
|
wantNumSpans: 2053,
|
2019-10-01 13:50:51 -07:00
|
|
|
wantBatchCount: 4,
|
|
|
|
genNumSpans: 2053,
|
|
|
|
},
|
2021-04-05 19:38:03 +02:00
|
|
|
{
|
|
|
|
name: "non-default ExportTimeout",
|
|
|
|
o: []sdktrace.BatchSpanProcessorOption{
|
|
|
|
sdktrace.WithExportTimeout(exportTimeout),
|
|
|
|
},
|
|
|
|
wantExportTimeout: true,
|
|
|
|
genNumSpans: 2053,
|
|
|
|
delayExportBy: 2 * exportTimeout, // to ensure export timeout
|
|
|
|
},
|
2019-10-01 13:50:51 -07:00
|
|
|
{
|
2020-05-20 20:12:57 +03:00
|
|
|
name: "non-default BatchTimeout",
|
2019-10-01 13:50:51 -07:00
|
|
|
o: []sdktrace.BatchSpanProcessorOption{
|
2020-05-20 20:12:57 +03:00
|
|
|
sdktrace.WithBatchTimeout(schDelay),
|
2019-10-01 13:50:51 -07:00
|
|
|
},
|
2020-05-14 14:02:22 +03:00
|
|
|
wantNumSpans: 2053,
|
2019-10-01 13:50:51 -07:00
|
|
|
wantBatchCount: 4,
|
|
|
|
genNumSpans: 2053,
|
|
|
|
},
|
|
|
|
{
|
2020-05-20 20:12:57 +03:00
|
|
|
name: "non-default MaxQueueSize and BatchTimeout",
|
2019-10-01 13:50:51 -07:00
|
|
|
o: []sdktrace.BatchSpanProcessorOption{
|
2020-05-20 20:12:57 +03:00
|
|
|
sdktrace.WithBatchTimeout(schDelay),
|
2019-10-01 13:50:51 -07:00
|
|
|
sdktrace.WithMaxQueueSize(200),
|
|
|
|
},
|
2020-05-14 14:02:22 +03:00
|
|
|
wantNumSpans: 205,
|
2019-10-01 13:50:51 -07:00
|
|
|
wantBatchCount: 1,
|
|
|
|
genNumSpans: 205,
|
|
|
|
},
|
|
|
|
{
|
2020-05-20 20:12:57 +03:00
|
|
|
name: "non-default MaxQueueSize, BatchTimeout and MaxExportBatchSize",
|
2019-10-01 13:50:51 -07:00
|
|
|
o: []sdktrace.BatchSpanProcessorOption{
|
2020-05-20 20:12:57 +03:00
|
|
|
sdktrace.WithBatchTimeout(schDelay),
|
2019-10-01 13:50:51 -07:00
|
|
|
sdktrace.WithMaxQueueSize(205),
|
|
|
|
sdktrace.WithMaxExportBatchSize(20),
|
|
|
|
},
|
2020-05-14 14:02:22 +03:00
|
|
|
wantNumSpans: 210,
|
2019-10-01 13:50:51 -07:00
|
|
|
wantBatchCount: 11,
|
|
|
|
genNumSpans: 210,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "blocking option",
|
|
|
|
o: []sdktrace.BatchSpanProcessorOption{
|
2020-05-20 20:12:57 +03:00
|
|
|
sdktrace.WithBatchTimeout(schDelay),
|
2019-10-01 13:50:51 -07:00
|
|
|
sdktrace.WithMaxQueueSize(200),
|
|
|
|
sdktrace.WithMaxExportBatchSize(20),
|
|
|
|
},
|
|
|
|
wantNumSpans: 205,
|
|
|
|
wantBatchCount: 11,
|
|
|
|
genNumSpans: 205,
|
|
|
|
},
|
2020-03-05 13:41:00 -08:00
|
|
|
{
|
|
|
|
name: "parallel span generation",
|
|
|
|
o: []sdktrace.BatchSpanProcessorOption{
|
2020-05-20 20:12:57 +03:00
|
|
|
sdktrace.WithBatchTimeout(schDelay),
|
2020-03-05 13:41:00 -08:00
|
|
|
sdktrace.WithMaxQueueSize(200),
|
|
|
|
},
|
2020-05-14 14:02:22 +03:00
|
|
|
wantNumSpans: 205,
|
2020-03-05 13:41:00 -08:00
|
|
|
wantBatchCount: 1,
|
|
|
|
genNumSpans: 205,
|
|
|
|
parallel: true,
|
|
|
|
},
|
2020-03-27 16:21:20 -07:00
|
|
|
{
|
|
|
|
name: "parallel span blocking",
|
|
|
|
o: []sdktrace.BatchSpanProcessorOption{
|
2020-05-20 20:12:57 +03:00
|
|
|
sdktrace.WithBatchTimeout(schDelay),
|
2020-03-27 16:21:20 -07:00
|
|
|
sdktrace.WithMaxExportBatchSize(200),
|
|
|
|
},
|
|
|
|
wantNumSpans: 2000,
|
|
|
|
wantBatchCount: 10,
|
|
|
|
genNumSpans: 2000,
|
|
|
|
parallel: true,
|
|
|
|
},
|
2019-10-01 13:50:51 -07:00
|
|
|
}
|
|
|
|
for _, option := range options {
|
2020-05-19 09:36:33 -07:00
|
|
|
t.Run(option.name, func(t *testing.T) {
|
2021-04-05 19:38:03 +02:00
|
|
|
te := testBatchExporter{
|
|
|
|
delay: option.delayExportBy,
|
|
|
|
}
|
2020-09-23 15:16:13 -07:00
|
|
|
tp := basicTracerProvider(t)
|
2020-09-09 10:19:03 -07:00
|
|
|
ssp := createAndRegisterBatchSP(option, &te)
|
2020-05-19 09:36:33 -07:00
|
|
|
if ssp == nil {
|
|
|
|
t.Fatalf("%s: Error creating new instance of BatchSpanProcessor\n", option.name)
|
|
|
|
}
|
|
|
|
tp.RegisterSpanProcessor(ssp)
|
|
|
|
tr := tp.Tracer("BatchSpanProcessorWithOptions")
|
|
|
|
|
|
|
|
generateSpan(t, option.parallel, tr, option)
|
|
|
|
|
|
|
|
tp.UnregisterSpanProcessor(ssp)
|
|
|
|
|
2020-06-10 01:20:48 +03:00
|
|
|
gotNumOfSpans := te.len()
|
2021-04-05 19:38:03 +02:00
|
|
|
if option.wantNumSpans > 0 && option.wantNumSpans != gotNumOfSpans {
|
2020-06-10 01:20:48 +03:00
|
|
|
t.Errorf("number of exported span: got %+v, want %+v\n",
|
|
|
|
gotNumOfSpans, option.wantNumSpans)
|
|
|
|
}
|
|
|
|
|
|
|
|
gotBatchCount := te.getBatchCount()
|
2021-04-05 19:38:03 +02:00
|
|
|
if option.wantBatchCount > 0 && gotBatchCount < option.wantBatchCount {
|
2020-06-10 01:20:48 +03:00
|
|
|
t.Errorf("number batches: got %+v, want >= %+v\n",
|
|
|
|
gotBatchCount, option.wantBatchCount)
|
|
|
|
t.Errorf("Batches %v\n", te.sizes)
|
|
|
|
}
|
2021-04-05 19:38:03 +02:00
|
|
|
|
|
|
|
if option.wantExportTimeout && te.err != context.DeadlineExceeded {
|
|
|
|
t.Errorf("context deadline: got err %+v, want %+v\n",
|
|
|
|
te.err, context.DeadlineExceeded)
|
|
|
|
}
|
2020-05-19 09:36:33 -07:00
|
|
|
})
|
2019-10-01 13:50:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-05 16:08:29 +00:00
|
|
|
func createAndRegisterBatchSP(option testOption, te *testBatchExporter) sdktrace.SpanProcessor {
|
2020-06-10 01:20:48 +03:00
|
|
|
// Always use blocking queue to avoid flaky tests.
|
|
|
|
options := append(option.o, sdktrace.WithBlocking())
|
2020-09-09 10:19:03 -07:00
|
|
|
return sdktrace.NewBatchSpanProcessor(te, options...)
|
2019-10-01 13:50:51 -07:00
|
|
|
}
|
|
|
|
|
2020-11-06 23:13:31 +01:00
|
|
|
func generateSpan(t *testing.T, parallel bool, tr trace.Tracer, option testOption) {
|
2019-10-01 13:50:51 -07:00
|
|
|
sc := getSpanContext()
|
|
|
|
|
2020-03-05 13:41:00 -08:00
|
|
|
wg := &sync.WaitGroup{}
|
2019-10-01 13:50:51 -07:00
|
|
|
for i := 0; i < option.genNumSpans; i++ {
|
2021-03-09 11:17:29 -05:00
|
|
|
tid := sc.TraceID()
|
|
|
|
binary.BigEndian.PutUint64(tid[0:8], uint64(i+1))
|
|
|
|
newSc := sc.WithTraceID(tid)
|
|
|
|
|
2020-03-05 13:41:00 -08:00
|
|
|
wg.Add(1)
|
2020-11-06 23:13:31 +01:00
|
|
|
f := func(sc trace.SpanContext) {
|
|
|
|
ctx := trace.ContextWithRemoteSpanContext(context.Background(), sc)
|
2020-03-05 13:41:00 -08:00
|
|
|
_, span := tr.Start(ctx, option.name)
|
|
|
|
span.End()
|
|
|
|
wg.Done()
|
|
|
|
}
|
|
|
|
if parallel {
|
2021-03-09 11:17:29 -05:00
|
|
|
go f(newSc)
|
2020-03-05 13:41:00 -08:00
|
|
|
} else {
|
2021-03-09 11:17:29 -05:00
|
|
|
f(newSc)
|
2020-03-05 13:41:00 -08:00
|
|
|
}
|
2019-10-01 13:50:51 -07:00
|
|
|
}
|
2020-03-05 13:41:00 -08:00
|
|
|
wg.Wait()
|
2019-10-01 13:50:51 -07:00
|
|
|
}
|
|
|
|
|
2020-11-06 23:13:31 +01:00
|
|
|
func getSpanContext() trace.SpanContext {
|
|
|
|
tid, _ := trace.TraceIDFromHex("01020304050607080102040810203040")
|
|
|
|
sid, _ := trace.SpanIDFromHex("0102040810203040")
|
2021-03-09 11:17:29 -05:00
|
|
|
return trace.NewSpanContext(trace.SpanContextConfig{
|
2019-10-01 13:50:51 -07:00
|
|
|
TraceID: tid,
|
|
|
|
SpanID: sid,
|
|
|
|
TraceFlags: 0x1,
|
2021-03-09 11:17:29 -05:00
|
|
|
})
|
2019-10-09 00:34:19 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestBatchSpanProcessorShutdown(t *testing.T) {
|
2021-01-14 09:14:03 +08:00
|
|
|
var bp testBatchExporter
|
|
|
|
bsp := sdktrace.NewBatchSpanProcessor(&bp)
|
2019-10-09 00:34:19 +07:00
|
|
|
|
2020-10-27 05:06:55 +03:00
|
|
|
err := bsp.Shutdown(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
t.Error("Error shutting the BatchSpanProcessor down\n")
|
|
|
|
}
|
2021-01-14 09:14:03 +08:00
|
|
|
assert.Equal(t, 1, bp.shutdownCount, "shutdown from span exporter not called")
|
2019-10-09 00:34:19 +07:00
|
|
|
|
|
|
|
// Multiple call to Shutdown() should not panic.
|
2020-10-27 05:06:55 +03:00
|
|
|
err = bsp.Shutdown(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
t.Error("Error shutting the BatchSpanProcessor down\n")
|
|
|
|
}
|
2021-01-14 09:14:03 +08:00
|
|
|
assert.Equal(t, 1, bp.shutdownCount)
|
2019-10-09 00:34:19 +07:00
|
|
|
}
|
2021-04-01 10:42:19 -07:00
|
|
|
|
2021-04-06 17:54:26 -04:00
|
|
|
func TestBatchSpanProcessorPostShutdown(t *testing.T) {
|
|
|
|
tp := basicTracerProvider(t)
|
|
|
|
be := testBatchExporter{}
|
|
|
|
bsp := sdktrace.NewBatchSpanProcessor(&be)
|
|
|
|
|
|
|
|
tp.RegisterSpanProcessor(bsp)
|
|
|
|
tr := tp.Tracer("Normal")
|
|
|
|
|
|
|
|
generateSpan(t, true, tr, testOption{
|
|
|
|
o: []sdktrace.BatchSpanProcessorOption{
|
|
|
|
sdktrace.WithMaxExportBatchSize(50),
|
|
|
|
},
|
|
|
|
genNumSpans: 60,
|
|
|
|
})
|
|
|
|
|
|
|
|
require.NoError(t, bsp.Shutdown(context.Background()), "shutting down BatchSpanProcessor")
|
|
|
|
lenJustAfterShutdown := be.len()
|
|
|
|
|
|
|
|
_, span := tr.Start(context.Background(), "foo")
|
|
|
|
span.End()
|
|
|
|
assert.NoError(t, bsp.ForceFlush(context.Background()), "force flushing BatchSpanProcessor")
|
|
|
|
|
|
|
|
assert.Equal(t, lenJustAfterShutdown, be.len(), "OnEnd and ForceFlush should have no effect after Shutdown")
|
|
|
|
}
|
|
|
|
|
2021-04-01 10:42:19 -07:00
|
|
|
func TestBatchSpanProcessorForceFlushSucceeds(t *testing.T) {
|
|
|
|
te := testBatchExporter{}
|
|
|
|
tp := basicTracerProvider(t)
|
|
|
|
option := testOption{
|
|
|
|
name: "default BatchSpanProcessorOptions",
|
|
|
|
o: []sdktrace.BatchSpanProcessorOption{
|
|
|
|
sdktrace.WithMaxQueueSize(0),
|
|
|
|
sdktrace.WithMaxExportBatchSize(3000),
|
|
|
|
},
|
|
|
|
wantNumSpans: 2053,
|
|
|
|
wantBatchCount: 1,
|
|
|
|
genNumSpans: 2053,
|
|
|
|
}
|
|
|
|
ssp := createAndRegisterBatchSP(option, &te)
|
|
|
|
if ssp == nil {
|
|
|
|
t.Fatalf("%s: Error creating new instance of BatchSpanProcessor\n", option.name)
|
|
|
|
}
|
|
|
|
tp.RegisterSpanProcessor(ssp)
|
|
|
|
tr := tp.Tracer("BatchSpanProcessorWithOption")
|
|
|
|
generateSpan(t, option.parallel, tr, option)
|
|
|
|
|
|
|
|
// Force flush any held span batches
|
|
|
|
err := ssp.ForceFlush(context.Background())
|
|
|
|
|
|
|
|
gotNumOfSpans := te.len()
|
|
|
|
spanDifference := option.wantNumSpans - gotNumOfSpans
|
|
|
|
if spanDifference > 10 || spanDifference < 0 {
|
|
|
|
t.Errorf("number of exported span not equal to or within 10 less than: got %+v, want %+v\n",
|
|
|
|
gotNumOfSpans, option.wantNumSpans)
|
|
|
|
}
|
|
|
|
gotBatchCount := te.getBatchCount()
|
|
|
|
if gotBatchCount < option.wantBatchCount {
|
|
|
|
t.Errorf("number batches: got %+v, want >= %+v\n",
|
|
|
|
gotBatchCount, option.wantBatchCount)
|
|
|
|
t.Errorf("Batches %v\n", te.sizes)
|
|
|
|
}
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBatchSpanProcessorForceFlushTimeout(t *testing.T) {
|
|
|
|
var bp testBatchExporter
|
|
|
|
bsp := sdktrace.NewBatchSpanProcessor(&bp)
|
|
|
|
// Add timeout to context to test deadline
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond)
|
|
|
|
defer cancel()
|
|
|
|
<-ctx.Done()
|
|
|
|
|
|
|
|
if err := bsp.ForceFlush(ctx); err == nil {
|
|
|
|
t.Error("expected context DeadlineExceeded error, got nil")
|
|
|
|
} else if !errors.Is(err, context.DeadlineExceeded) {
|
|
|
|
t.Errorf("expected context DeadlineExceeded error, got %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBatchSpanProcessorForceFlushCancellation(t *testing.T) {
|
|
|
|
var bp testBatchExporter
|
|
|
|
bsp := sdktrace.NewBatchSpanProcessor(&bp)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
// Cancel the context
|
|
|
|
cancel()
|
|
|
|
|
|
|
|
if err := bsp.ForceFlush(ctx); err == nil {
|
|
|
|
t.Error("expected context canceled error, got nil")
|
|
|
|
} else if !errors.Is(err, context.Canceled) {
|
|
|
|
t.Errorf("expected context canceled error, got %v", err)
|
|
|
|
}
|
|
|
|
}
|