github.com/xmidt-org/webpa-common@v1.11.9/tracing/spanner.go (about)

     1  package tracing
     2  
     3  import (
     4  	"time"
     5  )
     6  
     7  // Spanner acts as a factory for Spans
     8  type Spanner interface {
     9  	// Start begins a new, unfinished span.  The returned closure must be called
    10  	// to finished the span, recording it with a duration and the given error.  The
    11  	// returned closure is idempotent and only records the duration and error of the first call.
    12  	// It always returns the same Span instance, and that instance is immutable once the
    13  	// closure is called.
    14  	Start(string) func(error) Span
    15  }
    16  
    17  // SpannerOption supplies a configuration option to a Spanner.
    18  type SpannerOption func(*spanner)
    19  
    20  // Now sets a now function on a spanner.  If now is nil, this option does nothing.
    21  // This options is primarily useful for testing, however it can be useful in production
    22  // situations.  For example, this option can be used to emit times with a consistent time zone, like UTC.
    23  func Now(now func() time.Time) SpannerOption {
    24  	return func(sp *spanner) {
    25  		if now != nil {
    26  			sp.now = now
    27  		}
    28  	}
    29  }
    30  
    31  // Since sets a since function on a spanner.  If since is nil, this option does nothing.
    32  // This options is primarily useful for testing.
    33  func Since(since func(time.Time) time.Duration) SpannerOption {
    34  	return func(sp *spanner) {
    35  		if since != nil {
    36  			sp.since = since
    37  		}
    38  	}
    39  }
    40  
    41  // NewSpanner constructs a new Spanner with the given options.  By default, a Spanner
    42  // will use time.Now() to get the current time and time.Since() to compute durations.
    43  func NewSpanner(o ...SpannerOption) Spanner {
    44  	sp := &spanner{
    45  		now:   time.Now,
    46  		since: time.Since,
    47  	}
    48  
    49  	for _, option := range o {
    50  		option(sp)
    51  	}
    52  
    53  	return sp
    54  }
    55  
    56  // spanner is the internal spanner implementation.
    57  type spanner struct {
    58  	now   func() time.Time
    59  	since func(time.Time) time.Duration
    60  }
    61  
    62  func (sp *spanner) Start(name string) func(error) Span {
    63  	s := &span{
    64  		name:  name,
    65  		start: sp.now(),
    66  	}
    67  
    68  	return func(err error) Span {
    69  		s.finish(sp.since(s.start), err)
    70  		return s
    71  	}
    72  }