Skip to content

Commit 55880b4

Browse files
authored
Log the Azure search request-id to help future debugging (#10419)
Help debug NuGet/Engineering#5075
1 parent 18baffd commit 55880b4

8 files changed

Lines changed: 67 additions & 29 deletions

File tree

src/NuGet.Services.AzureSearch/AzureSearchTelemetryService.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -31,7 +31,7 @@ public IDisposable TrackVersionListsUpdated(int versionListCount, int workerCoun
3131
});
3232
}
3333

34-
public void TrackIndexPushSuccess(string indexName, int documentCount, TimeSpan elapsed)
34+
public void TrackIndexPushSuccess(string indexName, int documentCount, TimeSpan elapsed, string requestId)
3535
{
3636
_telemetryClient.TrackMetric(
3737
Prefix + "IndexPushSuccessSeconds",
@@ -40,6 +40,7 @@ public void TrackIndexPushSuccess(string indexName, int documentCount, TimeSpan
4040
{
4141
{ "IndexName", indexName },
4242
{ "DocumentCount", documentCount.ToString() },
43+
{ "RequestId", requestId ?? "(missing)" },
4344
});
4445
}
4546

src/NuGet.Services.AzureSearch/BatchPusher.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -180,11 +180,17 @@ private async Task IndexAsync(
180180
{
181181
var batchInput = new IndexDocumentsBatch<KeyedDocument>();
182182
batchInput.Actions.AddRange(batch);
183-
var batchResults = await indexClient.IndexAsync(batchInput);
183+
Response<IndexDocumentsResult> batchResultsResponse = await indexClient.IndexAsync(batchInput);
184+
string requestId = batchResultsResponse
185+
.GetRawResponse()?
186+
.Headers // See https://learn.microsoft.com/en-us/rest/api/searchservice/common-http-request-and-response-headers-used-in-azure-search
187+
.FirstOrDefault(x => StringComparer.OrdinalIgnoreCase.Equals(x.Name, "request-id"))
188+
.Value;
189+
IndexDocumentsResult batchResults = batchResultsResponse.Value;
184190
indexingResults = batchResults.Results;
185191

186192
stopwatch.Stop();
187-
_telemetryService.TrackIndexPushSuccess(indexClient.IndexName, batch.Count, stopwatch.Elapsed);
193+
_telemetryService.TrackIndexPushSuccess(indexClient.IndexName, batch.Count, stopwatch.Elapsed, requestId);
188194
}
189195
catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.RequestEntityTooLarge && batch.Count > 1)
190196
{

src/NuGet.Services.AzureSearch/IAzureSearchTelemetryService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -15,7 +15,7 @@ public interface IAzureSearchTelemetryService
1515
void TrackGetOwnersForPackageId(int ownerCount, TimeSpan elapsed);
1616
void TrackIndexPushFailure(string indexName, int documentCount, TimeSpan elapsed);
1717
void TrackIndexPushSplit(string indexName, int documentCount);
18-
void TrackIndexPushSuccess(string indexName, int documentCount, TimeSpan elapsed);
18+
void TrackIndexPushSuccess(string indexName, int documentCount, TimeSpan elapsed, string requestId);
1919
void TrackUpdateOwnersCompleted(JobOutcome outcome, TimeSpan elapsed);
2020
void TrackOwnerSetComparison(int oldCount, int newCount, int changeCount, TimeSpan elapsed);
2121
void TrackReadLatestIndexedOwners(int packageIdCount, TimeSpan elapsed);
@@ -59,4 +59,4 @@ void TrackDownloadCountDecrease(
5959
void TrackAuxiliaryFilesStringCache(int stringCount, long charCount, int requestCount, int hitCount);
6060
void TrackUpdateDownloadsCompleted(JobOutcome outcome, TimeSpan elapsed);
6161
}
62-
}
62+
}

src/NuGet.Services.AzureSearch/Wrappers/ISearchClientWrapper.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Threading.Tasks;
5+
using Azure;
56
using Azure.Search.Documents;
67
using Azure.Search.Documents.Models;
78

