1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Linq ;
4
+ using System . Net . Http ;
4
5
using System . Threading ;
5
6
using System . Threading . Tasks ;
6
7
using LightStep . Collector ;
@@ -19,9 +20,10 @@ public sealed class Tracer : ITracer
19
20
private readonly Options _options ;
20
21
private readonly IPropagator _propagator ;
21
22
private readonly LightStepHttpClient _httpClient ;
22
- private readonly ISpanRecorder _spanRecorder ;
23
+ private ISpanRecorder _spanRecorder ;
23
24
private readonly Timer _reportLoop ;
24
25
private static readonly ILog _logger = LogProvider . GetCurrentClassLogger ( ) ;
26
+ private int currentDroppedSpanCount ;
25
27
26
28
/// <inheritdoc />
27
29
public Tracer ( Options options ) : this ( new AsyncLocalScopeManager ( ) , Propagators . TextMap , options ,
@@ -96,26 +98,67 @@ public async void Flush()
96
98
if ( _options . Run )
97
99
{
98
100
// 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 ;
102
102
lock ( _lock )
103
103
{
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.") ;
107
107
}
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
+
111
146
}
112
147
}
113
148
114
149
internal void AppendFinishedSpan ( SpanData span )
115
150
{
116
151
lock ( _lock )
117
152
{
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
+ }
119
162
}
120
163
}
121
164
}
0 commit comments