func (t *Span) GetSpanID() string {
	return t.spanID
}
GetSpanID returns the ID of the span
package trace
import (
	"context"
	"crypto/rand"
	"encoding/hex"
	"sync"
	"time"
	"github.com/honeycombio/beeline-go/client"
	"github.com/honeycombio/beeline-go/propagation"
	"github.com/honeycombio/beeline-go/sample"
	libhoney "github.com/honeycombio/libhoney-go"
)
const (
	traceIDLengthBytes = 16
	spanIDLengthBytes  = 8
)
var GlobalConfig Config
type Config struct {
	SamplerHook func(map[string]interface{}) (bool, int)
	PresendHook func(map[string]interface{})
}
type Trace struct {
	builder          *libhoney.Builder
	traceID          string
	parentID         string
	rollupFields     map[string]float64
	rollupLock       sync.Mutex
	rootSpan         *Span
	tlfLock          sync.RWMutex
	traceLevelFields map[string]interface{}
}
func getNewID(length uint16) string {
	id := make([]byte, length)
	_, _ = rand.Read(id)
	return hex.EncodeToString(id)
}
func NewTraceFromPropagationContext(ctx context.Context, prop *propagation.PropagationContext) (context.Context, *Trace) {
	trace := &Trace{
		builder:          client.NewBuilder(),
		rollupFields:     make(map[string]float64),
		traceLevelFields: make(map[string]interface{}),
	}
	if prop != nil {
		trace.traceID = prop.TraceID
		trace.parentID = prop.ParentID
		for k, v := range prop.TraceContext {
			trace.traceLevelFields[k] = v
		}
		if prop.Dataset != "" {
			trace.builder.Dataset = prop.Dataset
		}
	}
	if trace.traceID == "" {
		trace.traceID = getNewID(traceIDLengthBytes)
	}
	rootSpan := newSpan()
	rootSpan.isRoot = true
	if trace.parentID != "" {
		rootSpan.parentID = trace.parentID
	}
	rootSpan.ev = trace.builder.NewEvent()
	rootSpan.trace = trace
	trace.rootSpan = rootSpan
	ctx = PutTraceInContext(ctx, trace)
	ctx = PutSpanInContext(ctx, rootSpan)
	return ctx, trace
}
func NewTraceFromSerializedHeaders(ctx context.Context, serializedHeaders string) (context.Context, *Trace) {
	var prop *propagation.PropagationContext
	if serializedHeaders != "" {
		prop, _ = propagation.UnmarshalHoneycombTraceContext(serializedHeaders)
	}
	return NewTraceFromPropagationContext(ctx, prop)
}
func NewTrace(ctx context.Context, prop *propagation.PropagationContext) (context.Context, *Trace) {
	return NewTraceFromPropagationContext(ctx, prop)
}
func (t *Trace) AddField(key string, val interface{}) {
	t.tlfLock.Lock()
	defer t.tlfLock.Unlock()
	if t.traceLevelFields != nil {
		t.traceLevelFields[key] = val
	}
}
func (t *Trace) serializeHeaders(spanID string) string {
	prop := t.propagationContext()
	prop.ParentID = spanID
	return propagation.MarshalHoneycombTraceContext(prop)
}
func (t *Trace) propagationContext() *propagation.PropagationContext {
	t.tlfLock.Lock()
	defer t.tlfLock.Unlock()
	localTLF := map[string]interface{}{}
	for k, v := range t.traceLevelFields {
		localTLF[k] = v
	}
	return &propagation.PropagationContext{
		TraceID:      t.traceID,
		Dataset:      t.builder.Dataset,
		TraceContext: localTLF,
		TraceFlags:   propagation.FlagsSampled,  
	}
}
func (t *Trace) addRollupField(key string, val float64) {
	t.rollupLock.Lock()
	defer t.rollupLock.Unlock()
	if t.rollupFields != nil {
		t.rollupFields[key] += val
	}
}
func (t *Trace) getTraceLevelFields() map[string]interface{} {
	t.tlfLock.Lock()
	defer t.tlfLock.Unlock()
	retVals := make(map[string]interface{})
	for k, v := range t.traceLevelFields {
		retVals[k] = v
	}
	return retVals
}
func (t *Trace) getRollupFields() map[string]interface{} {
	t.rollupLock.Lock()
	defer t.rollupLock.Unlock()
	rollupFields := make(map[string]interface{})
	for k, v := range t.rollupFields {
		rollupFields[k] = v
	}
	return rollupFields
}
func (t *Trace) GetRootSpan() *Span {
	return t.rootSpan
}
func (t *Trace) GetTraceID() string {
	return t.traceID
}
func (t *Trace) GetParentID() string {
	return t.parentID
}
func (t *Trace) Send() {
	rs := t.rootSpan
	if !rs.isSent {
		rs.Send()
	}
}
type Span struct {
	isAsync      bool
	isSent       bool
	isRoot       bool
	children     []*Span
	childrenLock sync.Mutex
	ev           *libhoney.Event
	spanID       string
	parentID     string
	parent       *Span
	rollupFields map[string]float64
	rollupLock   sync.Mutex
	started      time.Time
	trace        *Trace
	eventLock    sync.Mutex
	sendLock     sync.RWMutex
}
func newSpan() *Span {
	return &Span{
		spanID:  getNewID(spanIDLengthBytes),
		started: time.Now(),
	}
}
func (s *Span) AddField(key string, val interface{}) {
	s.eventLock.Lock()
	defer s.eventLock.Unlock()
	if s.ev != nil {
		if err, ok := val.(error); ok {
			s.ev.AddField(key, err.Error())
		} else {
			s.ev.AddField(key, val)
		}
	}
}
func (s *Span) AddRollupField(key string, val float64) {
	if s.trace != nil {
		s.trace.addRollupField(key, val)
	}
	s.rollupLock.Lock()
	defer s.rollupLock.Unlock()
	if s.rollupFields == nil {
		s.rollupFields = make(map[string]float64)
	}
	if s.rollupFields != nil {
		s.rollupFields[key] += val
	}
}
func (s *Span) AddTraceField(key string, val interface{}) {
	if s.trace != nil {
		s.trace.AddField(key, val)
	}
}
func (s *Span) Send() {
	s.sendLock.Lock()
	defer s.sendLock.Unlock()
	if s.isSent {
		return
	}
	s.sendLocked()
}
func (s *Span) sendByParent() {
	s.sendLock.Lock()
	defer s.sendLock.Unlock()
	if s.isSent {
		return
	}
	s.AddField("meta.sent_by_parent", true)
	s.sendLocked()
}
func (s *Span) sendLocked() {
	if s.ev == nil {
		return
	}
	if !s.started.IsZero() {
		dur := float64(time.Since(s.started)) / float64(time.Millisecond)
		s.AddField("duration_ms", dur)
	}
	s.ev.AddField("trace.trace_id", s.trace.traceID)
	if s.parentID != "" {
		s.AddField("trace.parent_id", s.parentID)
	}
	s.ev.AddField("trace.span_id", s.spanID)
	s.rollupLock.Lock()
	for k, v := range s.rollupFields {
		s.AddField(k, v)
	}
	s.rollupLock.Unlock()
	s.childrenLock.Lock()
	var childrenToSend []*Span
	if len(s.children) > 0 {
		childrenToSend = make([]*Span, 0, len(s.children))
		for _, child := range s.children {
			if !child.IsAsync() {
				childrenToSend = append(childrenToSend, child)
			}
		}
	}
	s.childrenLock.Unlock()
	for _, child := range childrenToSend {
		child.sendByParent()
	}
	s.send()
	s.isSent = true
	if s.parent != nil {
		s.parent.removeChildSpan(s)
	}
}
func (s *Span) IsAsync() bool {
	return s.isAsync
}
func (s *Span) GetChildren() []*Span {
	return s.children
}
func (s *Span) GetParent() *Span {
	return s.parent
}