trace.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package global // import "go.opentelemetry.io/otel/internal/global"
  4. /*
  5. This file contains the forwarding implementation of the TracerProvider used as
  6. the default global instance. Prior to initialization of an SDK, Tracers
  7. returned by the global TracerProvider will provide no-op functionality. This
  8. means that all Span created prior to initialization are no-op Spans.
  9. Once an SDK has been initialized, all provided no-op Tracers are swapped for
  10. Tracers provided by the SDK defined TracerProvider. However, any Span started
  11. prior to this initialization does not change its behavior. Meaning, the Span
  12. remains a no-op Span.
  13. The implementation to track and swap Tracers locks all new Tracer creation
  14. until the swap is complete. This assumes that this operation is not
  15. performance-critical. If that assumption is incorrect, be sure to configure an
  16. SDK prior to any Tracer creation.
  17. */
  18. import (
  19. "context"
  20. "sync"
  21. "sync/atomic"
  22. "go.opentelemetry.io/auto/sdk"
  23. "go.opentelemetry.io/otel/attribute"
  24. "go.opentelemetry.io/otel/codes"
  25. "go.opentelemetry.io/otel/trace"
  26. "go.opentelemetry.io/otel/trace/embedded"
  27. )
  28. // tracerProvider is a placeholder for a configured SDK TracerProvider.
  29. //
  30. // All TracerProvider functionality is forwarded to a delegate once
  31. // configured.
  32. type tracerProvider struct {
  33. embedded.TracerProvider
  34. mtx sync.Mutex
  35. tracers map[il]*tracer
  36. delegate trace.TracerProvider
  37. }
  38. // Compile-time guarantee that tracerProvider implements the TracerProvider
  39. // interface.
  40. var _ trace.TracerProvider = &tracerProvider{}
  41. // setDelegate configures p to delegate all TracerProvider functionality to
  42. // provider.
  43. //
  44. // All Tracers provided prior to this function call are switched out to be
  45. // Tracers provided by provider.
  46. //
  47. // It is guaranteed by the caller that this happens only once.
  48. func (p *tracerProvider) setDelegate(provider trace.TracerProvider) {
  49. p.mtx.Lock()
  50. defer p.mtx.Unlock()
  51. p.delegate = provider
  52. if len(p.tracers) == 0 {
  53. return
  54. }
  55. for _, t := range p.tracers {
  56. t.setDelegate(provider)
  57. }
  58. p.tracers = nil
  59. }
  60. // Tracer implements TracerProvider.
  61. func (p *tracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer {
  62. p.mtx.Lock()
  63. defer p.mtx.Unlock()
  64. if p.delegate != nil {
  65. return p.delegate.Tracer(name, opts...)
  66. }
  67. // At this moment it is guaranteed that no sdk is installed, save the tracer in the tracers map.
  68. c := trace.NewTracerConfig(opts...)
  69. key := il{
  70. name: name,
  71. version: c.InstrumentationVersion(),
  72. schema: c.SchemaURL(),
  73. attrs: c.InstrumentationAttributes(),
  74. }
  75. if p.tracers == nil {
  76. p.tracers = make(map[il]*tracer)
  77. }
  78. if val, ok := p.tracers[key]; ok {
  79. return val
  80. }
  81. t := &tracer{name: name, opts: opts, provider: p}
  82. p.tracers[key] = t
  83. return t
  84. }
  85. type il struct {
  86. name string
  87. version string
  88. schema string
  89. attrs attribute.Set
  90. }
  91. // tracer is a placeholder for a trace.Tracer.
  92. //
  93. // All Tracer functionality is forwarded to a delegate once configured.
  94. // Otherwise, all functionality is forwarded to a NoopTracer.
  95. type tracer struct {
  96. embedded.Tracer
  97. name string
  98. opts []trace.TracerOption
  99. provider *tracerProvider
  100. delegate atomic.Value
  101. }
  102. // Compile-time guarantee that tracer implements the trace.Tracer interface.
  103. var _ trace.Tracer = &tracer{}
  104. // setDelegate configures t to delegate all Tracer functionality to Tracers
  105. // created by provider.
  106. //
  107. // All subsequent calls to the Tracer methods will be passed to the delegate.
  108. //
  109. // It is guaranteed by the caller that this happens only once.
  110. func (t *tracer) setDelegate(provider trace.TracerProvider) {
  111. t.delegate.Store(provider.Tracer(t.name, t.opts...))
  112. }
  113. // Start implements trace.Tracer by forwarding the call to t.delegate if
  114. // set, otherwise it forwards the call to a NoopTracer.
  115. func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
  116. delegate := t.delegate.Load()
  117. if delegate != nil {
  118. return delegate.(trace.Tracer).Start(ctx, name, opts...)
  119. }
  120. return t.newSpan(ctx, autoInstEnabled, name, opts)
  121. }
  122. // autoInstEnabled determines if the auto-instrumentation SDK span is returned
  123. // from the tracer when not backed by a delegate and auto-instrumentation has
  124. // attached to this process.
  125. //
  126. // The auto-instrumentation is expected to overwrite this value to true when it
  127. // attaches. By default, this will point to false and mean a tracer will return
  128. // a nonRecordingSpan by default.
  129. var autoInstEnabled = new(bool)
  130. // newSpan is called by tracer.Start so auto-instrumentation can attach an eBPF
  131. // uprobe to this code.
  132. //
  133. // "noinline" pragma prevents the method from ever being inlined.
  134. //
  135. //go:noinline
  136. func (t *tracer) newSpan(
  137. ctx context.Context,
  138. autoSpan *bool,
  139. name string,
  140. opts []trace.SpanStartOption,
  141. ) (context.Context, trace.Span) {
  142. // autoInstEnabled is passed to newSpan via the autoSpan parameter. This is
  143. // so the auto-instrumentation can define a uprobe for (*t).newSpan and be
  144. // provided with the address of the bool autoInstEnabled points to. It
  145. // needs to be a parameter so that pointer can be reliably determined, it
  146. // should not be read from the global.
  147. if *autoSpan {
  148. tracer := sdk.TracerProvider().Tracer(t.name, t.opts...)
  149. return tracer.Start(ctx, name, opts...)
  150. }
  151. s := nonRecordingSpan{sc: trace.SpanContextFromContext(ctx), tracer: t}
  152. ctx = trace.ContextWithSpan(ctx, s)
  153. return ctx, s
  154. }
  155. // nonRecordingSpan is a minimal implementation of a Span that wraps a
  156. // SpanContext. It performs no operations other than to return the wrapped
  157. // SpanContext.
  158. type nonRecordingSpan struct {
  159. embedded.Span
  160. sc trace.SpanContext
  161. tracer *tracer
  162. }
  163. var _ trace.Span = nonRecordingSpan{}
  164. // SpanContext returns the wrapped SpanContext.
  165. func (s nonRecordingSpan) SpanContext() trace.SpanContext { return s.sc }
  166. // IsRecording always returns false.
  167. func (nonRecordingSpan) IsRecording() bool { return false }
  168. // SetStatus does nothing.
  169. func (nonRecordingSpan) SetStatus(codes.Code, string) {}
  170. // SetError does nothing.
  171. func (nonRecordingSpan) SetError(bool) {}
  172. // SetAttributes does nothing.
  173. func (nonRecordingSpan) SetAttributes(...attribute.KeyValue) {}
  174. // End does nothing.
  175. func (nonRecordingSpan) End(...trace.SpanEndOption) {}
  176. // RecordError does nothing.
  177. func (nonRecordingSpan) RecordError(error, ...trace.EventOption) {}
  178. // AddEvent does nothing.
  179. func (nonRecordingSpan) AddEvent(string, ...trace.EventOption) {}
  180. // AddLink does nothing.
  181. func (nonRecordingSpan) AddLink(trace.Link) {}
  182. // SetName does nothing.
  183. func (nonRecordingSpan) SetName(string) {}
  184. func (s nonRecordingSpan) TracerProvider() trace.TracerProvider { return s.tracer.provider }