mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 10:03:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			346 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			346 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 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 (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"sync"
 | 
						|
	"sync/atomic"
 | 
						|
 | 
						|
	"go.opentelemetry.io/otel"
 | 
						|
	"go.opentelemetry.io/otel/trace"
 | 
						|
 | 
						|
	"go.opentelemetry.io/otel/sdk/instrumentation"
 | 
						|
	"go.opentelemetry.io/otel/sdk/resource"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	defaultTracerName = "go.opentelemetry.io/otel/sdk/tracer"
 | 
						|
)
 | 
						|
 | 
						|
// tracerProviderConfig
 | 
						|
type tracerProviderConfig struct {
 | 
						|
	// processors contains collection of SpanProcessors that are processing pipeline
 | 
						|
	// for spans in the trace signal.
 | 
						|
	// SpanProcessors registered with a TracerProvider and are called at the start
 | 
						|
	// and end of a Span's lifecycle, and are called in the order they are
 | 
						|
	// registered.
 | 
						|
	processors []SpanProcessor
 | 
						|
 | 
						|
	// 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 TracerProvider struct {
 | 
						|
	mu             sync.Mutex
 | 
						|
	namedTracer    map[instrumentation.Library]*tracer
 | 
						|
	spanProcessors atomic.Value
 | 
						|
	sampler        Sampler
 | 
						|
	idGenerator    IDGenerator
 | 
						|
	spanLimits     SpanLimits
 | 
						|
	resource       *resource.Resource
 | 
						|
}
 | 
						|
 | 
						|
var _ trace.TracerProvider = &TracerProvider{}
 | 
						|
 | 
						|
// NewTracerProvider returns a new and configured TracerProvider.
 | 
						|
//
 | 
						|
// By default the returned TracerProvider is configured with:
 | 
						|
//  - a ParentBased(AlwaysSample) Sampler
 | 
						|
//  - a random number IDGenerator
 | 
						|
//  - the resource.Default() Resource
 | 
						|
//  - the default SpanLimits.
 | 
						|
//
 | 
						|
// The passed opts are used to override these default values and configure the
 | 
						|
// returned TracerProvider appropriately.
 | 
						|
func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider {
 | 
						|
	o := &tracerProviderConfig{}
 | 
						|
 | 
						|
	for _, opt := range opts {
 | 
						|
		opt.apply(o)
 | 
						|
	}
 | 
						|
 | 
						|
	ensureValidTracerProviderConfig(o)
 | 
						|
 | 
						|
	tp := &TracerProvider{
 | 
						|
		namedTracer: make(map[instrumentation.Library]*tracer),
 | 
						|
		sampler:     o.sampler,
 | 
						|
		idGenerator: o.idGenerator,
 | 
						|
		spanLimits:  o.spanLimits,
 | 
						|
		resource:    o.resource,
 | 
						|
	}
 | 
						|
 | 
						|
	for _, sp := range o.processors {
 | 
						|
		tp.RegisterSpanProcessor(sp)
 | 
						|
	}
 | 
						|
 | 
						|
	return tp
 | 
						|
}
 | 
						|
 | 
						|
// Tracer returns a Tracer with the given name and options. If a Tracer for
 | 
						|
// the given name and options does not exist it is created, otherwise the
 | 
						|
// existing Tracer is returned.
 | 
						|
//
 | 
						|
// If name is empty, DefaultTracerName is used instead.
 | 
						|
//
 | 
						|
// This method is safe to be called concurrently.
 | 
						|
func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer {
 | 
						|
	c := trace.NewTracerConfig(opts...)
 | 
						|
 | 
						|
	p.mu.Lock()
 | 
						|
	defer p.mu.Unlock()
 | 
						|
	if name == "" {
 | 
						|
		name = defaultTracerName
 | 
						|
	}
 | 
						|
	il := instrumentation.Library{
 | 
						|
		Name:      name,
 | 
						|
		Version:   c.InstrumentationVersion(),
 | 
						|
		SchemaURL: c.SchemaURL(),
 | 
						|
	}
 | 
						|
	t, ok := p.namedTracer[il]
 | 
						|
	if !ok {
 | 
						|
		t = &tracer{
 | 
						|
			provider:               p,
 | 
						|
			instrumentationLibrary: il,
 | 
						|
		}
 | 
						|
		p.namedTracer[il] = t
 | 
						|
	}
 | 
						|
	return t
 | 
						|
}
 | 
						|
 | 
						|
