mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-03-03 14:52:56 +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:
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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user