Skip to content

Commit c9bfc4d

Browse files
committed
Improve elasticsearch client exceptions default Message by trying to read the server error reason and making it part of the exception message
1 parent e78688e commit c9bfc4d

File tree

10 files changed

+88
-5
lines changed

10 files changed

+88
-5
lines changed

src/Elasticsearch.Net/Responses/ElasticsearchResponse.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,18 @@ namespace Elasticsearch.Net
88
/// <summary>
99
/// A response from elasticsearch including details about the request/response life cycle
1010
/// </summary>
11-
public class ElasticsearchResponseBase : IApiCallDetails, IElasticsearchResponse
11+
public abstract class ElasticsearchResponseBase : IApiCallDetails, IElasticsearchResponse
1212
{
1313
public IApiCallDetails ApiCall { get; set; }
14+
15+
bool IElasticsearchResponse.TryGetServerErrorReason(out string reason) => this.TryGetServerErrorReason(out reason);
16+
17+
protected virtual bool TryGetServerErrorReason(out string reason)
18+
{
19+
reason = null;
20+
return false;
21+
}
22+
1423
//ignored
1524
List<Audit> IApiCallDetails.AuditTrail { get; set; }
1625

@@ -26,12 +35,15 @@ public class ElasticsearchResponseBase : IApiCallDetails, IElasticsearchResponse
2635

2736
/// <summary>The raw byte request message body, only set when DisableDirectStreaming() is set on Connection configuration</summary>
2837
public byte[] RequestBodyInBytes => this.ApiCall.RequestBodyInBytes;
38+
2939
/// <summary>The raw byte response message body, only set when DisableDirectStreaming() is set on Connection configuration</summary>
3040
public byte[] ResponseBodyInBytes => this.ApiCall.ResponseBodyInBytes;
3141

3242
public string DebugInformation => this.ApiCall.DebugInformation;
3343

3444
public override string ToString() => this.ApiCall.ToString();
45+
46+
3547
}
3648

3749
/// <summary>

src/Elasticsearch.Net/Responses/IElasticsearchResponse.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ public interface IElasticsearchResponse
1010
/// Sets and returns the <see cref="IApiCallDetails"/> diagnostic information
1111
/// </summary>
1212
IApiCallDetails ApiCall { get; set; }
13+
14+
bool TryGetServerErrorReason(out string reason);
1315
}
1416
}

src/Elasticsearch.Net/Responses/Special/BytesResponse.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,13 @@ public bool TryGetServerError(out ServerError serverError)
1616
serverError = ServerError.Create(stream);
1717
return true;
1818
}
19+
20+
protected override bool TryGetServerErrorReason(out string reason)
21+
{
22+
reason = null;
23+
if (!this.TryGetServerError(out var serverError)) return false;
24+
reason = serverError?.Error?.Reason;
25+
return !reason.IsNullOrEmpty();
26+
}
1927
}
2028
}

src/Elasticsearch.Net/Responses/Special/StringResponse.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,13 @@ public bool TryGetServerError(out ServerError serverError)
1616
serverError = ServerError.Create(stream);
1717
return true;
1818
}
19+
20+
protected override bool TryGetServerErrorReason(out string reason)
21+
{
22+
reason = null;
23+
if (!this.TryGetServerError(out var serverError)) return false;
24+
reason = serverError?.Error?.Reason;
25+
return !reason.IsNullOrEmpty();
26+
}
1927
}
2028
}

src/Elasticsearch.Net/Responses/Special/VoidResponse.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ namespace Elasticsearch.Net
55
public class VoidResponse : ElasticsearchResponse<VoidResponse.VoidBody>
66
{
77
public class VoidBody { }
8+
89
}
910
}

src/Elasticsearch.Net/Transport/Pipeline/IRequestPipeline.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ void BadResponse<TResponse>(ref TResponse response, IApiCallDetails callDetails,
5353

5454
void AuditCancellationRequested();
5555

56-
ElasticsearchClientException CreateClientException(IApiCallDetails response, RequestData data, List<PipelineException> seenExceptions);
56+
ElasticsearchClientException CreateClientException<TResponse>(TResponse response, RequestData data, List<PipelineException> seenExceptions)
57+
where TResponse : class, IElasticsearchResponse, new();
5758
}
5859
}

