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 15package trace // import "go.opentelemetry.io/otel/sdk/trace" 16 17import ( 18 "context" 19 "sync" 20 "sync/atomic" 21 22 "go.opentelemetry.io/otel" 23 "go.opentelemetry.io/otel/trace" 24 25 export "go.opentelemetry.io/otel/sdk/export/trace" 26 "go.opentelemetry.io/otel/sdk/instrumentation" 27 "go.opentelemetry.io/otel/sdk/resource" 28) 29 30const ( 31 defaultTracerName = "go.opentelemetry.io/otel/sdk/tracer" 32) 33 34// TODO (MrAlias): unify this API option design: 35// https://github.com/open-telemetry/opentelemetry-go/issues/536 36 37// TracerProviderConfig 38type TracerProviderConfig struct { 39 processors []SpanProcessor 40 config Config 41} 42 43type TracerProviderOption func(*TracerProviderConfig) 44 45type TracerProvider struct { 46 mu sync.Mutex 47 namedTracer map[instrumentation.Library]*tracer 48 spanProcessors atomic.Value 49 config atomic.Value // access atomically 50} 51 52var _ trace.TracerProvider = &TracerProvider{} 53 54// NewTracerProvider creates an instance of trace provider. Optional 55// parameter configures the provider with common options applicable 56// to all tracer instances that will be created by this provider. 57func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider { 58 o := &TracerProviderConfig{} 59 60 for _, opt := range opts { 61 opt(o) 62 } 63 64 tp := &TracerProvider{ 65 namedTracer: make(map[instrumentation.Library]*tracer), 66 } 67 tp.config.Store(&Config{ 68 DefaultSampler: ParentBased(AlwaysSample()), 69 IDGenerator: defaultIDGenerator(), 70 SpanLimits: SpanLimits{ 71 AttributeCountLimit: DefaultAttributeCountLimit, 72 EventCountLimit: DefaultEventCountLimit, 73 LinkCountLimit: DefaultLinkCountLimit, 74 AttributePerEventCountLimit: DefaultAttributePerEventCountLimit, 75 AttributePerLinkCountLimit: DefaultAttributePerLinkCountLimit, 76 }, 77 }) 78 79 for _, sp := range o.processors { 80 tp.RegisterSpanProcessor(sp) 81 } 82 83 tp.ApplyConfig(o.config) 84 85 return tp 86} 87 88// Tracer with the given name. If a tracer for the given name does not exist, 89// it is created first. If the name is empty, DefaultTracerName is used. 90func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { 91 c := trace.NewTracerConfig(opts...) 92 93 p.mu.Lock() 94 defer p.mu.Unlock() 95 if name == "" { 96 name = defaultTracerName 97 } 98 il := instrumentation.Library{ 99 Name: name, 100 Version: c.InstrumentationVersion, 101 } 102 t, ok := p.namedTracer[il] 103 if !ok { 104 t = &tracer{ 105 provider: p, 106 instrumentationLibrary: il, 107 } 108 p.namedTracer[il] = t 109 } 110 return t 111} 112 113// RegisterSpanProcessor adds the given SpanProcessor to the list of SpanProcessors 114func (p *TracerProvider) RegisterSpanProcessor(s SpanProcessor) { 115 p.mu.Lock() 116 defer p.mu.Unlock() 117 new := spanProcessorStates{} 118 if old, ok := p.spanProcessors.Load().(spanProcessorStates); ok { 119 new = append(new, old...) 120 } 121 newSpanSync := &spanProcessorState{ 122 sp: s, 123 state: &sync.Once{}, 124 } 125 new = append(new, newSpanSync) 126 p.spanProcessors.Store(new) 127} 128 129// UnregisterSpanProcessor removes the given SpanProcessor from the list of SpanProcessors 130func (p *TracerProvider) UnregisterSpanProcessor(s SpanProcessor) { 131 p.mu.Lock() 132 defer p.mu.Unlock() 133 spss := spanProcessorStates{} 134 old, ok := p.spanProcessors.Load().(spanProcessorStates) 135 if !ok || len(old) == 0 { 136 return 137 } 138 spss = append(spss, old...) 139 140 // stop the span processor if it is started and remove it from the list 141 var stopOnce *spanProcessorState 142 var idx int 143 for i, sps := range spss { 144 if sps.sp == s { 145 stopOnce = sps 146 idx = i 147 } 148 } 149 if stopOnce != nil { 150 stopOnce.state.Do(func() { 151 if err := s.Shutdown(context.Background()); err != nil { 152 otel.Handle(err) 153 } 154 }) 155 } 156 if len(spss) > 1 { 157 copy(spss[idx:], spss[idx+1:]) 158 } 159 spss[len(spss)-1] = nil 160 spss = spss[:len(spss)-1] 161 162 p.spanProcessors.Store(spss) 163} 164 165// ApplyConfig changes the configuration of the provider. 166// If a field in the configuration is empty or nil then its original value is preserved. 167func (p *TracerProvider) ApplyConfig(cfg Config) { 168 p.mu.Lock() 169 defer p.mu.Unlock() 170 c := *p.config.Load().(*Config) 171 if cfg.DefaultSampler != nil { 172 c.DefaultSampler = cfg.DefaultSampler 173 } 174 if cfg.IDGenerator != nil { 175 c.IDGenerator = cfg.IDGenerator 176 } 177 if cfg.SpanLimits.EventCountLimit > 0 { 178 c.SpanLimits.EventCountLimit = cfg.SpanLimits.EventCountLimit 179 } 180 if cfg.SpanLimits.AttributeCountLimit > 0 { 181 c.SpanLimits.AttributeCountLimit = cfg.SpanLimits.AttributeCountLimit 182 } 183 if cfg.SpanLimits.LinkCountLimit > 0 { 184 c.SpanLimits.LinkCountLimit = cfg.SpanLimits.LinkCountLimit 185 } 186 if cfg.SpanLimits.AttributePerEventCountLimit > 0 { 187 c.SpanLimits.AttributePerEventCountLimit = cfg.SpanLimits.AttributePerEventCountLimit 188 } 189 if cfg.SpanLimits.AttributePerLinkCountLimit > 0 { 190 c.SpanLimits.AttributePerLinkCountLimit = cfg.SpanLimits.AttributePerLinkCountLimit 191 } 192 c.Resource = cfg.Resource 193 if c.Resource == nil { 194 c.Resource = resource.Default() 195 } 196 p.config.Store(&c) 197} 198 199// Shutdown shuts down the span processors in the order they were registered 200func (p *TracerProvider) Shutdown(ctx context.Context) error { 201 spss, ok := p.spanProcessors.Load().(spanProcessorStates) 202 if !ok || len(spss) == 0 { 203 return nil 204 } 205 206 for _, sps := range spss { 207 sps.state.Do(func() { 208 if err := sps.sp.Shutdown(ctx); err != nil { 209 otel.Handle(err) 210 } 211 }) 212 } 213 return nil 214} 215 216// WithSyncer registers the exporter with the TracerProvider using a 217// SimpleSpanProcessor. 218func WithSyncer(e export.SpanExporter) TracerProviderOption { 219 return WithSpanProcessor(NewSimpleSpanProcessor(e)) 220} 221 222// WithBatcher registers the exporter with the TracerProvider using a 223// BatchSpanProcessor configured with the passed opts. 224func WithBatcher(e export.SpanExporter, opts ...BatchSpanProcessorOption) TracerProviderOption { 225 return WithSpanProcessor(NewBatchSpanProcessor(e, opts...)) 226} 227 228// WithSpanProcessor registers the SpanProcessor with a TracerProvider. 229func WithSpanProcessor(sp SpanProcessor) TracerProviderOption { 230 return func(opts *TracerProviderConfig) { 231 opts.processors = append(opts.processors, sp) 232 } 233} 234 235// WithConfig option sets the configuration to provider. 236func WithConfig(config Config) TracerProviderOption { 237 return func(opts *TracerProviderConfig) { 238 opts.config = config 239 } 240} 241 242// WithResource option attaches a resource to the provider. 243// The resource is added to the span when it is started. 244func WithResource(r *resource.Resource) TracerProviderOption { 245 return func(opts *TracerProviderConfig) { 246 opts.config.Resource = r 247 } 248} 249 250// WithIDGenerator option registers an IDGenerator with the TracerProvider. 251func WithIDGenerator(g IDGenerator) TracerProviderOption { 252 return func(opts *TracerProviderConfig) { 253 opts.config.IDGenerator = g 254 } 255} 256