You've already forked opentelemetry-go
							
							
				mirror of
				https://github.com/open-telemetry/opentelemetry-go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	Enable support for externally-defined ID generators (#1363)
* Enable support for externally-defined ID generators * Moved the SDK's `internal.IDGenerator` interface to the `sdk/trace` package. * Added `trace.WithIDGenerator()` `TracerProviderOption`. Signed-off-by: Anthony J Mirabella <a9@aneurysm9.com> * Update CHANGELOG.md with PR info * Address PR feedback: * Fix IDGenerator godoc comment * rename type defaultIDGenerator to randomIDGenerator * rename defIDGenerator() to defaultIDGenerator() Signed-off-by: Anthony J Mirabella <a9@aneurysm9.com> * Rework trace.IDGenerator interface * NewTraceID() -> NewIDs(ctx) ** Returns both TraceID and SpanID * NewSpanID() -> NewSpanID(ctx, traceID) ** Returns only SpanID, has access to TraceID * Both methods now receive a context, from which they may extract information * startSpanInternal() updated to receive a context to pass to the ID generator * Drop outdated comment from docblock Co-authored-by: Krzesimir Nowak <qdlacz@gmail.com> Co-authored-by: Krzesimir Nowak <qdlacz@gmail.com>
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							0021ab0a3a
						
					
				
				
					commit
					970755bd08
				
			| @@ -8,9 +8,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm | ||||
