1
0
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:
Anthony Mirabella 2020-12-09 20:30:32 -05:00 committed by GitHub
parent 0021ab0a3a
commit 970755bd08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 55 additions and 76 deletions

View File

@ -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)

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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 {

View File

@ -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,

View File

@ -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
}

View File

@ -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

View File

@ -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)
}