<commit_before>package instana

import (
	"fmt"
	"os"
	"sync"
	"time"

	"github.com/opentracing/basictracer-go"
	ext "github.com/opentracing/opentracing-go/ext"
)

type SpanRecorder struct {
	sync.RWMutex
	spans    []Span
	testMode bool
}

type Span struct {
	TraceID   uint64      `json:"t"`
	ParentID  *uint64     `json:"p,omitempty"`
	SpanID    uint64      `json:"s"`
	Timestamp uint64      `json:"ts"`
	Duration  uint64      `json:"d"`
	Name      string      `json:"n"`
	From      *FromS      `json:"f"`
	Data      interface{} `json:"data"`
}

// NewRecorder Establish a new span recorder
func NewRecorder() *SpanRecorder {
	r := new(SpanRecorder)
	r.init()
	return r
}

// NewTestRecorder Establish a new span recorder used for testing
func NewTestRecorder() *SpanRecorder {
	r := new(SpanRecorder)
	r.testMode = true
	r.init()
	return r
}

// GetSpans returns a copy of the array of spans accumulated so far.
func (r *SpanRecorder) GetSpans() []Span {
	r.RLock()
	defer r.RUnlock()
	spans := make([]Span, len(r.spans))
	copy(spans, r.spans)
	return spans
}

func getTag(rawSpan basictracer.RawSpan, tag string) interface{} {
	var x, ok = rawSpan.Tags[tag]
	if !ok {
		x = ""
	}
	return x
}

func getIntTag(rawSpan basictracer.RawSpan, tag string) int {
	d := rawSpan.Tags[tag]
	if d == nil {
		return -1
	}

	r, ok := d.(int)
	if !ok {
		return -1
	}

	return r
}

func getStringTag(rawSpan basictracer.RawSpan, tag string) string {
	d := rawSpan.Tags[tag]
	if d == nil {
		return ""
	}
	return fmt.Sprint(d)
}

func getHostName(rawSpan basictracer.RawSpan) string {
	hostTag := getStringTag(rawSpan, string(ext.PeerHostname))
	if hostTag != "" {
		return hostTag
	}

	h, err := os.Hostname()
	if err != nil {
		h = "localhost"
	}

	return h
}

func getServiceName(rawSpan basictracer.RawSpan) string {
	// ServiceName can be determined from multiple sources and has
	// the following priority (preferred first):
	//   1. If added to the span via the OT component tag
	//   2. If added to the span via the OT http.url tag
	//   3. Specified in the tracer instantiation via Service option
	component := getStringTag(rawSpan, string(ext.Component))

	if len(component) > 0 {
		return component
	} else if len(component) == 0 {
		httpURL := getStringTag(rawSpan, string(ext.HTTPUrl))

		if len(httpURL) > 0 {
			return httpURL
		}
	}
	return sensor.serviceName
}

func getSpanKind(rawSpan basictracer.RawSpan) string {
	kind := getStringTag(rawSpan, string(ext.SpanKind))

	switch kind {
	case string(ext.SpanKindRPCServerEnum), "consumer", "entry":
		return "entry"
	case string(ext.SpanKindRPCClientEnum), "producer", "exit":
		return "exit"
	}
	return ""
}

func collectLogs(rawSpan basictracer.RawSpan) map[uint64]map[string]interface{} {
	logs := make(map[uint64]map[string]interface{})
	for _, l := range rawSpan.Logs {
		if _, ok := logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)]; !ok {
			logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)] = make(map[string]interface{})
		}

		for _, f := range l.Fields {
			logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)][f.Key()] = f.Value()
		}
	}

	return logs
}

func (r *SpanRecorder) init() {
	r.reset()

	if r.testMode {
		log.debug("Recorder in test mode.  Not reporting spans to the backend.")
	} else {
		ticker := time.NewTicker(1 * time.Second)
		go func() {
			for range ticker.C {
				log.debug("Sending spans to agent", len(r.spans))

				r.send()
			}
		}()
	}
}

