Skip to content

Commit ff93be2

Browse files
Search: Extend telemetry information (#6967)
Extend the telemetry information
1 parent 7fa9bd9 commit ff93be2

5 files changed

Lines changed: 61 additions & 20 deletions

File tree

src/NuGetGallery/Infrastructure/Lucene/HttpClientWrapper.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System;
55
using System.Net.Http;
66
using System.Threading.Tasks;
7+
using NuGetGallery.Infrastructure.Search;
8+
using Polly;
79

810
namespace NuGetGallery.Infrastructure
911
{
@@ -18,9 +20,18 @@ public HttpClientWrapper(HttpClient httpClient)
1820

1921
public Uri BaseAddress => _httpClient.BaseAddress;
2022

21-
public Task<HttpResponseMessage> GetAsync(Uri uri)
23+
public async Task<HttpResponseMessage> GetAsync(Uri uri)
2224
{
23-
return _httpClient.GetAsync(uri);
25+
// Add the request Uri to the Polly context to be used for logging.
26+
// https://docs.microsoft.com/en-us/dotnet/api/polly.httprequestmessageextensions.setpolicyexecutioncontext?view=aspnetcore-2.2
27+
// http://www.thepollyproject.org/2017/05/04/putting-the-context-into-polly/
28+
using (var request = new HttpRequestMessage(HttpMethod.Get, uri))
29+
{
30+
var context = new Context();
31+
context.Add(SearchClientPolicies.ContextKey_RequestUri, uri.AbsoluteUri);
32+
request.SetPolicyExecutionContext(context);
33+
return await _httpClient.SendAsync(request);
34+
}
2435
}
2536
}
2637
}

src/NuGetGallery/Infrastructure/Lucene/SearchClientPolicies.cs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,20 @@
99
using Polly;
1010
using Polly.CircuitBreaker;
1111
using Polly.Extensions.Http;
12-
using NuGetGallery;
1312

