gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

provider.go (15834B)


      1 // Copyright The OpenTelemetry Authors
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package trace // import "go.opentelemetry.io/otel/sdk/trace"
     16 
     17 import (
     18 	"context"
     19 	"fmt"
     20 	"sync"
     21 	"sync/atomic"
     22 
     23 	"go.opentelemetry.io/otel"
     24 	"go.opentelemetry.io/otel/internal/global"
     25 	"go.opentelemetry.io/otel/sdk/instrumentation"
     26 	"go.opentelemetry.io/otel/sdk/resource"
     27 	"go.opentelemetry.io/otel/trace"
     28 )
     29 
     30 const (
     31 	defaultTracerName = "go.opentelemetry.io/otel/sdk/tracer"
     32 )
     33 
     34 // tracerProviderConfig.
     35 type tracerProviderConfig struct {
     36 	// processors contains collection of SpanProcessors that are processing pipeline
     37 	// for spans in the trace signal.
     38 	// SpanProcessors registered with a TracerProvider and are called at the start
     39 	// and end of a Span's lifecycle, and are called in the order they are
     40 	// registered.
     41 	processors []SpanProcessor
     42 
     43 	// sampler is the default sampler used when creating new spans.
     44 	sampler Sampler
     45 
     46 	// idGenerator is used to generate all Span and Trace IDs when needed.
     47 	idGenerator IDGenerator
     48 
     49 	// spanLimits defines the attribute, event, and link limits for spans.
     50 	spanLimits SpanLimits
     51 
     52 	// resource contains attributes representing an entity that produces telemetry.
     53 	resource *resource.Resource
     54 }
     55 
     56 // MarshalLog is the marshaling function used by the logging system to represent this exporter.
     57 func (cfg tracerProviderConfig) MarshalLog() interface{} {
     58 	return struct {
     59 		SpanProcessors  []SpanProcessor
     60 		SamplerType     string
     61 		IDGeneratorType string
     62 		SpanLimits      SpanLimits
     63 		Resource        *resource.Resource
     64 	}{
     65 		SpanProcessors:  cfg.processors,
     66 		SamplerType:     fmt.Sprintf("%T", cfg.sampler),
     67 		IDGeneratorType: fmt.Sprintf("%T", cfg.idGenerator),
     68 		SpanLimits:      cfg.spanLimits,
     69 		Resource:        cfg.resource,
     70 	}
     71 }
     72 
     73 // TracerProvider is an OpenTelemetry TracerProvider. It provides Tracers to
     74 // instrumentation so it can trace operational flow through a system.
     75 type TracerProvider struct {
     76 	mu             sync.Mutex
     77 	namedTracer    map[instrumentation.Scope]*tracer
     78 	spanProcessors atomic.Pointer[spanProcessorStates]
     79 
     80 	isShutdown atomic.Bool
     81 
     82 	// These fields are not protected by the lock mu. They are assumed to be
     83 	// immutable after creation of the TracerProvider.
     84 	sampler     Sampler
     85 	idGenerator IDGenerator
     86 	spanLimits  SpanLimits
     87 	resource    *resource.Resource
     88 }
     89 
     90 var _ trace.TracerProvider = &TracerProvider{}
     91 
     92 // NewTracerProvider returns a new and configured TracerProvider.
     93 //
     94 // By default the returned TracerProvider is configured with:
     95 //   - a ParentBased(AlwaysSample) Sampler
     96 //   - a random number IDGenerator
     97 //   - the resource.Default() Resource
     98 //   - the default SpanLimits.
     99 //
    100 // The passed opts are used to override these default values and configure the
    101 // returned TracerProvider appropriately.
    102 func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider {
    103 	o := tracerProviderConfig{
    104 		spanLimits: NewSpanLimits(),
    105 	}
    106 	o = applyTracerProviderEnvConfigs(o)
    107 
    108 	for _, opt := range opts {
    109 		o = opt.apply(o)
    110 	}
    111 
    112 	o = ensureValidTracerProviderConfig(o)
    113 
    114 	tp := &TracerProvider{
    115 		namedTracer: make(map[instrumentation.Scope]*tracer),
    116 		sampler:     o.sampler,
    117 		idGenerator: o.idGenerator,
    118 		spanLimits:  o.spanLimits,
    119 		resource:    o.resource,
    120 	}
    121 	global.Info("TracerProvider created", "config", o)
    122 
    123 	spss := make(spanProcessorStates, 0, len(o.processors))
    124 	for _, sp := range o.processors {
    125 		spss = append(spss, newSpanProcessorState(sp))
    126 	}
    127 	tp.spanProcessors.Store(&spss)
    128 
    129 	return tp
    130 }
    131 
    132 // Tracer returns a Tracer with the given name and options. If a Tracer for
    133 // the given name and options does not exist it is created, otherwise the
    134 // existing Tracer is returned.
    135 //
    136 // If name is empty, DefaultTracerName is used instead.
    137 //
    138 // This method is safe to be called concurrently.
    139 func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer {
    140 	// This check happens before the mutex is acquired to avoid deadlocking if Tracer() is called from within Shutdown().
    141 	if p.isShutdown.Load() {
    142 		return trace.NewNoopTracerProvider().Tracer(name, opts...)
    143 	}
    144 	c := trace.NewTracerConfig(opts...)
    145 	if name == "" {
    146 		name = defaultTracerName
    147 	}
    148 	is := instrumentation.Scope{
    149 		Name:      name,
    150 		Version:   c.InstrumentationVersion(),
    151 		SchemaURL: c.SchemaURL(),
    152 	}
    153 
    154 	t, ok := func() (trace.Tracer, bool) {
    155 		p.mu.Lock()
    156 		defer p.mu.Unlock()
    157 		// Must check the flag after acquiring the mutex to avoid returning a valid tracer if Shutdown() ran
    158 		// after the first check above but before we acquired the mutex.
    159 		if p.isShutdown.Load() {
    160 			return trace.NewNoopTracerProvider().Tracer(name, opts...), true
    161 		}
    162 		t, ok := p.namedTracer[is]
    163 		if !ok {
    164 			t = &tracer{
    165 				provider:             p,
    166 				instrumentationScope: is,
    167 			}
    168 			p.namedTracer[is] = t
    169 		}
    170 		return t, ok
    171 	}()
    172 	if !ok {
    173 		// This code is outside the mutex to not hold the lock while calling third party logging code:
    174 		// - That code may do slow things like I/O, which would prolong the duration the lock is held,
    175 		//   slowing down all tracing consumers.
    176 		// - Logging code may be instrumented with tracing and deadlock because it could try
    177 		//   acquiring the same non-reentrant mutex.
    178 		global.Info("Tracer created", "name", name, "version", is.Version, "schemaURL", is.SchemaURL)
    179 	}
    180 	return t
    181 }
    182 
    183 // RegisterSpanProcessor adds the given SpanProcessor to the list of SpanProcessors.
    184 func (p *TracerProvider) RegisterSpanProcessor(sp SpanProcessor) {
    185 	// This check prevents calls during a shutdown.
    186 	if p.isShutdown.Load() {
    187 		return
    188 	}
    189 	p.mu.Lock()
    190 	defer p.mu.Unlock()
    191 	// This check prevents calls after a shutdown.
    192 	if p.isShutdown.Load() {
    193 		return
    194 	}
    195 
    196 	current := p.getSpanProcessors()
    197 	newSPS := make(spanProcessorStates, 0, len(current)+1)
    198 	newSPS = append(newSPS, current...)
    199 	newSPS = append(newSPS, newSpanProcessorState(sp))
    200 	p.spanProcessors.Store(&newSPS)
    201 }
    202 
    203 // UnregisterSpanProcessor removes the given SpanProcessor from the list of SpanProcessors.
    204 func (p *TracerProvider) UnregisterSpanProcessor(sp SpanProcessor) {
    205 	// This check prevents calls during a shutdown.
    206 	if p.isShutdown.Load() {
    207 		return
    208 	}
    209 	p.mu.Lock()
    210 	defer p.mu.Unlock()
    211 	// This check prevents calls after a shutdown.
    212 	if p.isShutdown.Load() {
    213 		return
    214 	}
    215 	old := p.getSpanProcessors()
    216 	if len(old) == 0 {
    217 		return
    218 	}
    219 	spss := make(spanProcessorStates, len(old))
    220 	copy(spss, old)
    221 
    222 	// stop the span processor if it is started and remove it from the list
    223 	var stopOnce *spanProcessorState
    224 	var idx int
    225 	for i, sps := range spss {
    226 		if sps.sp == sp {
    227 			stopOnce = sps
    228 			idx = i
    229 		}
    230 	}
    231 	if stopOnce != nil {
    232 		stopOnce.state.Do(func() {
    233 			if err := sp.Shutdown(context.Background()); err != nil {
    234 				otel.Handle(err)
    235 			}
    236 		})
    237 	}
    238 	if len(spss) > 1 {
    239 		copy(spss[idx:], spss[idx+1:])
    240 	}
    241 	spss[len(spss)-1] = nil
    242 	spss = spss[:len(spss)-1]
    243 
    244 	p.spanProcessors.Store(&spss)
    245 }
    246 
    247 // ForceFlush immediately exports all spans that have not yet been exported for
    248 // all the registered span processors.
    249 func (p *TracerProvider) ForceFlush(ctx context.Context) error {
    250 	spss := p.getSpanProcessors()
    251 	if len(spss) == 0 {
    252 		return nil
    253 	}
    254 
    255 	for _, sps := range spss {
    256 		select {
    257 		case <-ctx.Done():
    258 			return ctx.Err()
    259 		default:
    260 		}
    261 
    262 		if err := sps.sp.ForceFlush(ctx); err != nil {
    263 			return err
    264 		}
    265 	}
    266 	return nil
    267 }
    268 
    269 // Shutdown shuts down TracerProvider. All registered span processors are shut down
    270 // in the order they were registered and any held computational resources are released.
    271 // After Shutdown is called, all methods are no-ops.
    272 func (p *TracerProvider) Shutdown(ctx context.Context) error {
    273 	// This check prevents deadlocks in case of recursive shutdown.
    274 	if p.isShutdown.Load() {
    275 		return nil
    276 	}
    277 	p.mu.Lock()
    278 	defer p.mu.Unlock()
    279 	// This check prevents calls after a shutdown has already been done concurrently.
    280 	if !p.isShutdown.CompareAndSwap(false, true) { // did toggle?
    281 		return nil
    282 	}
    283 
    284 	var retErr error
    285 	for _, sps := range p.getSpanProcessors() {
    286 		select {
    287 		case <-ctx.Done():
    288 			return ctx.Err()
    289 		default:
    290 		}
    291 
    292 		var err error
    293 		sps.state.Do(func() {
    294 			err = sps.sp.Shutdown(ctx)
    295 		})
    296 		if err != nil {
    297 			if retErr == nil {
    298 				retErr = err
    299 			} else {
    300 				// Poor man's list of errors
    301 				retErr = fmt.Errorf("%v; %v", retErr, err)
    302 			}
    303 		}
    304 	}
    305 	p.spanProcessors.Store(&spanProcessorStates{})
    306 	return retErr
    307 }
    308 
    309 func (p *TracerProvider) getSpanProcessors() spanProcessorStates {
    310 	return *(p.spanProcessors.Load())
    311 }
    312 
    313 // TracerProviderOption configures a TracerProvider.
    314 type TracerProviderOption interface {
    315 	apply(tracerProviderConfig) tracerProviderConfig
    316 }
    317 
    318 type traceProviderOptionFunc func(tracerProviderConfig) tracerProviderConfig
    319 
    320 func (fn traceProviderOptionFunc) apply(cfg tracerProviderConfig) tracerProviderConfig {
    321 	return fn(cfg)
    322 }
    323 
    324 // WithSyncer registers the exporter with the TracerProvider using a
    325 // SimpleSpanProcessor.
    326 //
    327 // This is not recommended for production use. The synchronous nature of the
    328 // SimpleSpanProcessor that will wrap the exporter make it good for testing,
    329 // debugging, or showing examples of other feature, but it will be slow and
    330 // have a high computation resource usage overhead. The WithBatcher option is
    331 // recommended for production use instead.
    332 func WithSyncer(e SpanExporter) TracerProviderOption {
    333 	return WithSpanProcessor(NewSimpleSpanProcessor(e))
    334 }
    335 
    336 // WithBatcher registers the exporter with the TracerProvider using a
    337 // BatchSpanProcessor configured with the passed opts.
    338 func WithBatcher(e SpanExporter, opts ...BatchSpanProcessorOption) TracerProviderOption {
    339 	return WithSpanProcessor(NewBatchSpanProcessor(e, opts...))
    340 }
    341 
    342 // WithSpanProcessor registers the SpanProcessor with a TracerProvider.
    343 func WithSpanProcessor(sp SpanProcessor) TracerProviderOption {
    344 	return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
    345 		cfg.processors = append(cfg.processors, sp)
    346 		return cfg
    347 	})
    348 }
    349 
    350 // WithResource returns a TracerProviderOption that will configure the
    351 // Resource r as a TracerProvider's Resource. The configured Resource is
    352 // referenced by all the Tracers the TracerProvider creates. It represents the
    353 // entity producing telemetry.
    354 //
    355 // If this option is not used, the TracerProvider will use the
    356 // resource.Default() Resource by default.
    357 func WithResource(r *resource.Resource) TracerProviderOption {
    358 	return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
    359 		var err error
    360 		cfg.resource, err = resource.Merge(resource.Environment(), r)
    361 		if err != nil {
    362 			otel.Handle(err)
    363 		}
    364 		return cfg
    365 	})
    366 }
    367 
    368 // WithIDGenerator returns a TracerProviderOption that will configure the
    369 // IDGenerator g as a TracerProvider's IDGenerator. The configured IDGenerator
    370 // is used by the Tracers the TracerProvider creates to generate new Span and
    371 // Trace IDs.
    372 //
    373 // If this option is not used, the TracerProvider will use a random number
    374 // IDGenerator by default.
    375 func WithIDGenerator(g IDGenerator) TracerProviderOption {
    376 	return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
    377 		if g != nil {
    378 			cfg.idGenerator = g
    379 		}
    380 		return cfg
    381 	})
    382 }
    383 
    384 // WithSampler returns a TracerProviderOption that will configure the Sampler
    385 // s as a TracerProvider's Sampler. The configured Sampler is used by the
    386 // Tracers the TracerProvider creates to make their sampling decisions for the
    387 // Spans they create.
    388 //
    389 // This option overrides the Sampler configured through the OTEL_TRACES_SAMPLER
    390 // and OTEL_TRACES_SAMPLER_ARG environment variables. If this option is not used
    391 // and the sampler is not configured through environment variables or the environment
    392 // contains invalid/unsupported configuration, the TracerProvider will use a
    393 // ParentBased(AlwaysSample) Sampler by default.
    394 func WithSampler(s Sampler) TracerProviderOption {
    395 	return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
    396 		if s != nil {
    397 			cfg.sampler = s
    398 		}
    399 		return cfg
    400 	})
    401 }
    402 
    403 // WithSpanLimits returns a TracerProviderOption that configures a
    404 // TracerProvider to use the SpanLimits sl. These SpanLimits bound any Span
    405 // created by a Tracer from the TracerProvider.
    406 //
    407 // If any field of sl is zero or negative it will be replaced with the default
    408 // value for that field.
    409 //
    410 // If this or WithRawSpanLimits are not provided, the TracerProvider will use
    411 // the limits defined by environment variables, or the defaults if unset.
    412 // Refer to the NewSpanLimits documentation for information about this
    413 // relationship.
    414 //
    415 // Deprecated: Use WithRawSpanLimits instead which allows setting unlimited
    416 // and zero limits. This option will be kept until the next major version
    417 // incremented release.
    418 func WithSpanLimits(sl SpanLimits) TracerProviderOption {
    419 	if sl.AttributeValueLengthLimit <= 0 {
    420 		sl.AttributeValueLengthLimit = DefaultAttributeValueLengthLimit
    421 	}
    422 	if sl.AttributeCountLimit <= 0 {
    423 		sl.AttributeCountLimit = DefaultAttributeCountLimit
    424 	}
    425 	if sl.EventCountLimit <= 0 {
    426 		sl.EventCountLimit = DefaultEventCountLimit
    427 	}
    428 	if sl.AttributePerEventCountLimit <= 0 {
    429 		sl.AttributePerEventCountLimit = DefaultAttributePerEventCountLimit
    430 	}
    431 	if sl.LinkCountLimit <= 0 {
    432 		sl.LinkCountLimit = DefaultLinkCountLimit
    433 	}
    434 	if sl.AttributePerLinkCountLimit <= 0 {
    435 		sl.AttributePerLinkCountLimit = DefaultAttributePerLinkCountLimit
    436 	}
    437 	return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
    438 		cfg.spanLimits = sl
    439 		return cfg
    440 	})
    441 }
    442 
    443 // WithRawSpanLimits returns a TracerProviderOption that configures a
    444 // TracerProvider to use these limits. These limits bound any Span created by
    445 // a Tracer from the TracerProvider.
    446 //
    447 // The limits will be used as-is. Zero or negative values will not be changed
    448 // to the default value like WithSpanLimits does. Setting a limit to zero will
    449 // effectively disable the related resource it limits and setting to a
    450 // negative value will mean that resource is unlimited. Consequentially, this
    451 // means that the zero-value SpanLimits will disable all span resources.
    452 // Because of this, limits should be constructed using NewSpanLimits and
    453 // updated accordingly.
    454 //
    455 // If this or WithSpanLimits are not provided, the TracerProvider will use the
    456 // limits defined by environment variables, or the defaults if unset. Refer to
    457 // the NewSpanLimits documentation for information about this relationship.
    458 func WithRawSpanLimits(limits SpanLimits) TracerProviderOption {
    459 	return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
    460 		cfg.spanLimits = limits
    461 		return cfg
    462 	})
    463 }
    464 
    465 func applyTracerProviderEnvConfigs(cfg tracerProviderConfig) tracerProviderConfig {
    466 	for _, opt := range tracerProviderOptionsFromEnv() {
    467 		cfg = opt.apply(cfg)
    468 	}
    469 
    470 	return cfg
    471 }
    472 
    473 func tracerProviderOptionsFromEnv() []TracerProviderOption {
    474 	var opts []TracerProviderOption
    475 
    476 	sampler, err := samplerFromEnv()
    477 	if err != nil {
    478 		otel.Handle(err)
    479 	}
    480 
    481 	if sampler != nil {
    482 		opts = append(opts, WithSampler(sampler))
    483 	}
    484 
    485 	return opts
    486 }
    487 
    488 // ensureValidTracerProviderConfig ensures that given TracerProviderConfig is valid.
    489 func ensureValidTracerProviderConfig(cfg tracerProviderConfig) tracerProviderConfig {
    490 	if cfg.sampler == nil {
    491 		cfg.sampler = ParentBased(AlwaysSample())
    492 	}
    493 	if cfg.idGenerator == nil {
    494 		cfg.idGenerator = defaultIDGenerator()
    495 	}
    496 	if cfg.resource == nil {
    497 		cfg.resource = resource.Default()
    498 	}
    499 	return cfg
    500 }