22// Licensed under the MIT License.
33
44using System ;
5+ using System . Collections . Generic ;
6+ using System . Diagnostics . CodeAnalysis ;
57using System . IO ;
68using System . Text ;
79using System . Text . Json ;
810using System . Threading ;
9-
1011using Azure . Core ;
12+ using Azure . Monitor . OpenTelemetry . Exporter . Internals . ConnectionString ;
13+ using Azure . Monitor . OpenTelemetry . Exporter . Internals . Diagnostics ;
14+ using Azure . Monitor . OpenTelemetry . Exporter . Internals . PersistentStorage ;
1115using Azure . Monitor . OpenTelemetry . Exporter . Models ;
1216using OpenTelemetry ;
1317using OpenTelemetry . PersistentStorage . Abstractions ;
14- using Azure . Monitor . OpenTelemetry . Exporter . Internals . PersistentStorage ;
15- using System . Diagnostics . CodeAnalysis ;
16- using Azure . Monitor . OpenTelemetry . Exporter . Internals . ConnectionString ;
17- using Azure . Monitor . OpenTelemetry . Exporter . Internals . Diagnostics ;
18- using System . Collections . Generic ;
1918
2019namespace Azure . Monitor . OpenTelemetry . Exporter . Internals
2120{
@@ -25,6 +24,26 @@ internal static class HttpPipelineHelper
2524
2625 internal static int MinimumRetryInterval = 60000 ;
2726
27+ private static TransmissionResult CreateTransmissionResult ( ) => new ( )
28+ {
29+ ExportResult = ExportResult . Failure ,
30+ WillRetry = false ,
31+ SavedToStorage = false ,
32+ DeletedBlob = false ,
33+ StatusCode = 0 ,
34+ ItemsAccepted = null
35+ } ;
36+
37+ private static bool IsRetriableStatus ( int statusCode ) => statusCode == ResponseStatusCodes . RequestTimeout
38+ || statusCode == ResponseStatusCodes . ResponseCodeTooManyRequests
39+ || statusCode == ResponseStatusCodes . ResponseCodeTooManyRequestsAndRefreshCache
40+ || statusCode == ResponseStatusCodes . Unauthorized
41+ || statusCode == ResponseStatusCodes . Forbidden
42+ || statusCode == ResponseStatusCodes . InternalServerError
43+ || statusCode == ResponseStatusCodes . BadGateway
44+ || statusCode == ResponseStatusCodes . ServiceUnavailable
45+ || statusCode == ResponseStatusCodes . GatewayTimeout ;
46+
2847 internal static int GetItemsAccepted ( HttpMessage message )
2948 {
3049 return TryGetTrackResponse ( message , out var trackResponse )
@@ -180,118 +199,130 @@ internal static ExportResult IsSuccess(HttpMessage httpMessage)
180199 return ExportResult . Failure ;
181200 }
182201
183- internal static ExportResult HandleFailures ( HttpMessage httpMessage , PersistentBlobProvider blobProvider , ConnectionVars connectionVars , TelemetryItemOrigin origin , bool isAadEnabled )
202+ /// <summary>
203+ /// Centralized handling of a transmission result (exporter or storage origin).
204+ /// Decides whether to persist for retry, delete existing storage blob, and logs telemetry.
205+ /// </summary>
206+ /// <param name="httpMessage">The HTTP message (request/response).</param>
207+ /// <param name="blobProvider">Optional blob provider used to save new blobs.</param>
208+ /// <param name="blob">Existing blob (when retransmitting from storage).</param>
209+ /// <param name="connectionVars">Connection vars for logging.</param>
210+ /// <param name="origin">Origin of telemetry (Exporter vs Storage).</param>
211+ /// <param name="isAadEnabled">If AAD auth is enabled.</param>
212+ /// <returns>TransmissionResult describing actions taken.</returns>
213+ internal static TransmissionResult ProcessTransmissionResult ( HttpMessage httpMessage , PersistentBlobProvider ? blobProvider , PersistentBlob ? blob , ConnectionVars connectionVars , TelemetryItemOrigin origin , bool isAadEnabled )
184214 {
185- ExportResult result = ExportResult . Failure ;
186- int statusCode = 0 ;
187- byte [ ] ? content ;
215+ var result = CreateTransmissionResult ( ) ;
188216
189217 if ( ! httpMessage . HasResponse )
190218 {
191- // HttpRequestException
192- if ( TryGetRequestContent ( httpMessage . Request . Content , out content ) )
219+ if ( origin != TelemetryItemOrigin . Storage )
193220 {
194- result = blobProvider . SaveTelemetry ( content ) ;
221+ HandleNetworkFailure ( httpMessage , blobProvider , origin , ref result ) ;
195222 }
223+
224+ AzureMonitorExporterEventSource . Log . TransmissionFailed (
225+ origin : origin ,
226+ statusCode : result . StatusCode ,
227+ isAadEnabled : isAadEnabled ,
228+ connectionVars : connectionVars ,
229+ requestEndpoint : httpMessage . Request . Uri . Host ,
230+ willRetry : result . WillRetry ,
231+ response : null ) ;
232+
233+ return result ;
234+ }
235+
236+ result . StatusCode = httpMessage . Response . Status ;
237+
238+ if ( result . StatusCode == ResponseStatusCodes . PartialSuccess )
239+ {
240+ HandlePartialSuccess ( httpMessage , blobProvider , blob , origin , ref result ) ;
241+ }
242+ else if ( IsRetriableStatus ( result . StatusCode ) )
243+ {
244+ HandleRetriableFailure ( httpMessage , blobProvider , origin , ref result ) ;
196245 }
197246 else
198247 {
199- statusCode = httpMessage . Response . Status ;
200- switch ( statusCode )
201- {
202- case ResponseStatusCodes . PartialSuccess :
203- // Parse retry-after header
204- // Send Failed Messages To Storage
205- if ( TryGetTrackResponse ( httpMessage , out TrackResponse ? trackResponse ) )
206- {
207- content = HttpPipelineHelper . GetPartialContentForRetry ( trackResponse , httpMessage . Request . Content ) ;
208- if ( content != null )
209- {
210- result = blobProvider . SaveTelemetry ( content ) ;
211- }
212- }
213- break ;
214- case ResponseStatusCodes . RequestTimeout :
215- case ResponseStatusCodes . ResponseCodeTooManyRequests :
216- case ResponseStatusCodes . ResponseCodeTooManyRequestsAndRefreshCache :
217- case ResponseStatusCodes . Unauthorized :
218- case ResponseStatusCodes . Forbidden :
219- case ResponseStatusCodes . InternalServerError :
220- case ResponseStatusCodes . BadGateway :
221- case ResponseStatusCodes . ServiceUnavailable :
222- case ResponseStatusCodes . GatewayTimeout :
223- // Send Messages To Storage
224- if ( TryGetRequestContent ( httpMessage . Request . Content , out content ) )
225- {
226- result = blobProvider . SaveTelemetry ( content ) ;
227- }
228- break ;
229- default :
230- // Log Non-Retriable Status and don't retry or store;
231- break ;
232- }
248+ HandleNonRetriableFailure ( blob , origin , ref result ) ;
233249 }
234250
235251 AzureMonitorExporterEventSource . Log . TransmissionFailed (
236252 origin : origin ,
237- statusCode : statusCode ,
253+ statusCode : result . StatusCode ,
238254 isAadEnabled : isAadEnabled ,
239255 connectionVars : connectionVars ,
240256 requestEndpoint : httpMessage . Request . Uri . Host ,
241- willRetry : ( result == ExportResult . Success ) ,
242- response : httpMessage . HasResponse ? httpMessage . Response : null ) ;
257+ willRetry : result . WillRetry ,
258+ response : httpMessage . Response ) ;
243259
244260 return result ;
245261 }
246262
247- internal static void HandleFailures ( HttpMessage httpMessage , PersistentBlob blob , PersistentBlobProvider blobProvider , ConnectionVars connectionVars , bool isAadEnabled )
263+ private static void HandleNetworkFailure ( HttpMessage httpMessage , PersistentBlobProvider ? blobProvider , TelemetryItemOrigin origin , ref TransmissionResult result )
264+ {
265+ if ( blobProvider != null && TryGetRequestContent ( httpMessage . Request . Content , out var content ) )
266+ {
267+ result . ExportResult = blobProvider . SaveTelemetry ( content ) ;
268+ result . WillRetry = ( result . ExportResult == ExportResult . Success ) ;
269+ result . SavedToStorage = result . WillRetry ;
270+ }
271+ }
272+
273+ private static void HandlePartialSuccess ( HttpMessage httpMessage , PersistentBlobProvider ? blobProvider , PersistentBlob ? blob , TelemetryItemOrigin origin , ref TransmissionResult result )
248274 {
249- int statusCode = 0 ;
250- bool willRetry = true ;
275+ if ( ! TryGetTrackResponse ( httpMessage , out TrackResponse ? trackResponse ) )
276+ {
277+ return ;
278+ }
279+
280+ result . ItemsAccepted = trackResponse . ItemsAccepted ;
281+ var partialContent = GetPartialContentForRetry ( trackResponse , httpMessage . Request . Content ) ;
282+ if ( partialContent == null || blobProvider == null )
283+ {
284+ return ;
285+ }
251286
252- if ( httpMessage . HasResponse )
287+ if ( origin == TelemetryItemOrigin . Storage && blob != null )
253288 {
254- statusCode = httpMessage . Response . Status ;
255- switch ( statusCode )
289+ if ( blob . TryDelete ( ) )
256290 {
257- case ResponseStatusCodes . PartialSuccess :
258- // Parse retry-after header
259- // Send Failed Messages To Storage
260- // Delete existing file
261- if ( TryGetTrackResponse ( httpMessage , out TrackResponse ? trackResponse ) )
262- {
263- var content = GetPartialContentForRetry ( trackResponse , httpMessage . Request . Content ) ;
264- if ( content != null )
265- {
266- blob . TryDelete ( ) ;
267- blobProvider . SaveTelemetry ( content ) ;
268- }
269- }
270- break ;
271- case ResponseStatusCodes . RequestTimeout :
272- case ResponseStatusCodes . ResponseCodeTooManyRequests :
273- case ResponseStatusCodes . ResponseCodeTooManyRequestsAndRefreshCache :
274- case ResponseStatusCodes . Unauthorized :
275- case ResponseStatusCodes . Forbidden :
276- case ResponseStatusCodes . InternalServerError :
277- case ResponseStatusCodes . BadGateway :
278- case ResponseStatusCodes . ServiceUnavailable :
279- case ResponseStatusCodes . GatewayTimeout :
280- break ;
281- default :
282- willRetry = false ;
283- break ;
291+ result . DeletedBlob = true ;
284292 }
285293 }
286294
287- AzureMonitorExporterEventSource . Log . TransmissionFailed (
288- origin : TelemetryItemOrigin . Storage ,
289- isAadEnabled : isAadEnabled ,
290- statusCode : statusCode ,
291- connectionVars : connectionVars ,
292- requestEndpoint : httpMessage . Request . Uri . Host ,
293- willRetry : willRetry ,
294- response : httpMessage . HasResponse ? httpMessage . Response : null ) ;
295+ result . ExportResult = blobProvider . SaveTelemetry ( partialContent ) ;
296+ result . WillRetry = ( result . ExportResult == ExportResult . Success ) ;
297+ result . SavedToStorage = result . WillRetry ;
298+ }
299+
300+ private static void HandleRetriableFailure ( HttpMessage httpMessage , PersistentBlobProvider ? blobProvider , TelemetryItemOrigin origin , ref TransmissionResult result )
301+ {
302+ if ( origin != TelemetryItemOrigin . Storage )
303+ {
304+ if ( blobProvider != null && TryGetRequestContent ( httpMessage . Request . Content , out var content ) )
305+ {
306+ result . ExportResult = blobProvider . SaveTelemetry ( content ) ;
307+ result . WillRetry = ( result . ExportResult == ExportResult . Success ) ;
308+ result . SavedToStorage = result . WillRetry ;
309+ }
310+ }
311+ else if ( origin == TelemetryItemOrigin . Storage )
312+ {
313+ result . WillRetry = true ;
314+ }
315+ }
316+
317+ private static void HandleNonRetriableFailure ( PersistentBlob ? blob , TelemetryItemOrigin origin , ref TransmissionResult result )
318+ {
319+ if ( origin == TelemetryItemOrigin . Storage && blob != null )
320+ {
321+ if ( blob . TryDelete ( ) )
322+ {
323+ result . DeletedBlob = true ;
324+ }
325+ }
295326 }
296327 }
297328}
0 commit comments