Skip to content

Commit 3f8874c

Browse files
Prepare HttpPipelineHelper to onbord customer sdk stats. (Azure#52565)
1 parent 86d23e3 commit 3f8874c

File tree

4 files changed

+150
-93
lines changed

4 files changed

+150
-93
lines changed

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/AzureMonitorTransmitter.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ await _applicationInsightsRestClient.InternalTrackAsync(telemetryItems, cancella
179179
if (result == ExportResult.Failure && _fileBlobProvider != null)
180180
{
181181
_transmissionStateManager.EnableBackOff(httpMessage.HasResponse ? httpMessage.Response : null);
182-
result = HttpPipelineHelper.HandleFailures(httpMessage, _fileBlobProvider, _connectionVars, origin, _isAadEnabled);
182+
var transmissionResult = HttpPipelineHelper.ProcessTransmissionResult(httpMessage, _fileBlobProvider, null, _connectionVars, origin, _isAadEnabled);
183+
result = transmissionResult.ExportResult;
183184
}
184185
else
185186
{

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/HttpPipelineHelper.cs

Lines changed: 122 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@
22
// Licensed under the MIT License.
33

44
using System;
5+
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
57
using System.IO;
68
using System.Text;
79
using System.Text.Json;
810
using System.Threading;
9-
1011
using 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;
1115
using Azure.Monitor.OpenTelemetry.Exporter.Models;
1216
using OpenTelemetry;
1317
using 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

2019
namespace 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
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using OpenTelemetry;
5+
6+
namespace Azure.Monitor.OpenTelemetry.Exporter.Internals
7+
{
8+
/// <summary>
9+
/// Represents the unified result of attempting to transmit telemetry (exporter or from storage).
10+
/// </summary>
11+
internal struct TransmissionResult
12+
{
13+
internal ExportResult ExportResult { get; set; }
14+
15+
internal bool WillRetry { get; set; }
16+
17+
internal bool SavedToStorage { get; set; }
18+
19+
internal bool DeletedBlob { get; set; }
20+
21+
internal int StatusCode { get; set; }
22+
23+
internal int? ItemsAccepted { get; set; }
24+
}
25+
}

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/TransmitFromStorageHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ internal void TransmitFromStorage(object? sender, ElapsedEventArgs? e)
7070
else
7171
{
7272
_transmissionStateManager.EnableBackOff(httpMessage.HasResponse ? httpMessage.Response : null);
73-
HttpPipelineHelper.HandleFailures(httpMessage, blob, _blobProvider, _connectionVars, _isAadEnabled);
73+
HttpPipelineHelper.ProcessTransmissionResult(httpMessage, _blobProvider, blob, _connectionVars, TelemetryItemOrigin.Storage, _isAadEnabled);
7474
break;
7575
}
7676
}

0 commit comments

Comments
 (0)