@@ -10,7 +11,7 @@ namespace NuGet.Services.AzureSearch.Wrappers
1011
public interface ISearchClientWrapper
1112
{
1213
string IndexName { get; }
13-
Task<IndexDocumentsResult> IndexAsync<T>(IndexDocumentsBatch<T> batch) where T : class;
14+
Task<Response<IndexDocumentsResult>> IndexAsync<T>(IndexDocumentsBatch<T> batch) where T : class;
1415
Task<T> GetOrNullAsync<T>(string key) where T : class;
1516
Task<SingleSearchResultPage<T>> SearchAsync<T>(string searchText, SearchOptions options) where T : class;
1617
Task<long> CountAsync();

src/NuGet.Services.AzureSearch/Wrappers/SearchClientWrapper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -23,7 +23,7 @@ public SearchClientWrapper(SearchClient inner)
2323

2424
public string IndexName => _inner.IndexName;
2525

26-
public async Task<IndexDocumentsResult> IndexAsync<T>(IndexDocumentsBatch<T> batch) where T : class
26+
public async Task<Response<IndexDocumentsResult>> IndexAsync<T>(IndexDocumentsBatch<T> batch) where T : class
2727
{
2828
return await _inner.IndexDocumentsAsync(batch);
2929
}

tests/NuGet.Services.AzureSearch.Tests/Auxiliary2AzureSearch/Integration/PopularityTransferIntegrationTests.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,12 @@ public PopularityTransferIntegrationTests(ITestOutputHelper output)
126126
{
127127
_indexedBatch = batch;
128128
})
129-
.ReturnsAsync(SearchModelFactory.IndexDocumentsResult(Enumerable.Empty<IndexingResult>()));
129+
.ReturnsAsync(() =>
130+
{
131+
var response = new Mock<Response<IndexDocumentsResult>>();
132+
response.Setup(x => x.Value).Returns(() => SearchModelFactory.IndexDocumentsResult([]));
133+
return response.Object;
134+
});
130135

131136
var batchPusher = new BatchPusher(
132137
_searchClient.Object,

tests/NuGet.Services.AzureSearch.Tests/BatchPusherFacts.cs

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -7,6 +7,7 @@
77
using System.Net;
88
using System.Threading.Tasks;
99
using Azure;
10+
using Azure.Core;
1011
using Azure.Search.Documents.Models;
1112
using Microsoft.Extensions.Options;
1213
using Moq;
@@ -246,7 +247,10 @@ public async Task SplitsBatchesInHalfWhenTooLarge()
246247
throw new RequestFailedException((int)HttpStatusCode.RequestEntityTooLarge, "Too big!");
247248
}
248249

249-
return Task.FromResult(SearchModelFactory.IndexDocumentsResult(new List<IndexingResult>()));
250+
var response = new Mock<Response<IndexDocumentsResult>>();
251+
response.Setup(x => x.Value).Returns(() => SearchModelFactory.IndexDocumentsResult([]));
252+
253+
return Task.FromResult(response.Object);
250254
});
251255

252256
var result = await _target.TryFinishAsync();
@@ -325,16 +329,22 @@ public async Task LogsUpALimitedNumberOfFailedResults()
325329
_target.EnqueueIndexActions(IdA, _indexActions);
326330
_searchIndexWrapper
327331
.Setup(x => x.IndexAsync(It.IsAny<IndexDocumentsBatch<KeyedDocument>>()))
328-
.ReturnsAsync(() => SearchModelFactory.IndexDocumentsResult(new List<IndexingResult>
332+
.ReturnsAsync(() =>
329333
{
330-
SearchModelFactory.IndexingResult(key: "A-0", errorMessage: "A-0 message", succeeded: false, status: 0),
331-
SearchModelFactory.IndexingResult(key: "A-1", errorMessage: "A-1 message", succeeded: false, status: 1),
332-
SearchModelFactory.IndexingResult(key: "A-2", errorMessage: "A-2 message", succeeded: true, status: 2),
333-
SearchModelFactory.IndexingResult(key: "A-3", errorMessage: "A-3 message", succeeded: false, status: 3),
334-
SearchModelFactory.IndexingResult(key: "A-4", errorMessage: "A-4 message", succeeded: false, status: 4),
335-
SearchModelFactory.IndexingResult(key: "A-5", errorMessage: "A-5 message", succeeded: false, status: 5),
336-
SearchModelFactory.IndexingResult(key: "A-6", errorMessage: "A-6 message", succeeded: false, status: 6),
337-
}));
334+
var response = new Mock<Response<IndexDocumentsResult>>();
335+
response.Setup(x => x.Value).Returns(() => SearchModelFactory.IndexDocumentsResult(new List<IndexingResult>
336+
{
337+
SearchModelFactory.IndexingResult(key: "A-0", errorMessage: "A-0 message", succeeded: false, status: 0),
338+
SearchModelFactory.IndexingResult(key: "A-1", errorMessage: "A-1 message", succeeded: false, status: 1),
339+
SearchModelFactory.IndexingResult(key: "A-2", errorMessage: "A-2 message", succeeded: true, status: 2),
340+
SearchModelFactory.IndexingResult(key: "A-3", errorMessage: "A-3 message", succeeded: false, status: 3),
341+
SearchModelFactory.IndexingResult(key: "A-4", errorMessage: "A-4 message", succeeded: false, status: 4),
342+
SearchModelFactory.IndexingResult(key: "A-5", errorMessage: "A-5 message", succeeded: false, status: 5),
343+
SearchModelFactory.IndexingResult(key: "A-6", errorMessage: "A-6 message", succeeded: false, status: 6),
344+
}));
345+
346+
return response.Object;
347+
});
338348