1413
namespace NuGetGallery.Infrastructure.Search
1514
{
1615
// Implements Polly policies
1716
// Samples at https://github.com/App-vNext/Polly-Samples
17+
// Docs: https://github.com/App-vNext/Polly/wiki/Circuit-Breaker
1818
public class SearchClientPolicies
1919
{
20+
internal const string ContextKey_RequestUri = "RequestUri";
21+
internal const string ContextKey_CircuitBreakerStatus = "CircuitBreakerStatus";
22+
2023
/// <summary>
21-
/// Builds the CircuitBreakerPolicy. Through this policy a request will be retried for <paramref name="breakAfterCount"/> and break after. This will move the circuit breaker into Open state.
24+
/// Builds the CircuitBreakerPolicy. Through this policy if <paramref name="breakAfterCount"/> consecutive requests will fail with transient HttpErrors
25+
/// the circuit breaker will move into Open state.
2226
/// It will stay in this state(Open) for the <paramref name="breakDuration"/>. This means that requests made while the circuit is in this state will fail fast.
2327
/// When the timeout expires trial requsts are allowed. The state will be changed to a Close state if they succeed.
2428
/// If they do not succeed the circuit will be moved back in the Open state for another <paramref name="breakDuration"/>.
@@ -35,17 +39,18 @@ public static IAsyncPolicy<HttpResponseMessage> SearchClientCircuitBreakerPolicy
3539
.HandleTransientHttpError()
3640
.CircuitBreakerAsync(breakAfterCount,
3741
breakDuration,
38-
onBreak: (delegateResult, breakDelay, context) =>
42+
onBreak: (delegateResult, circuitBreakerStatus, breakDelay, context) =>
3943
{
40-
telemetryService.TrackMetricForSearchCircuitBreakerOnBreak(searchName, delegateResult.Exception, delegateResult.Result);
44+
context.Add(ContextKey_CircuitBreakerStatus, circuitBreakerStatus);
45+
telemetryService.TrackMetricForSearchCircuitBreakerOnBreak(searchName, delegateResult.Exception, delegateResult.Result, context.CorrelationId.ToString(), GetValueFromContext("RequestUri",context));
4146
logger.LogWarning("SearchCircuitBreaker logging: Breaking the circuit for {BreakDelayInMilliseconds} milliseconds due to {Exception} {SearchName}.",
4247
breakDelay.TotalMilliseconds,
4348
delegateResult.Exception,
4449
searchName);
4550
},
4651
onReset: (context) =>
4752
{
48-
telemetryService.TrackMetricForSearchCircuitBreakerOnReset(searchName);
53+
telemetryService.TrackMetricForSearchCircuitBreakerOnReset(searchName, context.CorrelationId.ToString(), GetValueFromContext("RequestUri", context));
4954
logger.LogInformation("SearchCircuitBreaker logging: Call ok! Closed the circuit again! {SearchName}", searchName);
5055
},
5156
onHalfOpen: () => logger.LogInformation("SearchCircuitBreaker logging: Half-open: Next call is a trial! {SearchName}", searchName));
@@ -69,10 +74,14 @@ public static IAsyncPolicy<HttpResponseMessage> SearchClientWaitAndRetryForeverP
6974
return false;
7075
}).
7176
WaitAndRetryForeverAsync(
72-
sleepDurationProvider: retryAttempt => TimeSpan.FromMilliseconds(SearchClientConfiguration.WaitAndRetryDefaultIntervalInMilliseconds),
73-
onRetry: (delegateResult, waitDuration) =>
77+
sleepDurationProvider: (retryAttempt, context) => TimeSpan.FromMilliseconds(SearchClientConfiguration.WaitAndRetryDefaultIntervalInMilliseconds),
78+
onRetry: (delegateResult, waitDuration, context) =>
7479
{
75-
telemetryService.TrackMetricForSearchOnRetry(searchName, delegateResult.Exception);
80+
telemetryService.TrackMetricForSearchOnRetry(searchName,
81+
delegateResult.Exception,
82+
context.CorrelationId.ToString(),
83+
GetValueFromContext(ContextKey_RequestUri, context),
84+
GetValueFromContext(ContextKey_CircuitBreakerStatus, context));
7685
logger.LogInformation("Policy retry - it will retry after {RetryMilliseconds} milliseconds. {Exception} {SearchName}", waitDuration.TotalMilliseconds, delegateResult.Exception, searchName);
7786
});
7887
}
@@ -101,5 +110,11 @@ public static IAsyncPolicy<HttpResponseMessage> SearchClientFallBackCircuitBreak
101110
logger.LogInformation("On circuit breaker fallback. {SearchName} {Exception} {Result}", searchName, delegateResult.Exception, delegateResult.Result);
102111
});
103112
}
113+
114+
private static string GetValueFromContext(string contextKey, Context context)
115+
{
116+
object objValue = null;
117+
return context.TryGetValue(contextKey, out objValue) ? objValue.ToString() : string.Empty;
118+
}
104119
}
105120
}

src/NuGetGallery/Services/ITelemetryService.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,20 +272,26 @@ void TrackMetricForTyposquattingCheckResultAndTotalTime(
272272
/// <param name="searchName">A name to identify the search instance.</param>
273273
/// <param name="exception">The exception if any.</param>
274274
/// <param name="responseMessage">The response message.</param>
275-
void TrackMetricForSearchCircuitBreakerOnBreak(string searchName, Exception exception, HttpResponseMessage responseMessage);
275+
/// <param name="correlationId">CorrelationId set by Polly context.</param>
276+
/// <param name="uri">The request uri.</param>
277+
void TrackMetricForSearchCircuitBreakerOnBreak(string searchName, Exception exception, HttpResponseMessage responseMessage, string correlationId, string uri);
276278

277279
/// <summary>
278280
/// Tracks the OnReset for the search circuit breaker.
279281
/// </summary>
280282
/// <param name="searchName">A name to identify the search instance.</param>
281-
void TrackMetricForSearchCircuitBreakerOnReset(string searchName);
283+
/// <param name="correlationId">CorrelationId set by Polly context.</param>
284+
/// <param name="uri">The request uri.</param>
285+
void TrackMetricForSearchCircuitBreakerOnReset(string searchName, string correlationId, string uri);
282286

283287
/// <summary>
284288
/// Tracks the OnRetry for the search retry policy.
285289
/// </summary>
286290
/// <param name="searchName">A name to identify the search instance.</param>
287291
/// <param name="exception">The exception.</param>
288-
/// <param name=""></param>
289-
void TrackMetricForSearchOnRetry(string searchName, Exception exception);
292+
/// <param name="correlationId">CorrelationId set by Polly context.</param>
293+
/// <param name="uri">The request uri.</param>
294+
/// <param name="circuitBreakerStatus">The CircuitBreakerStatus at the time of the Retry action.</param>
295+
void TrackMetricForSearchOnRetry(string searchName, Exception exception, string correlationId, string uri, string circuitBreakerStatus);
290296
}
291297
}