func (r *SpanRecorder) reset() {
	r.Lock()
	defer r.Unlock()
	r.spans = make([]Span, 0, sensor.options.MaxBufferedSpans)<commit_msg>Remove unneeded dbg msg; only send when can<commit_after>package instana

import (
	"fmt"
	"os"
	"sync"
	"time"

	"github.com/opentracing/basictracer-go"
	ext "github.com/opentracing/opentracing-go/ext"
)

type SpanRecorder struct {
	sync.RWMutex
	spans    []Span
	testMode bool
}

type Span struct {
	TraceID   uint64      `json:"t"`
	ParentID  *uint64     `json:"p,omitempty"`
	SpanID    uint64      `json:"s"`
	Timestamp uint64      `json:"ts"`
	Duration  uint64      `json:"d"`
	Name      string      `json:"n"`
	From      *FromS      `json:"f"`
	Data      interface{} `json:"data"`
}

// NewRecorder Establish a new span recorder
func NewRecorder() *SpanRecorder {
	r := new(SpanRecorder)
	r.init()
	return r
}

// NewTestRecorder Establish a new span recorder used for testing
func NewTestRecorder() *SpanRecorder {
	r := new(SpanRecorder)
	r.testMode = true
	r.init()
	return r
}

// GetSpans returns a copy of the array of spans accumulated so far.
func (r *SpanRecorder) GetSpans() []Span {
	r.RLock()
	defer r.RUnlock()
	spans := make([]Span, len(r.spans))
	copy(spans, r.spans)
	return spans
}

func getTag(rawSpan basictracer.RawSpan, tag string) interface{} {
	var x, ok = rawSpan.Tags[tag]
	if !ok {
		x = ""
	}
	return x
}

func getIntTag(rawSpan basictracer.RawSpan, tag string) int {
	d := rawSpan.Tags[tag]
	if d == nil {
		return -1
	}

	r, ok := d.(int)
	if !ok {
		return -1
	}

	return r
}

func getStringTag(rawSpan basictracer.RawSpan, tag string) string {
	d := rawSpan.Tags[tag]
	if d == nil {
		return ""
	}
	return fmt.Sprint(d)
}

func getHostName(rawSpan basictracer.RawSpan) string {
	hostTag := getStringTag(rawSpan, string(ext.PeerHostname))
	if hostTag != "" {
		return hostTag
	}

	h, err := os.Hostname()
	if err != nil {
		h = "localhost"
	}

	return h
}

func getServiceName(rawSpan basictracer.RawSpan) string {
	// ServiceName can be determined from multiple sources and has
	// the following priority (preferred first):
	//   1. If added to the span via the OT component tag
	//   2. If added to the span via the OT http.url tag
	//   3. Specified in the tracer instantiation via Service option
	component := getStringTag(rawSpan, string(ext.Component))

	if len(component) > 0 {
		return component
	} else if len(component) == 0 {
		httpURL := getStringTag(rawSpan, string(ext.HTTPUrl))

		if len(httpURL) > 0 {
			return httpURL
		}
	}
	return sensor.serviceName
}

func getSpanKind(rawSpan basictracer.RawSpan) string {
	kind := getStringTag(rawSpan, string(ext.SpanKind))

	switch kind {
	case string(ext.SpanKindRPCServerEnum), "consumer", "entry":
		return "entry"
	case string(ext.SpanKindRPCClientEnum), "producer", "exit":
		return "exit"
	}
	return ""
}

func collectLogs(rawSpan basictracer.RawSpan) map[uint64]map[string]interface{} {
	logs := make(map[uint64]map[string]interface{})
	for _, l := range rawSpan.Logs {
		if _, ok := logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)]; !ok {
			logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)] = make(map[string]interface{})
		}

		for _, f := range l.Fields {
			logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)][f.Key()] = f.Value()
		}
	}

	return logs
}

func (r *SpanRecorder) init() {
	r.reset()

	if !r.testMode {
		ticker := time.NewTicker(1 * time.Second)
		go func() {
			for range ticker.C {
				// Only attempt to send spans if we're announced.
				if sensor.agent.canSend() {
					log.debug("Sending spans to agent", len(r.spans))
					r.send()
				}
			}
		}()
	}
}

func (r *SpanRecorder) reset() {
	r.Lock()
	defer r.Unlock()
	r.spans = make([]Span, 0, sensor.options.MaxBufferedSpans)
{'fraction_non_alphanumeric': 0.1377642669614481, 'fraction_numerical': 0.009948873842752521, 'mean_word_length': 3.6367713004484306, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5949997', 'n_tokens_mistral': 2809, 'n_tokens_neox': 2678, 'n_words': 679}