1package lightstep
2
3import (
4	"time"
5)
6
7type reportBuffer struct {
8	rawSpans []RawSpan
9
10	// droppedSpanCount is the total number of spans that have been dropped
11	// (either because the buffer was full when the span arrived or because a report
12	// failed and there wasn't sufficient room to re-enqueue the spans back into the
13	// following report).
14	//
15	// This counter increases continually until is has successfully been reported
16	// to the telemetry provider by being attached to a report that doesn't return
17	// an error.
18	droppedSpanCount int64
19	// reportedDroppedSpanCount is a counter that tracks the cumulative value of what
20	// has been reported to the service through an event status report. This should
21	// always be smaller than droppedSpanCount because droppedSpanCount is monotonically
22	// increasing and this only represents the value reported in the past.
23	// To determine what to report in the next event status report, subtract the previously
24	// reported value from the updated dropped spans count (see reportDroppedSpanCount).
25	reportedDroppedSpanCount int64
26
27	// logEncoderErrorCount is the total number of spans that have been rejected
28	// because of a log encoder error.
29	//
30	// This counter increases continually until is has successfully been reported
31	// to the telemetry provider by being attached to a report that doesn't return
32	// an error.
33	logEncoderErrorCount int64
34	// reportedLogEncoderErrorCount is a counter that tracks the cumulative value of what
35	// has been reported to the service through an event status report. This should
36	// always be smaller than logEncoderErrorCount because logEncoderErrorCount is monotonically
37	// increasing and this only represents the value reported in the past.
38	// To determine what to report in the next event status report, subtract the previously
39	// reported value from the updated dropped spans count (see reportLogEncoderErrorCount).
40	reportedLogEncoderErrorCount int64
41
42	reportStart time.Time
43	reportEnd   time.Time
44}
45
46func newSpansBuffer(size int) (b reportBuffer) {
47	b.rawSpans = make([]RawSpan, 0, size)
48	b.reportStart = time.Time{}
49	b.reportEnd = time.Time{}
50	return
51}
52
53func (b *reportBuffer) isHalfFull() bool {
54	return len(b.rawSpans) > cap(b.rawSpans)/2
55}
56
57func (b *reportBuffer) setCurrent(now time.Time) {
58	b.reportStart = now
59	b.reportEnd = now
60}
61
62func (b *reportBuffer) setFlushing(now time.Time) {
63	b.reportEnd = now
64}
65
66func (b *reportBuffer) clear() {
67	b.rawSpans = b.rawSpans[:0]
68	b.reportStart = time.Time{}
69	b.reportEnd = time.Time{}
70	b.droppedSpanCount = 0
71	b.reportedDroppedSpanCount = 0
72	b.logEncoderErrorCount = 0
73	b.reportedLogEncoderErrorCount = 0
74}
75
76func (b *reportBuffer) addSpan(span RawSpan) {
77	if len(b.rawSpans) == cap(b.rawSpans) {
78		b.droppedSpanCount++
79		return
80	}
81	b.rawSpans = append(b.rawSpans, span)
82}
83
84// mergeFrom combines the spans and metadata in `from` with `into`,
85// returning with `from` empty and `into` having a subset of the
86// combined data.
87func (b *reportBuffer) mergeFrom(from *reportBuffer) {
88	b.droppedSpanCount += from.droppedSpanCount
89	b.reportedDroppedSpanCount += from.reportedDroppedSpanCount
90	b.logEncoderErrorCount += from.logEncoderErrorCount
91	b.reportedLogEncoderErrorCount += from.reportedLogEncoderErrorCount
92
93	if from.reportStart.Before(b.reportStart) {
94		b.reportStart = from.reportStart
95	}
96	if from.reportEnd.After(b.reportEnd) {
97		b.reportEnd = from.reportEnd
98	}
99
100	// Note: Somewhat arbitrarily dropping the spans that won't
101	// fit; could be more principled here to avoid bias.
102	have := len(b.rawSpans)
103	space := cap(b.rawSpans) - have
104	unreported := len(from.rawSpans)
105
106	if space > unreported {
107		space = unreported
108	}
109
110	b.rawSpans = append(b.rawSpans, from.rawSpans[0:space]...)
111
112	if unreported > space {
113		b.droppedSpanCount += int64(unreported - space)
114	}
115
116	from.clear()
117}
118
119func (b *reportBuffer) reportDroppedSpanCount() int64 {
120	var toReport int64
121	toReport, b.reportedDroppedSpanCount = b.droppedSpanCount-b.reportedDroppedSpanCount, b.droppedSpanCount
122	return toReport
123}
124
125func (b *reportBuffer) reportLogEncoderErrorCount() int64 {
126	var toReport int64
127	toReport, b.reportedLogEncoderErrorCount = b.logEncoderErrorCount-b.reportedLogEncoderErrorCount, b.logEncoderErrorCount
128	return toReport
129}
130