provider.go 15 KB

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