provider.go 13 KB

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