src/NuGetGallery/Services/TelemetryService.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ internal class Events
173173
public const string SearchSuccessExecutionStatus = "SearchSuccessExecutionStatus";
174174
public const string SearchException = "SearchException";
175175
public const string SearchName = "SearchName";
176+
public const string SearchPollyCorrelationId = "SearchPollyCorrelationId";
177+
public const string SearchCircuitBreakerStatus = "SearchCircuitBreakerStatus";
176178

177179
public TelemetryService(IDiagnosticsService diagnosticsService, ITelemetryClient telemetryClient = null)
178180
{
@@ -803,27 +805,34 @@ public void TrackMetricForSearchExecutionDuration(string url, TimeSpan duration,
803805
});
804806
}
805807

806-
public void TrackMetricForSearchCircuitBreakerOnBreak(string searchName, Exception exception, HttpResponseMessage responseMessage)
808+
public void TrackMetricForSearchCircuitBreakerOnBreak(string searchName, Exception exception, HttpResponseMessage responseMessage, string correlationId, string uri)
807809
{
808810
TrackMetric(Events.SearchCircuitBreakerOnBreak, 1, properties => {
809811
properties.Add(SearchName, searchName);
810812
properties.Add(SearchException, exception?.ToString() ?? string.Empty);
811813
properties.Add(SearchHttpResponseCode, responseMessage?.StatusCode.ToString() ?? string.Empty);
814+
properties.Add(SearchPollyCorrelationId, correlationId);
815+
properties.Add(SearchUrl, uri);
812816
});
813817
}
814818

815-
public void TrackMetricForSearchCircuitBreakerOnReset(string searchName)
819+
public void TrackMetricForSearchCircuitBreakerOnReset(string searchName, string correlationId, string uri)
816820
{
817821
TrackMetric(Events.SearchCircuitBreakerOnReset, 1, properties => {
818822
properties.Add(SearchName, searchName);
823+
properties.Add(SearchPollyCorrelationId, correlationId);
824+
properties.Add(SearchUrl, uri);
819825
});
820826
}
821827

822-
public void TrackMetricForSearchOnRetry(string searchName, Exception exception)
828+
public void TrackMetricForSearchOnRetry(string searchName, Exception exception, string correlationId, string uri, string circuitBreakerStatus)
823829
{
824830
TrackMetric(Events.SearchOnRetry, 1, properties => {
825831
properties.Add(SearchName, searchName);
826832
properties.Add(SearchException, exception?.ToString() ?? string.Empty);
833+
properties.Add(SearchPollyCorrelationId, correlationId);
834+
properties.Add(SearchUrl, uri);
835+
properties.Add(SearchCircuitBreakerStatus, circuitBreakerStatus);
827836
});
828837
}
829838
/// <summary>

tests/NuGetGallery.Facts/Services/TelemetryServiceFacts.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,15 +259,15 @@ public static IEnumerable<object[]> TrackMetricNames_Data
259259
};
260260

261261
yield return new object[] { "SearchCircuitBreakerOnBreak",
262-
(TrackAction)(s => s.TrackMetricForSearchCircuitBreakerOnBreak("SomeName", exception: null, responseMessage: null))
262+
(TrackAction)(s => s.TrackMetricForSearchCircuitBreakerOnBreak("SomeName", exception: null, responseMessage: null, correlationId: string.Empty, uri: string.Empty))
263263
};
264264

265265
yield return new object[] { "SearchCircuitBreakerOnReset",
266-
(TrackAction)(s => s.TrackMetricForSearchCircuitBreakerOnReset("SomeName"))
266+
(TrackAction)(s => s.TrackMetricForSearchCircuitBreakerOnReset("SomeName", correlationId: string.Empty, uri: string.Empty))
267267
};
268268

269269
yield return new object[] { "SearchOnRetry",
270-
(TrackAction)(s => s.TrackMetricForSearchOnRetry("SomeName", exception: null))
270+
(TrackAction)(s => s.TrackMetricForSearchOnRetry("SomeName", exception: null, correlationId: string.Empty, uri: string.Empty, circuitBreakerStatus: string.Empty))
271271
};
272272
}
273273
}

0 commit comments

Comments
 (0)