1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-04-07 07:00:13 +02:00

sdk/trace: removing ApplyConfig and Config (#1693)

This patch removes `ApplyConfig` method and `Config` struct from
`go.opentelemetry.io/otel/sdk/trace` package.  To ensure valid config
for TracerProvider, it adds `ensureValidTracerProviderConfig` private
function.
Jaeger and Zipkin have been used the `Config` directly across package
boundaries. Since `Config` is removed, they can't use it. This change,
thus, replaces `WithSDK` with `WithSDKOptions`.

Resolves #1636, #1705.
This commit is contained in:
Injun Song 2021-03-19 02:48:13 +09:00 committed by GitHub
parent 1d42be1601
commit 4beb70416e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 247 additions and 136 deletions

View File

@ -31,6 +31,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Jaeger exporter populates Jaeger's Span Process from Resource. (#1673)
- `"go.opentelemetry.io/otel/sdk/resource".NewWithAttributes` will now drop any invalid attributes passed. (#1703)
- `"go.opentelemetry.io/otel/sdk/resource".StringDetector` will now error if the produced attribute is invalid. (#1703)
- Changed `WithSDK` to `WithSDKOptions` to accept variadic arguments of `TracerProviderOption` type in `go.opentelemetry.io/otel/exporters/trace/jaeger` package. (#1693)
- Changed `WithSDK` to `WithSDKOptions` to accept variadic arguments of `TracerProviderOption` type in `go.opentelemetry.io/otel/exporters/trace/zipkin` package. (#1693)
### Removed
@ -41,6 +43,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Removed `WithConfig` from tracer provider to avoid overriding configuration. (#1633)
- Removed `serviceName` parameter from Zipkin exporter and uses resource instead. (#1549)
- Removed `jaeger.WithProcess`. (#1673)
- Removed `ApplyConfig` method and `Config` struct from tracer provider. (#1693)
### Fixed

View File

@ -34,14 +34,14 @@ func initTracer() func() {
// Create and install Jaeger export pipeline.
flush, err := jaeger.InstallNewPipeline(
jaeger.WithCollectorEndpoint("http://localhost:14268/api/traces"),
jaeger.WithSDK(&sdktrace.Config{
DefaultSampler: sdktrace.AlwaysSample(),
Resource: resource.NewWithAttributes(
jaeger.WithSDKOptions(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithResource(resource.NewWithAttributes(
semconv.ServiceNameKey.String("trace-demo"),
attribute.String("exporter", "jaeger"),
attribute.Float64("float", 312.23),
),
}),
)),
),
)
if err != nil {
log.Fatal(err)

View File

@ -43,7 +43,7 @@ func initTracer(url string) func() {
exporter, err := zipkin.NewRawExporter(
url,
zipkin.WithLogger(logger),
zipkin.WithSDK(&sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
zipkin.WithSDKOptions(sdktrace.WithSampler(sdktrace.AlwaysSample())),
)
if err != nil {
log.Fatal(err)

View File

@ -52,7 +52,8 @@ type options struct {
// BatchMaxCount defines the maximum number of spans sent in one batch
BatchMaxCount int
Config *sdktrace.Config
// TracerProviderOptions defines the options for tracer provider of sdk.
TracerProviderOptions []sdktrace.TracerProviderOption
Disabled bool
}
@ -71,10 +72,10 @@ func WithBatchMaxCount(batchMaxCount int) Option {
}
}
// WithSDK sets the SDK config for the exporter pipeline.
func WithSDK(config *sdktrace.Config) Option {
// WithSDKOptions configures options for tracer provider of sdk.
func WithSDKOptions(opts ...sdktrace.TracerProviderOption) Option {
return func(o *options) {
o.Config = config
o.TracerProviderOptions = opts
}
}
@ -157,15 +158,7 @@ func NewExportPipeline(endpointOption EndpointOption, opts ...Option) (trace.Tra
return nil, nil, err
}
pOpts := []sdktrace.TracerProviderOption{sdktrace.WithSyncer(exporter)}
if exporter.o.Config != nil {
pOpts = append(pOpts,
sdktrace.WithSampler(exporter.o.Config.DefaultSampler),
sdktrace.WithIDGenerator(exporter.o.Config.IDGenerator),
sdktrace.WithSpanLimits(exporter.o.Config.SpanLimits),
sdktrace.WithResource(exporter.o.Config.Resource),
)
}
pOpts := append(exporter.o.TracerProviderOptions, sdktrace.WithSyncer(exporter))
tp := sdktrace.NewTracerProvider(pOpts...)
return tp, exporter.Flush, nil
}

View File

@ -17,6 +17,7 @@ package jaeger
import (
"context"
"encoding/binary"
"fmt"
"os"
"sort"
"strings"
@ -114,9 +115,7 @@ func TestNewExportPipeline(t *testing.T) {
name: "always on",
endpoint: WithCollectorEndpoint(collectorEndpoint),
options: []Option{
WithSDK(&sdktrace.Config{
DefaultSampler: sdktrace.AlwaysSample(),
}),
WithSDKOptions(sdktrace.WithSampler(sdktrace.AlwaysSample())),
},
expectedProviderType: &sdktrace.TracerProvider{},
testSpanSampling: true,
@ -126,9 +125,7 @@ func TestNewExportPipeline(t *testing.T) {
name: "never",
endpoint: WithCollectorEndpoint(collectorEndpoint),
options: []Option{
WithSDK(&sdktrace.Config{
DefaultSampler: sdktrace.NeverSample(),
}),
WithSDKOptions(sdktrace.WithSampler(sdktrace.NeverSample())),
},
expectedProviderType: &sdktrace.TracerProvider{},
testSpanSampling: true,
@ -281,11 +278,11 @@ func TestNewRawExporterShouldFailIfCollectorUnset(t *testing.T) {
}
type testCollectorEnpoint struct {
spansUploaded []*gen.Span
batchesUploaded []*gen.Batch
}
func (c *testCollectorEnpoint) upload(batch *gen.Batch) error {
c.spansUploaded = append(c.spansUploaded, batch.Spans...)
c.batchesUploaded = append(c.batchesUploaded, batch)
return nil
}
@ -297,6 +294,12 @@ func withTestCollectorEndpoint() func() (batchUploader, error) {
}
}
func withTestCollectorEndpointInjected(ce *testCollectorEnpoint) func() (batchUploader, error) {
return func() (batchUploader, error) {
return ce, nil
}
}
func TestExporter_ExportSpan(t *testing.T) {
const (
serviceName = "test-service"
@ -306,12 +309,12 @@ func TestExporter_ExportSpan(t *testing.T) {
// Create Jaeger Exporter
exp, err := NewRawExporter(
withTestCollectorEndpoint(),
WithSDK(&sdktrace.Config{
Resource: resource.NewWithAttributes(
WithSDKOptions(
sdktrace.WithResource(resource.NewWithAttributes(
semconv.ServiceNameKey.String(serviceName),
attribute.String(tagKey, tagVal),
),
}),
)),
),
)
assert.NoError(t, err)
@ -328,7 +331,8 @@ func TestExporter_ExportSpan(t *testing.T) {
exp.Flush()
tc := exp.uploader.(*testCollectorEnpoint)
assert.True(t, len(tc.spansUploaded) == 1)
assert.True(t, len(tc.batchesUploaded) == 1)
assert.True(t, len(tc.batchesUploaded[0].GetSpans()) == 1)
}
func Test_spanSnapshotToThrift(t *testing.T) {
@ -886,3 +890,50 @@ func TestProcess(t *testing.T) {
})
}
}
func TestNewExporterPipelineWithOptions(t *testing.T) {
envStore, err := ottest.SetEnvVariables(map[string]string{
envDisabled: "false",
})
require.NoError(t, err)
defer func() {
require.NoError(t, envStore.Restore())
}()
const (
serviceName = "test-service"
eventCountLimit = 10
)
testCollector := &testCollectorEnpoint{}
tp, spanFlush, err := NewExportPipeline(
withTestCollectorEndpointInjected(testCollector),
WithSDKOptions(
sdktrace.WithResource(resource.NewWithAttributes(
semconv.ServiceNameKey.String(serviceName),
)),
sdktrace.WithSpanLimits(sdktrace.SpanLimits{
EventCountLimit: eventCountLimit,
}),
),
)
assert.NoError(t, err)
otel.SetTracerProvider(tp)
_, span := otel.Tracer("test-tracer").Start(context.Background(), "test-span")
for i := 0; i < eventCountLimit*2; i++ {
span.AddEvent(fmt.Sprintf("event-%d", i))
}
span.End()
spanFlush()
assert.True(t, span.SpanContext().IsValid())
batchesUploaded := testCollector.batchesUploaded
assert.True(t, len(batchesUploaded) == 1)
uploadedBatch := batchesUploaded[0]
assert.Equal(t, serviceName, uploadedBatch.GetProcess().GetServiceName())
assert.True(t, len(uploadedBatch.GetSpans()) == 1)
uploadedSpan := uploadedBatch.GetSpans()[0]
assert.Equal(t, eventCountLimit, len(uploadedSpan.GetLogs()))
}

View File

@ -53,7 +53,7 @@ var (
type options struct {
client *http.Client
logger *log.Logger
config *sdktrace.Config
tpOpts []sdktrace.TracerProviderOption
}
// Option defines a function that configures the exporter.
@ -73,10 +73,10 @@ func WithClient(client *http.Client) Option {
}
}
// WithSDK sets the SDK config for the exporter pipeline.
func WithSDK(config *sdktrace.Config) Option {
return func(o *options) {
o.config = config
// WithSDKOptions configures options passed to the created TracerProvider.
func WithSDKOptions(tpOpts ...sdktrace.TracerProviderOption) Option {
return func(opts *options) {
opts.tpOpts = tpOpts
}
}
@ -116,10 +116,8 @@ func NewExportPipeline(collectorURL string, opts ...Option) (*sdktrace.TracerPro
return nil, err
}
tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter))
if exporter.o.config != nil {
tp.ApplyConfig(*exporter.o.config)
}
tpOpts := append(exporter.o.tpOpts, sdktrace.WithBatcher(exporter))
tp := sdktrace.NewTracerProvider(tpOpts...)
return tp, err
}

View File

@ -63,9 +63,7 @@ func TestNewExportPipeline(t *testing.T) {
{
name: "always on",
options: []Option{
WithSDK(&sdktrace.Config{
DefaultSampler: sdktrace.AlwaysSample(),
}),
WithSDKOptions(sdktrace.WithSampler(sdktrace.AlwaysSample())),
},
testSpanSampling: true,
spanShouldBeSampled: true,
@ -73,9 +71,7 @@ func TestNewExportPipeline(t *testing.T) {
{
name: "never",
options: []Option{
WithSDK(&sdktrace.Config{
DefaultSampler: sdktrace.NeverSample(),
}),
WithSDKOptions(sdktrace.WithSampler(sdktrace.NeverSample())),
},
testSpanSampling: true,
spanShouldBeSampled: false,
@ -389,3 +385,34 @@ func TestErrorOnExportShutdownExporter(t *testing.T) {
assert.NoError(t, exp.Shutdown(context.Background()))
assert.NoError(t, exp.ExportSpans(context.Background(), nil))
}
func TestNewExportPipelineWithOptions(t *testing.T) {
const eventCountLimit = 10
collector := startMockZipkinCollector(t)
defer collector.Close()
tp, err := NewExportPipeline(collector.url,
WithSDKOptions(
sdktrace.WithResource(resource.NewWithAttributes(
semconv.ServiceNameKey.String("zipkin-test"),
)),
sdktrace.WithSpanLimits(sdktrace.SpanLimits{
EventCountLimit: eventCountLimit,
}),
),
)
require.NoError(t, err)
otel.SetTracerProvider(tp)
_, span := otel.Tracer("zipkin-tracer").Start(context.Background(), "test-span")
for i := 0; i < eventCountLimit*2; i++ {
span.AddEvent(fmt.Sprintf("event-%d", i))
}
span.End()
require.NoError(t, tp.Shutdown(context.Background()))
require.Equal(t, 1, collector.ModelsLen())
model := collector.StealModels()[0]
require.Equal(t, len(model.Annotations), eventCountLimit)
}

View File

@ -14,25 +14,6 @@
package trace // import "go.opentelemetry.io/otel/sdk/trace"
import (
"go.opentelemetry.io/otel/sdk/resource"
)
// Config represents the global tracing configuration.
type Config struct {
// DefaultSampler is the default sampler used when creating new spans.
DefaultSampler Sampler
// IDGenerator is for internal use only.
IDGenerator IDGenerator
// SpanLimits used to limit the number of attributes, events and links to a span.
SpanLimits SpanLimits
// Resource contains attributes representing an entity that produces telemetry.
Resource *resource.Resource
}
// SpanLimits represents the limits of a span.
type SpanLimits struct {
// AttributeCountLimit is the maximum allowed span attribute count.
@ -51,6 +32,24 @@ type SpanLimits struct {
AttributePerLinkCountLimit int
}
func (sl *SpanLimits) ensureDefault() {
if sl.EventCountLimit <= 0 {
sl.EventCountLimit = DefaultEventCountLimit
}
if sl.AttributeCountLimit <= 0 {
sl.AttributeCountLimit = DefaultAttributeCountLimit
}
if sl.LinkCountLimit <= 0 {
sl.LinkCountLimit = DefaultLinkCountLimit
}
if sl.AttributePerEventCountLimit <= 0 {
sl.AttributePerEventCountLimit = DefaultAttributePerEventCountLimit
}
if sl.AttributePerLinkCountLimit <= 0 {
sl.AttributePerLinkCountLimit = DefaultAttributePerLinkCountLimit
}
}
const (
// DefaultAttributeCountLimit is the default maximum allowed span attribute count.
DefaultAttributeCountLimit = 128

View File

@ -38,7 +38,18 @@ const (
// TracerProviderConfig
type TracerProviderConfig struct {
processors []SpanProcessor
config Config
// sampler is the default sampler used when creating new spans.
sampler Sampler
// idGenerator is used to generate all Span and Trace IDs when needed.
idGenerator IDGenerator
// spanLimits defines the attribute, event, and link limits for spans.
spanLimits SpanLimits
// resource contains attributes representing an entity that produces telemetry.
resource *resource.Resource
}
type TracerProviderOption func(*TracerProviderConfig)
@ -47,7 +58,10 @@ type TracerProvider struct {
mu sync.Mutex
namedTracer map[instrumentation.Library]*tracer
spanProcessors atomic.Value
config atomic.Value // access atomically
sampler Sampler
idGenerator IDGenerator
spanLimits SpanLimits
resource *resource.Resource
}
var _ trace.TracerProvider = &TracerProvider{}
@ -69,27 +83,20 @@ func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider {
opt(o)
}
ensureValidTracerProviderConfig(o)
tp := &TracerProvider{
namedTracer: make(map[instrumentation.Library]*tracer),
sampler: o.sampler,
idGenerator: o.idGenerator,
spanLimits: o.spanLimits,
resource: o.resource,
}
tp.config.Store(&Config{
DefaultSampler: ParentBased(AlwaysSample()),
IDGenerator: defaultIDGenerator(),
SpanLimits: SpanLimits{
AttributeCountLimit: DefaultAttributeCountLimit,
EventCountLimit: DefaultEventCountLimit,
LinkCountLimit: DefaultLinkCountLimit,
AttributePerEventCountLimit: DefaultAttributePerEventCountLimit,
AttributePerLinkCountLimit: DefaultAttributePerLinkCountLimit,
},
})
for _, sp := range o.processors {
tp.RegisterSpanProcessor(sp)
}
tp.ApplyConfig(o.config)
return tp
}
@ -175,40 +182,6 @@ func (p *TracerProvider) UnregisterSpanProcessor(s SpanProcessor) {
p.spanProcessors.Store(spss)
}
// ApplyConfig changes the configuration of the provider.
// If a field in the configuration is empty or nil then its original value is preserved.
func (p *TracerProvider) ApplyConfig(cfg Config) {
p.mu.Lock()
defer p.mu.Unlock()
c := *p.config.Load().(*Config)
if cfg.DefaultSampler != nil {
c.DefaultSampler = cfg.DefaultSampler
}
if cfg.IDGenerator != nil {
c.IDGenerator = cfg.IDGenerator
}
if cfg.SpanLimits.EventCountLimit > 0 {
c.SpanLimits.EventCountLimit = cfg.SpanLimits.EventCountLimit
}
if cfg.SpanLimits.AttributeCountLimit > 0 {
c.SpanLimits.AttributeCountLimit = cfg.SpanLimits.AttributeCountLimit
}
if cfg.SpanLimits.LinkCountLimit > 0 {
c.SpanLimits.LinkCountLimit = cfg.SpanLimits.LinkCountLimit
}
if cfg.SpanLimits.AttributePerEventCountLimit > 0 {
c.SpanLimits.AttributePerEventCountLimit = cfg.SpanLimits.AttributePerEventCountLimit
}
if cfg.SpanLimits.AttributePerLinkCountLimit > 0 {
c.SpanLimits.AttributePerLinkCountLimit = cfg.SpanLimits.AttributePerLinkCountLimit
}
c.Resource = cfg.Resource
if c.Resource == nil {
c.Resource = resource.Default()
}
p.config.Store(&c)
}
// ForceFlush immediately exports all spans that have not yet been exported for
// all the registered span processors.
func (p *TracerProvider) ForceFlush(ctx context.Context) error {
@ -290,7 +263,9 @@ func WithSpanProcessor(sp SpanProcessor) TracerProviderOption {
// resource.Default() Resource by default.
func WithResource(r *resource.Resource) TracerProviderOption {
return func(opts *TracerProviderConfig) {
opts.config.Resource = r
if r != nil {
opts.resource = r
}
}
}
@ -303,7 +278,9 @@ func WithResource(r *resource.Resource) TracerProviderOption {
// IDGenerator by default.
func WithIDGenerator(g IDGenerator) TracerProviderOption {
return func(opts *TracerProviderConfig) {
opts.config.IDGenerator = g
if g != nil {
opts.idGenerator = g
}
}
}
@ -316,7 +293,9 @@ func WithIDGenerator(g IDGenerator) TracerProviderOption {
// ParentBased(AlwaysSample) Sampler by default.
func WithSampler(s Sampler) TracerProviderOption {
return func(opts *TracerProviderConfig) {
opts.config.DefaultSampler = s
if s != nil {
opts.sampler = s
}
}
}
@ -329,6 +308,20 @@ func WithSampler(s Sampler) TracerProviderOption {
// SpanLimits.
func WithSpanLimits(sl SpanLimits) TracerProviderOption {
return func(opts *TracerProviderConfig) {
opts.config.SpanLimits = sl
opts.spanLimits = sl
}
}
// ensureValidTracerProviderConfig ensures that given TracerProviderConfig is valid.
func ensureValidTracerProviderConfig(cfg *TracerProviderConfig) {
if cfg.sampler == nil {
cfg.sampler = ParentBased(AlwaysSample())
}
if cfg.idGenerator == nil {
cfg.idGenerator = defaultIDGenerator()
}
cfg.spanLimits.ensureDefault()
if cfg.resource == nil {
cfg.resource = resource.Default()
}
}

View File

@ -521,18 +521,18 @@ func (*span) private() {}
func startSpanInternal(ctx context.Context, tr *tracer, name string, parent trace.SpanContext, remoteParent bool, o *trace.SpanConfig) *span {
span := &span{}
cfg := tr.provider.config.Load().(*Config)
provider := tr.provider
var tid trace.TraceID
var sid trace.SpanID
if hasEmptySpanContext(parent) {
// Generate both TraceID and SpanID
tid, sid = cfg.IDGenerator.NewIDs(ctx)
tid, sid = provider.idGenerator.NewIDs(ctx)
} else {
// TraceID already exists, just generate a SpanID
tid = parent.TraceID()
sid = cfg.IDGenerator.NewSpanID(ctx, tid)
sid = provider.idGenerator.NewSpanID(ctx, tid)
}
span.spanContext = trace.NewSpanContext(trace.SpanContextConfig{
@ -542,17 +542,18 @@ func startSpanInternal(ctx context.Context, tr *tracer, name string, parent trac
TraceState: parent.TraceState(),
})
span.attributes = newAttributesMap(cfg.SpanLimits.AttributeCountLimit)
span.messageEvents = newEvictedQueue(cfg.SpanLimits.EventCountLimit)
span.links = newEvictedQueue(cfg.SpanLimits.LinkCountLimit)
span.spanLimits = cfg.SpanLimits
spanLimits := provider.spanLimits
span.attributes = newAttributesMap(spanLimits.AttributeCountLimit)
span.messageEvents = newEvictedQueue(spanLimits.EventCountLimit)
span.links = newEvictedQueue(spanLimits.LinkCountLimit)
span.spanLimits = spanLimits
data := samplingData{
noParent: hasEmptySpanContext(parent),
remoteParent: remoteParent,
parent: parent,
name: name,
cfg: cfg,
sampler: provider.sampler,
span: span,
attributes: o.Attributes,
links: o.Links,
@ -579,7 +580,7 @@ func startSpanInternal(ctx context.Context, tr *tracer, name string, parent trac
span.spanKind = trace.ValidateSpanKind(o.SpanKind)
span.name = name
span.hasRemoteParent = remoteParent
span.resource = cfg.Resource
span.resource = provider.resource
span.instrumentationLibrary = tr.instrumentationLibrary
span.SetAttributes(samplingResult.Attributes...)
@ -598,7 +599,7 @@ type samplingData struct {
remoteParent bool
parent trace.SpanContext
name string
cfg *Config
sampler Sampler
span *span
attributes []attribute.KeyValue
links []trace.Link
@ -606,8 +607,7 @@ type samplingData struct {
}
func makeSamplingDecision(data samplingData) SamplingResult {
sampler := data.cfg.DefaultSampler
return sampler.ShouldSample(SamplingParameters{
return data.sampler.ShouldSample(SamplingParameters{
ParentContext: data.parent,
TraceID: data.span.spanContext.TraceID(),
Name: data.name,

View File

@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"math"
"strconv"
"strings"
"sync"
"sync/atomic"
@ -1375,11 +1376,10 @@ func TestReadOnlySpan(t *testing.T) {
kv := attribute.String("foo", "bar")
tp := NewTracerProvider(WithResource(resource.NewWithAttributes(kv)))
cfg := tp.config.Load().(*Config)
tr := tp.Tracer("ReadOnlySpan", trace.WithInstrumentationVersion("3"))
// Initialize parent context.
tID, sID := cfg.IDGenerator.NewIDs(context.Background())
tID, sID := tp.idGenerator.NewIDs(context.Background())
parent := trace.NewSpanContext(trace.SpanContextConfig{
TraceID: tID,
SpanID: sID,
@ -1389,7 +1389,7 @@ func TestReadOnlySpan(t *testing.T) {
ctx := trace.ContextWithRemoteSpanContext(context.Background(), parent)
// Initialize linked context.
tID, sID = cfg.IDGenerator.NewIDs(context.Background())
tID, sID = tp.idGenerator.NewIDs(context.Background())
linked := trace.NewSpanContext(trace.SpanContextConfig{
TraceID: tID,
SpanID: sID,
@ -1456,11 +1456,10 @@ func TestReadOnlySpan(t *testing.T) {
func TestReadWriteSpan(t *testing.T) {
tp := NewTracerProvider(WithResource(resource.Empty()))
cfg := tp.config.Load().(*Config)
tr := tp.Tracer("ReadWriteSpan")
// Initialize parent context.
tID, sID := cfg.IDGenerator.NewIDs(context.Background())
tID, sID := tp.idGenerator.NewIDs(context.Background())
parent := trace.NewSpanContext(trace.SpanContextConfig{
TraceID: tID,
SpanID: sID,
@ -1742,3 +1741,51 @@ func TestSamplerTraceState(t *testing.T) {
}
}
type testIDGenerator struct {
traceID int
spanID int
}
func (gen *testIDGenerator) NewIDs(ctx context.Context) (trace.TraceID, trace.SpanID) {
traceIDHex := fmt.Sprintf("%032x", gen.traceID)
traceID, _ := trace.TraceIDFromHex(traceIDHex)
gen.traceID++
spanID := gen.NewSpanID(ctx, traceID)
return traceID, spanID
}
func (gen *testIDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) trace.SpanID {
spanIDHex := fmt.Sprintf("%016x", gen.spanID)
spanID, _ := trace.SpanIDFromHex(spanIDHex)
gen.spanID++
return spanID
}
var _ IDGenerator = (*testIDGenerator)(nil)
func TestWithIDGenerator(t *testing.T) {
const (
startTraceID = 1
startSpanID = 1
numSpan = 10
)
gen := &testIDGenerator{traceID: startSpanID, spanID: startSpanID}
for i := 0; i < numSpan; i++ {
te := NewTestExporter()
tp := NewTracerProvider(
WithSyncer(te),
WithIDGenerator(gen),
)
span := startSpan(tp, "TestWithIDGenerator")
got, err := strconv.ParseUint(span.SpanContext().SpanID().String(), 16, 64)
require.NoError(t, err)
want := uint64(startSpanID + i)
assert.Equal(t, got, want)
_, err = endSpan(te, span)
require.NoError(t, err)
}
}