339349
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
340350
() => _target.TryPushFullBatchesAsync());
@@ -682,11 +692,21 @@ public BaseFacts(ITestOutputHelper output)
682692

683693
_searchIndexWrapper
684694
.Setup(x => x.IndexAsync(It.IsAny<IndexDocumentsBatch<KeyedDocument>>()))
685-
.ReturnsAsync(() => SearchModelFactory.IndexDocumentsResult(new IndexingResult[0]))
695+
.ReturnsAsync(() =>
696+
{
697+
var response = new Mock<Response<IndexDocumentsResult>>();
698+
response.Setup(x => x.Value).Returns(() => SearchModelFactory.IndexDocumentsResult([]));
699+
return response.Object;
700+
})
686701
.Callback<IndexDocumentsBatch<KeyedDocument>>(b => _searchBatches.Add(b));
687702
_hijackIndexWrapper
688703
.Setup(x => x.IndexAsync(It.IsAny<IndexDocumentsBatch<KeyedDocument>>()))
689-
.ReturnsAsync(() => SearchModelFactory.IndexDocumentsResult(new IndexingResult[0]))
704+
.ReturnsAsync(() =>
705+
{
706+
var response = new Mock<Response<IndexDocumentsResult>>();
707+
response.Setup(x => x.Value).Returns(() => SearchModelFactory.IndexDocumentsResult([]));
708+
return response.Object;
709+
})
690710
.Callback<IndexDocumentsBatch<KeyedDocument>>(b => _hijackBatches.Add(b));
691711

692712
_config.AzureSearchBatchSize = 2;

tests/NuGet.Services.AzureSearch.Tests/Catalog2AzureSearch/Integration/InMemorySearchClient.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
55
using System.Collections.Concurrent;
66
using System.Collections.Generic;
77
using System.Threading.Tasks;
8+
using Azure;
89
using Azure.Search.Documents;
910
using Azure.Search.Documents.Models;
11+
using Moq;
1012
using NuGet.Services.AzureSearch.Wrappers;
1113

1214
namespace NuGet.Services.AzureSearch.Catalog2AzureSearch.Integration
@@ -40,7 +42,7 @@ public Task<T> GetOrNullAsync<T>(string key) where T : class
4042
throw new NotImplementedException();
4143
}
4244

43-
public Task<IndexDocumentsResult> IndexAsync<T>(IndexDocumentsBatch<T> batch) where T : class
45+
public Task<Response<IndexDocumentsResult>> IndexAsync<T>(IndexDocumentsBatch<T> batch) where T : class
4446
{
4547
if (typeof(T) != typeof(KeyedDocument))
4648
{
@@ -49,7 +51,10 @@ public Task<IndexDocumentsResult> IndexAsync<T>(IndexDocumentsBatch<T> batch) wh
4951

5052
Batches.Enqueue(batch as IndexDocumentsBatch<KeyedDocument>);
5153

52-
return Task.FromResult(SearchModelFactory.IndexDocumentsResult(new List<IndexingResult>()));
54+
var response = new Mock<Response<IndexDocumentsResult>>();
55+
response.Setup(x => x.Value).Returns(() => SearchModelFactory.IndexDocumentsResult([]));
56+
57+
return Task.FromResult(response.Object);
5358
}
5459

5560
public Task<SingleSearchResultPage<T>> SearchAsync<T>(string searchText, SearchOptions searchParameters) where T : class

0 commit comments

Comments
 (0)