|  | ||||
| ## [Unreleased] | ||||
|  | ||||
| ### Added | ||||
|  | ||||
| - `trace.WithIDGenerator()` `TracerProviderOption`. (#1363) | ||||
|  | ||||
| ### Changed | ||||
|  | ||||
| - Move the OpenCensus example into `example` directory. (#1359) | ||||
| - Moved the SDK's `internal.IDGenerator` interface in to the `sdk/trace` package to enable support for externally-defined ID generators. (#1363) | ||||
| - `NewExporter` and `Start` functions in `go.opentelemetry.io/otel/exporters/otlp` now receive `context.Context` as a first parameter. (#1357) | ||||
| - Zipkin exporter relies on the status code for success rather than body read but still read the response body. (#1328) | ||||
|  | ||||
|   | ||||
| @@ -16,7 +16,6 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace" | ||||
|  | ||||
| import ( | ||||
| 	"go.opentelemetry.io/otel/sdk/resource" | ||||
| 	"go.opentelemetry.io/otel/sdk/trace/internal" | ||||
| ) | ||||
|  | ||||
| // Config represents the global tracing configuration. | ||||
| @@ -25,7 +24,7 @@ type Config struct { | ||||
| 	DefaultSampler Sampler | ||||
|  | ||||
| 	// IDGenerator is for internal use only. | ||||
| 	IDGenerator internal.IDGenerator | ||||
| 	IDGenerator IDGenerator | ||||
|  | ||||
| 	// MaxEventsPerSpan is max number of message events per span | ||||
| 	MaxEventsPerSpan int | ||||
|   | ||||
| @@ -15,23 +15,30 @@ | ||||
| package trace // import "go.opentelemetry.io/otel/sdk/trace" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	crand "crypto/rand" | ||||
| 	"encoding/binary" | ||||
| 	"math/rand" | ||||
| 	"sync" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/sdk/trace/internal" | ||||
| ) | ||||
|  | ||||
| type defaultIDGenerator struct { | ||||
| // IDGenerator allows custom generators for TraceID and SpanID. | ||||
| type IDGenerator interface { | ||||
| 	NewIDs(ctx context.Context) (trace.TraceID, trace.SpanID) | ||||
| 	NewSpanID(ctx context.Context, traceID trace.TraceID) trace.SpanID | ||||
| } | ||||
|  | ||||
| type randomIDGenerator struct { | ||||
| 	sync.Mutex | ||||
| 	randSource *rand.Rand | ||||
| } | ||||
|  | ||||
| var _ internal.IDGenerator = &defaultIDGenerator{} | ||||
| var _ IDGenerator = &randomIDGenerator{} | ||||
|  | ||||
| // NewSpanID returns a non-zero span ID from a randomly-chosen sequence. | ||||
| func (gen *defaultIDGenerator) NewSpanID() trace.SpanID { | ||||
| func (gen *randomIDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) trace.SpanID { | ||||
| 	gen.Lock() | ||||
| 	defer gen.Unlock() | ||||
| 	sid := trace.SpanID{} | ||||
| @@ -39,12 +46,22 @@ func (gen *defaultIDGenerator) NewSpanID() trace.SpanID { | ||||
| 	return sid | ||||
| } | ||||
|  | ||||
| // NewTraceID returns a non-zero trace ID from a randomly-chosen sequence. | ||||
| // mu should be held while this function is called. | ||||
| func (gen *defaultIDGenerator) NewTraceID() trace.TraceID { | ||||
| // NewIDs returns a non-zero trace ID and a non-zero span ID from a | ||||
| // randomly-chosen sequence. | ||||
| func (gen *randomIDGenerator) NewIDs(ctx context.Context) (trace.TraceID, trace.SpanID) { | ||||
| 	gen.Lock() | ||||
| 	defer gen.Unlock() | ||||
| 	tid := trace.TraceID{} | ||||
| 	gen.randSource.Read(tid[:]) | ||||
| 	return tid | ||||
| 	sid := trace.SpanID{} | ||||
| 	gen.randSource.Read(sid[:]) | ||||
| 	return tid, sid | ||||
| } | ||||
|  | ||||
| func defaultIDGenerator() IDGenerator { | ||||
| 	gen := &randomIDGenerator{} | ||||
| 	var rngSeed int64 | ||||
| 	_ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) | ||||
| 	gen.randSource = rand.New(rand.NewSource(rngSeed)) | ||||
| 	return gen | ||||
| } | ||||
|   | ||||
| @@ -1,24 +0,0 @@ | ||||
| // Copyright The OpenTelemetry Authors | ||||
| // | ||||
| // 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 internal provides trace internals. | ||||
| package internal | ||||
|  | ||||
| import "go.opentelemetry.io/otel/trace" | ||||
|  | ||||
| // IDGenerator allows custom generators for TraceId and SpanId. | ||||
| type IDGenerator interface { | ||||
| 	NewTraceID() trace.TraceID | ||||
| 	NewSpanID() trace.SpanID | ||||
| } | ||||
| @@ -66,7 +66,7 @@ func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider { | ||||
| 	} | ||||
| 	tp.config.Store(&Config{ | ||||
| 		DefaultSampler:       ParentBased(AlwaysSample()), | ||||
| 		IDGenerator:          defIDGenerator(), | ||||
| 		IDGenerator:          defaultIDGenerator(), | ||||
| 		MaxAttributesPerSpan: DefaultMaxAttributesPerSpan, | ||||
| 		MaxEventsPerSpan:     DefaultMaxEventsPerSpan, | ||||
| 		MaxLinksPerSpan:      DefaultMaxLinksPerSpan, | ||||
| @@ -231,3 +231,10 @@ func WithResource(r *resource.Resource) TracerProviderOption { | ||||
| 		opts.config.Resource = r | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithIDGenerator option registers an IDGenerator with the TracerProvider. | ||||
| func WithIDGenerator(g IDGenerator) TracerProviderOption { | ||||
| 	return func(opts *TracerProviderConfig) { | ||||
| 		opts.config.IDGenerator = g | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| package trace | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"math/rand" | ||||
| 	"testing" | ||||
| @@ -168,7 +169,7 @@ func TestTraceIdRatioSamplesInclusively(t *testing.T) { | ||||
| 		numSamplers = 1000 | ||||
| 		numTraces   = 100 | ||||
| 	) | ||||
| 	idg := defIDGenerator() | ||||
| 	idg := defaultIDGenerator() | ||||
|  | ||||
| 	for i := 0; i < numSamplers; i++ { | ||||
| 		ratioLo, ratioHi := rand.Float64(), rand.Float64() | ||||
| @@ -178,7 +179,7 @@ func TestTraceIdRatioSamplesInclusively(t *testing.T) { | ||||
| 		samplerHi := TraceIDRatioBased(ratioHi) | ||||
| 		samplerLo := TraceIDRatioBased(ratioLo) | ||||
| 		for j := 0; j < numTraces; j++ { | ||||
| 			traceID := idg.NewTraceID() | ||||
| 			traceID, _ := idg.NewIDs(context.Background()) | ||||
|  | ||||
| 			params := SamplingParameters{TraceID: traceID} | ||||
| 			if samplerLo.ShouldSample(params).Decision == RecordAndSample { | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| package trace // import "go.opentelemetry.io/otel/sdk/trace" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| @@ -306,7 +307,7 @@ func (s *span) addChild() { | ||||
| 	s.mu.Unlock() | ||||
| } | ||||
|  | ||||
| func startSpanInternal(tr *tracer, name string, parent trace.SpanContext, remoteParent bool, o *trace.SpanConfig) *span { | ||||
| func startSpanInternal(ctx context.Context, tr *tracer, name string, parent trace.SpanContext, remoteParent bool, o *trace.SpanConfig) *span { | ||||
| 	var noParent bool | ||||
| 	span := &span{} | ||||
| 	span.spanContext = parent | ||||
| @@ -314,10 +315,13 @@ func startSpanInternal(tr *tracer, name string, parent trace.SpanContext, remote | ||||
| 	cfg := tr.provider.config.Load().(*Config) | ||||
|  | ||||
| 	if parent == emptySpanContext { | ||||
| 		span.spanContext.TraceID = cfg.IDGenerator.NewTraceID() | ||||
| 		// Generate both TraceID and SpanID | ||||
| 		span.spanContext.TraceID, span.spanContext.SpanID = cfg.IDGenerator.NewIDs(ctx) | ||||
| 		noParent = true | ||||
| 	} else { | ||||
| 		// TraceID already exists, just generate a SpanID | ||||
| 		span.spanContext.SpanID = cfg.IDGenerator.NewSpanID(ctx, parent.TraceID) | ||||
| 	} | ||||
| 	span.spanContext.SpanID = cfg.IDGenerator.NewSpanID() | ||||
| 	data := samplingData{ | ||||
| 		noParent:     noParent, | ||||
| 		remoteParent: remoteParent, | ||||
|   | ||||
| @@ -1,31 +0,0 @@ | ||||
| // Copyright The OpenTelemetry Authors | ||||
| // | ||||
| // 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 // import "go.opentelemetry.io/otel/sdk/trace" | ||||
|  | ||||
| import ( | ||||
| 	crand "crypto/rand" | ||||
| 	"encoding/binary" | ||||
| 	"math/rand" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/sdk/trace/internal" | ||||
| ) | ||||
|  | ||||
| func defIDGenerator() internal.IDGenerator { | ||||
| 	gen := &defaultIDGenerator{} | ||||
| 	var rngSeed int64 | ||||
| 	_ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) | ||||
| 	gen.randSource = rand.New(rand.NewSource(rngSeed)) | ||||
| 	return gen | ||||
| } | ||||
| @@ -213,7 +213,7 @@ func TestRecordingIsOn(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestSampling(t *testing.T) { | ||||
| 	idg := defIDGenerator() | ||||
| 	idg := defaultIDGenerator() | ||||
| 	const total = 10000 | ||||
| 	for name, tc := range map[string]struct { | ||||
| 		sampler       Sampler | ||||
| @@ -263,9 +263,10 @@ func TestSampling(t *testing.T) { | ||||
| 			for i := 0; i < total; i++ { | ||||
| 				ctx := context.Background() | ||||
| 				if tc.parent { | ||||
| 					tid, sid := idg.NewIDs(ctx) | ||||
| 					psc := trace.SpanContext{ | ||||
| 						TraceID: idg.NewTraceID(), | ||||
| 						SpanID:  idg.NewSpanID(), | ||||
| 						TraceID: tid, | ||||
| 						SpanID:  sid, | ||||
| 					} | ||||
| 					if tc.sampledParent { | ||||
| 						psc.TraceFlags = trace.FlagsSampled | ||||
|   | ||||
| @@ -47,7 +47,7 @@ func (tr *tracer) Start(ctx context.Context, name string, options ...trace.SpanO | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	span := startSpanInternal(tr, name, parentSpanContext, remoteParent, config) | ||||
| 	span := startSpanInternal(ctx, tr, name, parentSpanContext, remoteParent, config) | ||||
| 	for _, l := range links { | ||||
| 		span.addLink(l) | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user