ipld-eth-server/vendor/gopkg.in/DataDog/dd-trace-go.v1/ddtrace/mocktracer/mockspan.go
2018-09-11 16:30:29 -05:00

215 lines
5.0 KiB
Go

package mocktracer // import "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/mocktracer"
import (
"fmt"
"sync"
"time"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
)
var _ ddtrace.Span = (*mockspan)(nil)
var _ Span = (*mockspan)(nil)
// Span is an interface that allows querying a span returned by the mock tracer.
type Span interface {
// SpanID returns the span's ID.
SpanID() uint64
// TraceID returns the span's trace ID.
TraceID() uint64
// ParentID returns the span's parent ID.
ParentID() uint64
// StartTime returns the time when the span has started.
StartTime() time.Time
// FinishTime returns the time when the span has finished.
FinishTime() time.Time
// OperationName returns the operation name held by this span.
OperationName() string
// Tag returns the value of the tag at key k.
Tag(k string) interface{}
// Tags returns a copy of all the tags in this span.
Tags() map[string]interface{}
// Context returns the span's SpanContext.
Context() ddtrace.SpanContext
// Stringer allows pretty-printing the span's fields for debugging.
fmt.Stringer
}
func newSpan(t *mocktracer, operationName string, cfg *ddtrace.StartSpanConfig) *mockspan {
if cfg.Tags == nil {
cfg.Tags = make(map[string]interface{})
}
if cfg.Tags[ext.ResourceName] == nil {
cfg.Tags[ext.ResourceName] = operationName
}
s := &mockspan{
name: operationName,
tracer: t,
}
if cfg.StartTime.IsZero() {
s.startTime = time.Now()
} else {
s.startTime = cfg.StartTime
}
id := nextID()
s.context = &spanContext{spanID: id, traceID: id, span: s}
if ctx, ok := cfg.Parent.(*spanContext); ok {
if ctx.span != nil && s.tags[ext.ServiceName] == nil {
// if we have a local parent and no service, inherit the parent's
s.SetTag(ext.ServiceName, ctx.span.Tag(ext.ServiceName))
}
if ctx.hasSamplingPriority() {
s.SetTag(ext.SamplingPriority, ctx.samplingPriority())
}
s.parentID = ctx.spanID
s.context.priority = ctx.samplingPriority()
s.context.hasPriority = ctx.hasSamplingPriority()
s.context.traceID = ctx.traceID
s.context.baggage = make(map[string]string, len(ctx.baggage))
ctx.ForeachBaggageItem(func(k, v string) bool {
s.context.baggage[k] = v
return true
})
}
for k, v := range cfg.Tags {
s.SetTag(k, v)
}
return s
}
type mockspan struct {
sync.RWMutex // guards below fields
name string
tags map[string]interface{}
finishTime time.Time
startTime time.Time
parentID uint64
context *spanContext
tracer *mocktracer
}
// SetTag sets a given tag on the span.
func (s *mockspan) SetTag(key string, value interface{}) {
s.Lock()
defer s.Unlock()
if s.tags == nil {
s.tags = make(map[string]interface{}, 1)
}
if key == ext.SamplingPriority {
switch p := value.(type) {
case int:
s.context.setSamplingPriority(p)
case float64:
s.context.setSamplingPriority(int(p))
}
}
s.tags[key] = value
}
func (s *mockspan) FinishTime() time.Time {
s.RLock()
defer s.RUnlock()
return s.finishTime
}
func (s *mockspan) StartTime() time.Time { return s.startTime }
func (s *mockspan) Tag(k string) interface{} {
s.RLock()
defer s.RUnlock()
return s.tags[k]
}
func (s *mockspan) Tags() map[string]interface{} {
s.RLock()
defer s.RUnlock()
// copy
cp := make(map[string]interface{}, len(s.tags))
for k, v := range s.tags {
cp[k] = v
}
return cp
}
func (s *mockspan) TraceID() uint64 { return s.context.traceID }
func (s *mockspan) SpanID() uint64 { return s.context.spanID }
func (s *mockspan) ParentID() uint64 { return s.parentID }
func (s *mockspan) OperationName() string {
s.RLock()
defer s.RUnlock()
return s.name
}
// SetOperationName resets the original operation name to the given one.
func (s *mockspan) SetOperationName(operationName string) {
s.Lock()
defer s.Unlock()
s.name = operationName
return
}
// BaggageItem returns the baggage item with the given key.
func (s *mockspan) BaggageItem(key string) string {
return s.context.baggageItem(key)
}
// SetBaggageItem sets a new baggage item at the given key. The baggage
// item should propagate to all descendant spans, both in- and cross-process.
func (s *mockspan) SetBaggageItem(key, val string) {
s.context.setBaggageItem(key, val)
return
}
// Finish finishes the current span with the given options.
func (s *mockspan) Finish(opts ...ddtrace.FinishOption) {
var cfg ddtrace.FinishConfig
for _, fn := range opts {
fn(&cfg)
}
var t time.Time
if cfg.FinishTime.IsZero() {
t = time.Now()
} else {
t = cfg.FinishTime
}
if cfg.Error != nil {
s.SetTag(ext.Error, cfg.Error)
}
s.Lock()
s.finishTime = t
s.Unlock()
s.tracer.addFinishedSpan(s)
}
// String implements fmt.Stringer.
func (s *mockspan) String() string {
sc := s.context
return fmt.Sprintf(`
name: %s
tags: %#v
start: %s
finish: %s
id: %d
parent: %d
trace: %d
baggage: %#v
`, s.name, s.tags, s.startTime, s.finishTime, sc.spanID, s.parentID, sc.traceID, sc.baggage)
}
// Context returns the SpanContext of this Span.
func (s *mockspan) Context() ddtrace.SpanContext { return s.context }