provider.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  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.Value
  68. isShutdown 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 := spanProcessorStates{}
  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. c := trace.NewTracerConfig(opts...)
  120. p.mu.Lock()
  121. defer p.mu.Unlock()
  122. if name == "" {
  123. name = defaultTracerName
  124. }
  125. is := instrumentation.Scope{
  126. Name: name,
  127. Version: c.InstrumentationVersion(),
  128. SchemaURL: c.SchemaURL(),
  129. }
  130. t, ok := p.namedTracer[is]
  131. if !ok {
  132. t = &tracer{
  133. provider: p,
  134. instrumentationScope: is,
  135. }
  136. p.namedTracer[is] = t
  137. global.Info("Tracer created", "name", name, "version", c.InstrumentationVersion(), "schemaURL", c.SchemaURL())
  138. }
  139. return t
  140. }
  141. // RegisterSpanProcessor adds the given SpanProcessor to the list of SpanProcessors.
  142. func (p *TracerProvider) RegisterSpanProcessor(sp SpanProcessor) {
  143. p.mu.Lock()
  144. defer p.mu.Unlock()
  145. if p.isShutdown {
  146. return
  147. }
  148. newSPS := spanProcessorStates{}
  149. newSPS = append(newSPS, p.spanProcessors.Load().(spanProcessorStates)...)
  150. newSPS = append(newSPS, newSpanProcessorState(sp))
  151. p.spanProcessors.Store(newSPS)
  152. }
  153. // UnregisterSpanProcessor removes the given SpanProcessor from the list of SpanProcessors.
  154. func (p *TracerProvider) UnregisterSpanProcessor(sp SpanProcessor) {
  155. p.mu.Lock()
  156. defer p.mu.Unlock()
  157. if p.isShutdown {
  158. return
  159. }
  160. old := p.spanProcessors.Load().(spanProcessorStates)
  161. if len(old) == 0 {
  162. return
  163. }
  164. spss := spanProcessorStates{}
  165. spss = append(spss, old...)
  166. // stop the span processor if it is started and remove it from the list
  167. var stopOnce *spanProcessorState
  168. var idx int
  169. for i, sps := range spss {
  170. if sps.sp == sp {
  171. stopOnce = sps
  172. idx = i
  173. }
  174. }
  175. if stopOnce != nil {
  176. stopOnce.state.Do(func() {
  177. if err := sp.Shutdown(context.Background()); err != nil {
  178. otel.Handle(err)
  179. }
  180. })
  181. }
  182. if len(spss) > 1 {
  183. copy(spss[idx:], spss[idx+1:])
  184. }
  185. spss[len(spss)-1] = nil
  186. spss = spss[:len(spss)-1]
  187. p.spanProcessors.Store(spss)
  188. }
  189. // ForceFlush immediately exports all spans that have not yet been exported for
  190. // all the registered span processors.
  191. func (p *TracerProvider) ForceFlush(ctx context.Context) error {
  192. spss := p.spanProcessors.Load().(spanProcessorStates)
  193. if len(spss) == 0 {
  194. return nil
  195. }
  196. for _, sps := range spss {
  197. select {
  198. case <-ctx.Done():
  199. return ctx.Err()
  200. default:
  201. }
  202. if err := sps.sp.ForceFlush(ctx); err != nil {
  203. return err
  204. }
  205. }
  206. return nil
  207. }
  208. // Shutdown shuts down TracerProvider. All registered span processors are shut down
  209. // in the order they were registered and any held computational resources are released.
  210. func (p *TracerProvider) Shutdown(ctx context.Context) error {
  211. spss := p.spanProcessors.Load().(spanProcessorStates)
  212. if len(spss) == 0 {
  213. return nil
  214. }
  215. p.mu.Lock()
  216. defer p.mu.Unlock()
  217. p.isShutdown = true
  218. var retErr error
  219. for _, sps := range spss {
  220. select {
  221. case <-ctx.Done():
  222. return ctx.Err()
  223. default:
  224. }
  225. var err error
  226. sps.state.Do(func() {
  227. err = sps.sp.Shutdown(ctx)
  228. })
  229. if err != nil {
  230. if retErr == nil {
  231. retErr = err
  232. } else {
  233. // Poor man's list of errors
  234. retErr = fmt.Errorf("%v; %v", retErr, err)
  235. }
  236. }
  237. }
  238. p.spanProcessors.Store(spanProcessorStates{})
  239. return retErr
  240. }
  241. // TracerProviderOption configures a TracerProvider.
  242. type TracerProviderOption interface {
  243. apply(tracerProviderConfig) tracerProviderConfig
  244. }
  245. type traceProviderOptionFunc func(tracerProviderConfig) tracerProviderConfig
  246. func (fn traceProviderOptionFunc) apply(cfg tracerProviderConfig) tracerProviderConfig {
  247. return fn(cfg)
  248. }
  249. // WithSyncer registers the exporter with the TracerProvider using a
  250. // SimpleSpanProcessor.
  251. //
  252. // This is not recommended for production use. The synchronous nature of the
  253. // SimpleSpanProcessor that will wrap the exporter make it good for testing,
  254. // debugging, or showing examples of other feature, but it will be slow and
  255. // have a high computation resource usage overhead. The WithBatcher option is
  256. // recommended for production use instead.
  257. func WithSyncer(e SpanExporter) TracerProviderOption {
  258. return WithSpanProcessor(NewSimpleSpanProcessor(e))
  259. }
  260. // WithBatcher registers the exporter with the TracerProvider using a
  261. // BatchSpanProcessor configured with the passed opts.
  262. func WithBatcher(e SpanExporter, opts ...BatchSpanProcessorOption) TracerProviderOption {
  263. return WithSpanProcessor(NewBatchSpanProcessor(e, opts...))
  264. }
  265. // WithSpanProcessor registers the SpanProcessor with a TracerProvider.
  266. func WithSpanProcessor(sp SpanProcessor) TracerProviderOption {
  267. return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
  268. cfg.processors = append(cfg.processors, sp)
  269. return cfg
  270. })
  271. }
  272. // WithResource returns a TracerProviderOption that will configure the
  273. // Resource r as a TracerProvider's Resource. The configured Resource is
  274. // referenced by all the Tracers the TracerProvider creates. It represents the
  275. // entity producing telemetry.
  276. //
  277. // If this option is not used, the TracerProvider will use the
  278. // resource.Default() Resource by default.
  279. func WithResource(r *resource.Resource) TracerProviderOption {
  280. return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
  281. var err error
  282. cfg.resource, err = resource.Merge(resource.Environment(), r)
  283. if err != nil {
  284. otel.Handle(err)
  285. }
  286. return cfg
  287. })
  288. }
  289. // WithIDGenerator returns a TracerProviderOption that will configure the
  290. // IDGenerator g as a TracerProvider's IDGenerator. The configured IDGenerator
  291. // is used by the Tracers the TracerProvider creates to generate new Span and
  292. // Trace IDs.
  293. //
  294. // If this option is not used, the TracerProvider will use a random number
  295. // IDGenerator by default.
  296. func WithIDGenerator(g IDGenerator) TracerProviderOption {
  297. return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
  298. if g != nil {
  299. cfg.idGenerator = g
  300. }
  301. return cfg
  302. })
  303. }
  304. // WithSampler returns a TracerProviderOption that will configure the Sampler
  305. // s as a TracerProvider's Sampler. The configured Sampler is used by the
  306. // Tracers the TracerProvider creates to make their sampling decisions for the
  307. // Spans they create.
  308. //
  309. // This option overrides the Sampler configured through the OTEL_TRACES_SAMPLER
  310. // and OTEL_TRACES_SAMPLER_ARG environment variables. If this option is not used
  311. // and the sampler is not configured through environment variables or the environment
  312. // contains invalid/unsupported configuration, the TracerProvider will use a
  313. // ParentBased(AlwaysSample) Sampler by default.
  314. func WithSampler(s Sampler) TracerProviderOption {
  315. return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
  316. if s != nil {
  317. cfg.sampler = s
  318. }
  319. return cfg
  320. })
  321. }
  322. // WithSpanLimits returns a TracerProviderOption that configures a
  323. // TracerProvider to use the SpanLimits sl. These SpanLimits bound any Span
  324. // created by a Tracer from the TracerProvider.
  325. //
  326. // If any field of sl is zero or negative it will be replaced with the default
  327. // value for that field.
  328. //
  329. // If this or WithRawSpanLimits are not provided, the TracerProvider will use
  330. // the limits defined by environment variables, or the defaults if unset.
  331. // Refer to the NewSpanLimits documentation for information about this
  332. // relationship.
  333. //
  334. // Deprecated: Use WithRawSpanLimits instead which allows setting unlimited
  335. // and zero limits. This option will be kept until the next major version
  336. // incremented release.
  337. func WithSpanLimits(sl SpanLimits) TracerProviderOption {
  338. if sl.AttributeValueLengthLimit <= 0 {
  339. sl.AttributeValueLengthLimit = DefaultAttributeValueLengthLimit
  340. }
  341. if sl.AttributeCountLimit <= 0 {
  342. sl.AttributeCountLimit = DefaultAttributeCountLimit
  343. }
  344. if sl.EventCountLimit <= 0 {
  345. sl.EventCountLimit = DefaultEventCountLimit
  346. }
  347. if sl.AttributePerEventCountLimit <= 0 {
  348. sl.AttributePerEventCountLimit = DefaultAttributePerEventCountLimit
  349. }
  350. if sl.LinkCountLimit <= 0 {
  351. sl.LinkCountLimit = DefaultLinkCountLimit
  352. }
  353. if sl.AttributePerLinkCountLimit <= 0 {
  354. sl.AttributePerLinkCountLimit = DefaultAttributePerLinkCountLimit
  355. }
  356. return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
  357. cfg.spanLimits = sl
  358. return cfg
  359. })
  360. }
  361. // WithRawSpanLimits returns a TracerProviderOption that configures a
  362. // TracerProvider to use these limits. These limits bound any Span created by
  363. // a Tracer from the TracerProvider.
  364. //
  365. // The limits will be used as-is. Zero or negative values will not be changed
  366. // to the default value like WithSpanLimits does. Setting a limit to zero will
  367. // effectively disable the related resource it limits and setting to a
  368. // negative value will mean that resource is unlimited. Consequentially, this
  369. // means that the zero-value SpanLimits will disable all span resources.
  370. // Because of this, limits should be constructed using NewSpanLimits and
  371. // updated accordingly.
  372. //
  373. // If this or WithSpanLimits are not provided, the TracerProvider will use the
  374. // limits defined by environment variables, or the defaults if unset. Refer to
  375. // the NewSpanLimits documentation for information about this relationship.
  376. func WithRawSpanLimits(limits SpanLimits) TracerProviderOption {
  377. return traceProviderOptionFunc(func(cfg tracerProviderConfig) tracerProviderConfig {
  378. cfg.spanLimits = limits
  379. return cfg
  380. })
  381. }
  382. func applyTracerProviderEnvConfigs(cfg tracerProviderConfig) tracerProviderConfig {
  383. for _, opt := range tracerProviderOptionsFromEnv() {
  384. cfg = opt.apply(cfg)
  385. }
  386. return cfg
  387. }
  388. func tracerProviderOptionsFromEnv() []TracerProviderOption {
  389. var opts []TracerProviderOption
  390. sampler, err := samplerFromEnv()
  391. if err != nil {
  392. otel.Handle(err)
  393. }
  394. if sampler != nil {
  395. opts = append(opts, WithSampler(sampler))
  396. }
  397. return opts
  398. }
  399. // ensureValidTracerProviderConfig ensures that given TracerProviderConfig is valid.
  400. func ensureValidTracerProviderConfig(cfg tracerProviderConfig) tracerProviderConfig {
  401. if cfg.sampler == nil {
  402. cfg.sampler = ParentBased(AlwaysSample())
  403. }
  404. if cfg.idGenerator == nil {
  405. cfg.idGenerator = defaultIDGenerator()
  406. }
  407. if cfg.resource == nil {
  408. cfg.resource = resource.Default()
  409. }
  410. return cfg
  411. }