11using System ;
22using System . Collections . Generic ;
33using System . Linq ;
4+ using System . Net . Http ;
45using System . Threading ;
56using System . Threading . Tasks ;
67using LightStep . Collector ;
@@ -19,9 +20,10 @@ public sealed class Tracer : ITracer
1920 private readonly Options _options ;
2021 private readonly IPropagator _propagator ;
2122 private readonly LightStepHttpClient _httpClient ;
22- private readonly ISpanRecorder _spanRecorder ;
23+ private ISpanRecorder _spanRecorder ;
2324 private readonly Timer _reportLoop ;
2425 private static readonly ILog _logger = LogProvider . GetCurrentClassLogger ( ) ;
26+ private int currentDroppedSpanCount ;
2527
2628 /// <inheritdoc />
2729 public Tracer ( Options options ) : this ( new AsyncLocalScopeManager ( ) , Propagators . TextMap , options ,
@@ -96,26 +98,67 @@ public async void Flush()
9698 if ( _options . Run )
9799 {
98100 // save current spans and clear the buffer
99- // TODO: add retry logic so as to not drop spans on unreachable satellite
100- _logger . Debug ( $ "Flushing SpanData") ;
101- List < SpanData > currentSpans = new List < SpanData > ( ) ;
101+ ISpanRecorder currentBuffer ;
102102 lock ( _lock )
103103 {
104- _logger . Debug ( $ "Lock freed, getting current buffer." ) ;
105- currentSpans = _spanRecorder . GetSpanBuffer ( ) ;
106- _logger . Debug ( $ "{ currentSpans . Count } spans copied from buffer.") ;
104+ currentBuffer = _spanRecorder . GetSpanBuffer ( ) ;
105+ _spanRecorder = new LightStepSpanRecorder ( ) ;
106+ _logger . Debug ( $ "{ currentBuffer . GetSpans ( ) . Count ( ) } spans in buffer.") ;
107107 }
108- var data = _httpClient . Translate ( currentSpans ) ;
109- var resp = await _httpClient . SendReport ( data ) ;
110- if ( resp . Errors . Count > 0 ) _logger . Warn ( $ "Errors sending report to LightStep: { resp . Errors } ") ;
108+
109+ /**
110+ * there are two ways spans can be dropped:
111+ * 1. the buffer drops a span because it's too large, malformed, etc.
112+ * 2. the report failed to be sent to the satellite.
113+ * since flush is async and there can potentially be any number of buffers in flight to the satellite,
114+ * we need to set the current drop count on the tracer to be the amount of dropped spans from the buffer
115+ * plus the existing dropped spans, then mutate the current buffer to this new total value.
116+ */
117+ currentDroppedSpanCount += currentBuffer . DroppedSpanCount ;
118+ currentBuffer . DroppedSpanCount = currentDroppedSpanCount ;
119+ var data = _httpClient . Translate ( currentBuffer ) ;
120+
121+ try
122+ {
123+ var resp = await _httpClient . SendReport ( data ) ;
124+ if ( resp . Errors . Count > 0 )
125+ {
126+ _logger . Warn ( $ "Errors in report: { resp . Errors } ") ;
127+ }
128+
129+ lock ( _lock )
130+ {
131+ _logger . Debug ( $ "Resetting tracer dropped span count as the last report was successful.") ;
132+ currentDroppedSpanCount = 0 ;
133+ }
134+
135+ }
136+ catch ( Exception ex ) when ( ex is HttpRequestException || ex is TaskCanceledException || ex is OperationCanceledException )
137+ {
138+ lock ( _lock )
139+ {
140+ _logger . Warn ( $ "Adding { currentBuffer . GetSpans ( ) . Count ( ) } spans to dropped span count (current total: { currentDroppedSpanCount } )") ;
141+ currentDroppedSpanCount += currentBuffer . GetSpans ( ) . Count ( ) ;
142+ }
143+ }
144+
145+
111146 }
112147 }
113148
114149 internal void AppendFinishedSpan ( SpanData span )
115150 {
116151 lock ( _lock )
117152 {
118- _spanRecorder . RecordSpan ( span ) ;
153+ if ( _spanRecorder . GetSpans ( ) . Count ( ) < _options . ReportMaxSpans )
154+ {
155+ _spanRecorder . RecordSpan ( span ) ;
156+ }
157+ else
158+ {
159+ _spanRecorder . RecordDroppedSpans ( 1 ) ;
160+ _logger . Warn ( $ "Dropping span due to too many spans in buffer.") ;
161+ }
119162 }
120163 }
121164 }
0 commit comments