Skip to content

Commit

Permalink
Enable support for externally-defined ID generators (open-telemetry#1363
Browse files Browse the repository at this point in the history
)

* 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>
  • Loading branch information
Aneurysm9 and krnowak authored Dec 10, 2020
1 parent 0021ab0 commit 970755b
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 76 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
3 changes: 1 addition & 2 deletions sdk/trace/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
35 changes: 26 additions & 9 deletions sdk/trace/id_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,53 @@
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{}
gen.randSource.Read(sid[:])
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
}
24 changes: 0 additions & 24 deletions sdk/trace/internal/internal.go

This file was deleted.

9 changes: 8 additions & 1 deletion sdk/trace/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
}
5 changes: 3 additions & 2 deletions sdk/trace/sampling_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package trace

import (
"context"
"fmt"
"math/rand"
"testing"
Expand Down Expand Up @@ -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()
Expand All @@ -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 {
Expand Down
10 changes: 7 additions & 3 deletions sdk/trace/span.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package trace // import "go.opentelemetry.io/otel/sdk/trace"

import (
"context"
"errors"
"fmt"
"reflect"
Expand Down Expand Up @@ -306,18 +307,21 @@ 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

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,
Expand Down
31 changes: 0 additions & 31 deletions sdk/trace/trace.go

This file was deleted.

7 changes: 4 additions & 3 deletions sdk/trace/trace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion sdk/trace/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down

0 comments on commit 970755b

Please sign in to comment.