// RegisterSpanProcessor adds the given SpanProcessor to the list of SpanProcessors
 | 
						|
func (p *TracerProvider) RegisterSpanProcessor(s SpanProcessor) {
 | 
						|
	p.mu.Lock()
 | 
						|
	defer p.mu.Unlock()
 | 
						|
	new := spanProcessorStates{}
 | 
						|
	if old, ok := p.spanProcessors.Load().(spanProcessorStates); ok {
 | 
						|
		new = append(new, old...)
 | 
						|
	}
 | 
						|
	newSpanSync := &spanProcessorState{
 | 
						|
		sp:    s,
 | 
						|
		state: &sync.Once{},
 | 
						|
	}
 | 
						|
	new = append(new, newSpanSync)
 | 
						|
	p.spanProcessors.Store(new)
 | 
						|
}
 | 
						|
 | 
						|
// UnregisterSpanProcessor removes the given SpanProcessor from the list of SpanProcessors
 | 
						|
func (p *TracerProvider) UnregisterSpanProcessor(s SpanProcessor) {
 | 
						|
	p.mu.Lock()
 | 
						|
	defer p.mu.Unlock()
 | 
						|
	spss := spanProcessorStates{}
 | 
						|
	old, ok := p.spanProcessors.Load().(spanProcessorStates)
 | 
						|
	if !ok || len(old) == 0 {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	spss = append(spss, old...)
 | 
						|
 | 
						|
	// stop the span processor if it is started and remove it from the list
 | 
						|
	var stopOnce *spanProcessorState
 | 
						|
	var idx int
 | 
						|
	for i, sps := range spss {
 | 
						|
		if sps.sp == s {
 | 
						|
			stopOnce = sps
 | 
						|
			idx = i
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if stopOnce != nil {
 | 
						|
		stopOnce.state.Do(func() {
 | 
						|
			if err := s.Shutdown(context.Background()); err != nil {
 | 
						|
				otel.Handle(err)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
	if len(spss) > 1 {
 | 
						|
		copy(spss[idx:], spss[idx+1:])
 | 
						|
	}
 | 
						|
	spss[len(spss)-1] = nil
 | 
						|
	spss = spss[:len(spss)-1]
 | 
						|
 | 
						|
	p.spanProcessors.Store(spss)
 | 
						|
}
 | 
						|
 | 
						|
// 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 {
 | 
						|
	spss, ok := p.spanProcessors.Load().(spanProcessorStates)
 | 
						|
	if !ok {
 | 
						|
		return fmt.Errorf("failed to load span processors")
 | 
						|
	}
 | 
						|
	if len(spss) == 0 {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	for _, sps := range spss {
 | 
						|
		select {
 | 
						|
		case <-ctx.Done():
 | 
						|
			return ctx.Err()
 | 
						|
		default:
 | 
						|
		}
 | 
						|
 | 
						|
		if err := sps.sp.ForceFlush(ctx); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Shutdown shuts down the span processors in the order they were registered.
 | 
						|
func (p *TracerProvider) Shutdown(ctx context.Context) error {
 | 
						|
	spss, ok := p.spanProcessors.Load().(spanProcessorStates)
 | 
						|
	if !ok {
 | 
						|
		return fmt.Errorf("failed to load span processors")
 | 
						|
	}
 | 
						|
	if len(spss) == 0 {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	for _, sps := range spss {
 | 
						|
		select {
 | 
						|
		case <-ctx.Done():
 | 
						|
			return ctx.Err()
 | 
						|
		default:
 | 
						|
		}
 | 
						|
 | 
						|
		var err error
 | 
						|
		sps.state.Do(func() {
 | 
						|
			err = sps.sp.Shutdown(ctx)
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
type TracerProviderOption interface {
 | 
						|
	apply(*tracerProviderConfig)
 | 
						|
}
 | 
						|
 | 
						|
type traceProviderOptionFunc func(*tracerProviderConfig)
 | 
						|
 | 
						|
func (fn traceProviderOptionFunc) apply(cfg *tracerProviderConfig) {
 | 
						|
	fn(cfg)
 | 
						|
}
 | 
						|
 | 
						|
// WithSyncer registers the exporter with the TracerProvider using a
 | 
						|
// SimpleSpanProcessor.
 | 
						|
//
 | 
						|
// This is not recommended for production use. The synchronous nature of the
 | 
						|
// SimpleSpanProcessor that will wrap the exporter make it good for testing,
 | 
						|
// debugging, or showing examples of other feature, but it will be slow and
 | 
						|
// have a high computation resource usage overhead. The WithBatcher option is
 | 
						|
// recommended for production use instead.
 | 
						|
func WithSyncer(e SpanExporter) TracerProviderOption {
 | 
						|
	return WithSpanProcessor(NewSimpleSpanProcessor(e))
 | 
						|
}
 | 
						|
 | 
						|
// WithBatcher registers the exporter with the TracerProvider using a
 | 
						|
// BatchSpanProcessor configured with the passed opts.
 | 
						|
func WithBatcher(e SpanExporter, opts ...BatchSpanProcessorOption) TracerProviderOption {
 | 
						|
	return WithSpanProcessor(NewBatchSpanProcessor(e, opts...))
 | 
						|
}
 | 
						|
 | 
						|
// WithSpanProcessor registers the SpanProcessor with a TracerProvider.
 | 
						|
func WithSpanProcessor(sp SpanProcessor) TracerProviderOption {
 | 
						|
	return traceProviderOptionFunc(func(cfg *tracerProviderConfig) {
 | 
						|
		cfg.processors = append(cfg.processors, sp)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// WithResource returns a TracerProviderOption that will configure the
 | 
						|
// Resource r as a TracerProvider's Resource. The configured Resource is
 | 
						|
// referenced by all the Tracers the TracerProvider creates. It represents the
 | 
						|
// entity producing telemetry.
 | 
						|
//
 | 
						|
// If this option is not used, the TracerProvider will use the
 | 
						|
// resource.Default() Resource by default.
 | 
						|
func WithResource(r *resource.Resource) TracerProviderOption {
 | 
						|
	return traceProviderOptionFunc(func(cfg *tracerProviderConfig) {
 | 
						|
		var err error
 | 
						|
		cfg.resource, err = resource.Merge(resource.Environment(), r)
 | 
						|
		if err != nil {
 | 
						|
			otel.Handle(err)
 | 
						|
		}
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// WithIDGenerator returns a TracerProviderOption that will configure the
 | 
						|
// IDGenerator g as a TracerProvider's IDGenerator. The configured IDGenerator
 | 
						|
// is used by the Tracers the TracerProvider creates to generate new Span and
 | 
						|
// Trace IDs.
 | 
						|
//
 | 
						|
// If this option is not used, the TracerProvider will use a random number
 | 
						|
// IDGenerator by default.
 | 
						|
func WithIDGenerator(g IDGenerator) TracerProviderOption {
 | 
						|
	return traceProviderOptionFunc(func(cfg *tracerProviderConfig) {
 | 
						|
		if g != nil {
 | 
						|
			cfg.idGenerator = g
 | 
						|
		}
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// WithSampler returns a TracerProviderOption that will configure the Sampler
 | 
						|
// s as a TracerProvider's Sampler. The configured Sampler is used by the
 | 
						|
// Tracers the TracerProvider creates to make their sampling decisions for the
 | 
						|
// Spans they create.
 | 
						|
//
 | 
						|
// If this option is not used, the TracerProvider will use a
 | 
						|
// ParentBased(AlwaysSample) Sampler by default.
 | 
						|
func WithSampler(s Sampler) TracerProviderOption {
 | 
						|
	return traceProviderOptionFunc(func(cfg *tracerProviderConfig) {
 | 
						|
		if s != nil {
 | 
						|
			cfg.sampler = s
 | 
						|
		}
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// WithSpanLimits returns a TracerProviderOption that will configure the
 | 
						|
// SpanLimits sl as a TracerProvider's SpanLimits. The configured SpanLimits
 | 
						|
// are used used by the Tracers the TracerProvider and the Spans they create
 | 
						|
// to limit tracing resources used.
 | 
						|
//
 | 
						|
// If this option is not used, the TracerProvider will use the default
 | 
						|
// SpanLimits.
 | 
						|
func WithSpanLimits(sl SpanLimits) TracerProviderOption {
 | 
						|
	return traceProviderOptionFunc(func(cfg *tracerProviderConfig) {
 | 
						|
		cfg.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()
 | 
						|
	}
 | 
						|
}
 |