diff --git a/span.go b/span.go index 25da1e4ed1b1..08c53d046abd 100644 --- a/span.go +++ b/span.go @@ -136,12 +136,18 @@ func (s *spanImpl) FinishWithOptions(opts opentracing.FinishOptions) { s.onFinish(s.raw) s.tracer.options.Recorder.RecordSpan(s.raw) + + // Last chance to get options before the span is possbily reset. + poolEnabled := s.tracer.options.EnableSpanPool if s.tracer.options.DebugAssertUseAfterFinish { // This makes it much more likely to catch a panic on any subsequent // operation since s.tracer is accessed on every call to `Lock`. s.reset() } - spanPool.Put(s) + + if poolEnabled { + spanPool.Put(s) + } } func (s *spanImpl) SetBaggageItem(restrictedKey, val string) opentracing.Span { diff --git a/tracer.go b/tracer.go index 28c26be6f9ea..3cf5fe5d5ce9 100644 --- a/tracer.go +++ b/tracer.go @@ -73,6 +73,11 @@ type Options struct { // When set, it attempts to exacerbate issues emanating from use of Spans // after calling Finish by running additional assertions. DebugAssertUseAfterFinish bool + // EnableSpanPool enables the use of a pool, so that the tracer reuses spans + // after Finish has been called on it. Adds a slight performance gain as it + // reduces allocations. However, if you have any use-after-finish race + // conditions the code may panic. + EnableSpanPool bool } // DefaultOptions returns an Options object with a 1 in 64 sampling rate and @@ -122,9 +127,12 @@ func (t *tracerImpl) StartSpan( } func (t *tracerImpl) getSpan() *spanImpl { - sp := spanPool.Get().(*spanImpl) - sp.reset() - return sp + if t.options.EnableSpanPool { + sp := spanPool.Get().(*spanImpl) + sp.reset() + return sp + } + return &spanImpl{} } func (t *tracerImpl) StartSpanWithOptions(