src/Elasticsearch.Net/Transport/Pipeline/RequestPipeline.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,12 +482,16 @@ public void BadResponse<TResponse>(ref TResponse response, IApiCallDetails callD
482482
response.ApiCall.AuditTrail = this.AuditTrail;
483483
}
484484

485-
public ElasticsearchClientException CreateClientException(IApiCallDetails callDetails, RequestData data, List<PipelineException> pipelineExceptions)
485+
public ElasticsearchClientException CreateClientException<TResponse>(TResponse response, RequestData data, List<PipelineException> pipelineExceptions)
486+
where TResponse : class, IElasticsearchResponse, new()
486487
{
488+
var callDetails = response.ApiCall;
487489
if (callDetails.Success) return null;
488490
var innerException = pipelineExceptions.HasAny() ? new AggregateException(pipelineExceptions) : callDetails?.OriginalException;
489491

490492
var exceptionMessage = innerException?.Message ?? $"Request failed to execute";
493+
if (response.TryGetServerErrorReason(out var reason))
494+
exceptionMessage += $". Error: {reason}";
491495

492496
var pipelineFailure = data.OnFailurePipelineFailure;
493497
if (pipelineExceptions.HasAny())

src/Elasticsearch.Net/Transport/Transport.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,8 @@ private TResponse FinalizeResponse<TResponse>(RequestData requestData, IRequestP
171171
pipeline.ThrowNoNodesAttempted(requestData, seenExceptions);
172172

173173
var callDetails = GetMostRecentCallDetails(response, seenExceptions);
174-
var clientException = pipeline.CreateClientException(callDetails, requestData, seenExceptions);
174+
var clientException = pipeline.CreateClientException(response, requestData, seenExceptions);
175175

176-
//if (response?.ApiCall == null || !response.ApiCall.Success)
177176
if (response?.ApiCall == null)
178177
pipeline.BadResponse(ref response, callDetails, requestData, clientException);
179178

src/Nest/CommonAbstractions/Response/ResponseBase.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ public abstract class ResponseBase : IResponse
5555
[JsonIgnore]
5656
IApiCallDetails IElasticsearchResponse.ApiCall { get => _originalApiCall; set => _originalApiCall = value; }
5757

58+
bool IElasticsearchResponse.TryGetServerErrorReason(out string reason)
59+
{
60+
reason = this.ServerError?.Error?.Reason;
61+
return !reason.IsNullOrEmpty();
62+
}
63+
5864
public ServerError ServerError
5965
{
6066
get
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Linq;
3+
using Elasticsearch.Net;
4+
using FluentAssertions;
5+
using Nest;
6+
using Tests.Framework;
7+
using Tests.Framework.ManagedElasticsearch.Clusters;
8+
using Tests.Framework.MockData;
9+
using Xunit;
10+
11+
namespace Tests.Reproduce
12+
{
13+
public class GithubIssue2985 : IClusterFixture<WritableCluster>
14+
{
15+
private readonly WritableCluster _cluster;
16+
17+
public GithubIssue2985(WritableCluster cluster) => _cluster = cluster;
18+
19+
protected static string RandomString() => Guid.NewGuid().ToString("N").Substring(0, 8);
20+
21+
[I]
22+
public void CanReadSingleOrMultipleCommonGramsCommonWordsItem()
23+
{
24+
var client = _cluster.Client;
25+
var index = $"gh2985-{RandomString()}";
26+
var response = client.CreateIndex(index, i=> i
27+
.Settings(s=>s
28+
.Analysis(a=>a
29+
.Analyzers(an=>an
30+
.Custom("custom", c=>c.Filters("ascii_folding").Tokenizer("standard"))
31+
)
32+
)
33+
)
34+
);
35+
response.OriginalException.Should().NotBeNull().And.BeOfType<ElasticsearchClientException>();
36+
response.OriginalException.Message.Should()
37+
.Be("Request failed to execute. Error: Custom Analyzer [custom] failed to find filter under name [ascii_folding]");
38+
39+
client.DeleteIndex(index);
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)