tracer.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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. "time"
  18. "go.opentelemetry.io/otel/sdk/instrumentation"
  19. "go.opentelemetry.io/otel/trace"
  20. )
  21. type tracer struct {
  22. provider *TracerProvider
  23. instrumentationScope instrumentation.Scope
  24. }
  25. var _ trace.Tracer = &tracer{}
  26. // Start starts a Span and returns it along with a context containing it.
  27. //
  28. // The Span is created with the provided name and as a child of any existing
  29. // span context found in the passed context. The created Span will be
  30. // configured appropriately by any SpanOption passed.
  31. func (tr *tracer) Start(ctx context.Context, name string, options ...trace.SpanStartOption) (context.Context, trace.Span) {
  32. config := trace.NewSpanStartConfig(options...)
  33. if ctx == nil {
  34. // Prevent trace.ContextWithSpan from panicking.
  35. ctx = context.Background()
  36. }
  37. // For local spans created by this SDK, track child span count.
  38. if p := trace.SpanFromContext(ctx); p != nil {
  39. if sdkSpan, ok := p.(*recordingSpan); ok {
  40. sdkSpan.addChild()
  41. }
  42. }
  43. s := tr.newSpan(ctx, name, &config)
  44. if rw, ok := s.(ReadWriteSpan); ok && s.IsRecording() {
  45. sps := tr.provider.getSpanProcessors()
  46. for _, sp := range sps {
  47. sp.sp.OnStart(ctx, rw)
  48. }
  49. }
  50. if rtt, ok := s.(runtimeTracer); ok {
  51. ctx = rtt.runtimeTrace(ctx)
  52. }
  53. return trace.ContextWithSpan(ctx, s), s
  54. }
  55. type runtimeTracer interface {
  56. // runtimeTrace starts a "runtime/trace".Task for the span and
  57. // returns a context containing the task.
  58. runtimeTrace(ctx context.Context) context.Context
  59. }
  60. // newSpan returns a new configured span.
  61. func (tr *tracer) newSpan(ctx context.Context, name string, config *trace.SpanConfig) trace.Span {
  62. // If told explicitly to make this a new root use a zero value SpanContext
  63. // as a parent which contains an invalid trace ID and is not remote.
  64. var psc trace.SpanContext
  65. if config.NewRoot() {
  66. ctx = trace.ContextWithSpanContext(ctx, psc)
  67. } else {
  68. psc = trace.SpanContextFromContext(ctx)
  69. }
  70. // If there is a valid parent trace ID, use it to ensure the continuity of
  71. // the trace. Always generate a new span ID so other components can rely
  72. // on a unique span ID, even if the Span is non-recording.
  73. var tid trace.TraceID
  74. var sid trace.SpanID
  75. if !psc.TraceID().IsValid() {
  76. tid, sid = tr.provider.idGenerator.NewIDs(ctx)
  77. } else {
  78. tid = psc.TraceID()
  79. sid = tr.provider.idGenerator.NewSpanID(ctx, tid)
  80. }
  81. samplingResult := tr.provider.sampler.ShouldSample(SamplingParameters{
  82. ParentContext: ctx,
  83. TraceID: tid,
  84. Name: name,
  85. Kind: config.SpanKind(),
  86. Attributes: config.Attributes(),
  87. Links: config.Links(),
  88. })
  89. scc := trace.SpanContextConfig{
  90. TraceID: tid,
  91. SpanID: sid,
  92. TraceState: samplingResult.Tracestate,
  93. }
  94. if isSampled(samplingResult) {
  95. scc.TraceFlags = psc.TraceFlags() | trace.FlagsSampled
  96. } else {
  97. scc.TraceFlags = psc.TraceFlags() &^ trace.FlagsSampled
  98. }
  99. sc := trace.NewSpanContext(scc)
  100. if !isRecording(samplingResult) {
  101. return tr.newNonRecordingSpan(sc)
  102. }
  103. return tr.newRecordingSpan(psc, sc, name, samplingResult, config)
  104. }
  105. // newRecordingSpan returns a new configured recordingSpan.
  106. func (tr *tracer) newRecordingSpan(psc, sc trace.SpanContext, name string, sr SamplingResult, config *trace.SpanConfig) *recordingSpan {
  107. startTime := config.Timestamp()
  108. if startTime.IsZero() {
  109. startTime = time.Now()
  110. }
  111. s := &recordingSpan{
  112. // Do not pre-allocate the attributes slice here! Doing so will
  113. // allocate memory that is likely never going to be used, or if used,
  114. // will be over-sized. The default Go compiler has been tested to
  115. // dynamically allocate needed space very well. Benchmarking has shown
  116. // it to be more performant than what we can predetermine here,
  117. // especially for the common use case of few to no added
  118. // attributes.
  119. parent: psc,
  120. spanContext: sc,
  121. spanKind: trace.ValidateSpanKind(config.SpanKind()),
  122. name: name,
  123. startTime: startTime,
  124. events: newEvictedQueue(tr.provider.spanLimits.EventCountLimit),
  125. links: newEvictedQueue(tr.provider.spanLimits.LinkCountLimit),
  126. tracer: tr,
  127. }
  128. for _, l := range config.Links() {
  129. s.addLink(l)
  130. }
  131. s.SetAttributes(sr.Attributes...)
  132. s.SetAttributes(config.Attributes()...)
  133. return s
  134. }
  135. // newNonRecordingSpan returns a new configured nonRecordingSpan.
  136. func (tr *tracer) newNonRecordingSpan(sc trace.SpanContext) nonRecordingSpan {
  137. return nonRecordingSpan{tracer: tr, sc: sc}
  138. }