Skip to content

Commit c9cb337

Browse files
committed
Update Elastic.Transport to 0.5.5 (#8421)
1 parent 21eb7c0 commit c9cb337

File tree

11 files changed

+136
-52
lines changed

11 files changed

+136
-52
lines changed

docs/migration-guide.asciidoc

+38-8
Original file line numberDiff line numberDiff line change
@@ -292,13 +292,43 @@ As a last resort, the low-level client `Elastic.Transport` can be used to create
292292

293293
[source,csharp]
294294
----
295+
public class MyRequestParameters : RequestParameters
296+
{
297+
public bool Pretty
298+
{
299+
get => Q<bool>("pretty");
300+
init => Q("pretty", value);
301+
}
302+
}
303+
304+
// ...
305+
295306
var body = """
296-
{
297-
"name": "my-api-key",
298-
"expiration": "1d",
299-
"...": "..."
300-
}
301-
""";
302-
303-
var response = await client.Transport.RequestAsync<StringResponse>(HttpMethod.POST, "/_security/api_key", PostData.String(body));
307+
{
308+
"name": "my-api-key",
309+
"expiration": "1d",
310+
"...": "..."
311+
}
312+
""";
313+
314+
MyRequestParameters requestParameters = new()
315+
{
316+
Pretty = true
317+
};
318+
319+
var pathAndQuery = requestParameters.CreatePathWithQueryStrings("/_security/api_key",
320+
client.ElasticsearchClientSettings);
321+
var endpointPath = new EndpointPath(Elastic.Transport.HttpMethod.POST, pathAndQuery);
322+
323+
// Or, if the path does not contain query parameters:
324+
// new EndpointPath(Elastic.Transport.HttpMethod.POST, "my_path")
325+
326+
var response = await client.Transport
327+
.RequestAsync<StringResponse>(
328+
endpointPath,
329+
PostData.String(body),
330+
null,
331+
null,
332+
cancellationToken: default)
333+
.ConfigureAwait(false);
304334
----

docs/usage/index.asciidoc

+6-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ If you're new to {es}, make sure also to read {ref}/getting-started.html[Elastic
1616

1717
NOTE: This is still a work in progress, more sections will be added in the near future.
1818

19-
include::recommendations.asciidoc[]
19+
include::aggregations.asciidoc[]
20+
include::esql.asciidoc[]
2021
include::examples.asciidoc[]
21-
include::esql.asciidoc[]
22+
include::mappings.asciidoc[]
23+
include::query.asciidoc[]
24+
include::recommendations.asciidoc[]
25+
include::transport.asciidoc[]

docs/usage/transport.asciidoc

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[[transport]]
2+
== Transport example
3+
4+
This page demonstrates how to use the low level transport to send requests.
5+
6+
[source,csharp]
7+
----
8+
public class MyRequestParameters : RequestParameters
9+
{
10+
public bool Pretty
11+
{
12+
get => Q<bool>("pretty");
13+
init => Q("pretty", value);
14+
}
15+
}
16+
17+
// ...
18+
19+
var body = """
20+
{
21+
"name": "my-api-key",
22+
"expiration": "1d",
23+
"...": "..."
24+
}
25+
""";
26+
27+
MyRequestParameters requestParameters = new()
28+
{
29+
Pretty = true
30+
};
31+
32+
var pathAndQuery = requestParameters.CreatePathWithQueryStrings("/_security/api_key",
33+
client.ElasticsearchClientSettings);
34+
var endpointPath = new EndpointPath(Elastic.Transport.HttpMethod.POST, pathAndQuery);
35+
36+
// Or, if the path does not contain query parameters:
37+
// new EndpointPath(Elastic.Transport.HttpMethod.POST, "my_path")
38+
39+
var response = await client.Transport
40+
.RequestAsync<StringResponse>(
41+
endpointPath,
42+
PostData.String(body),
43+
null,
44+
null,
45+
cancellationToken: default)
46+
.ConfigureAwait(false);
47+
----

src/Elastic.Clients.Elasticsearch.Serverless/Core/ElasticsearchClientProductRegistration.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public class ApiVersionMetaHeaderProducer : MetaHeaderProducer
7777

7878
public override string HeaderName => "Elastic-Api-Version";
7979

80-
public override string ProduceHeaderValue(RequestData requestData, bool isAsync) => _apiVersion;
80+
public override string ProduceHeaderValue(BoundConfiguration boundConfiguration, bool isAsync) => _apiVersion;
8181

8282
public ApiVersionMetaHeaderProducer(VersionInfo version)
8383
{

src/Elastic.Clients.Elasticsearch.Serverless/Elastic.Clients.Elasticsearch.Serverless.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<Nullable>annotations</Nullable>
2222
</PropertyGroup>
2323
<ItemGroup>
24-
<PackageReference Include="Elastic.Transport" Version="0.5.2" />
24+
<PackageReference Include="Elastic.Transport" Version="0.5.5" />
2525
</ItemGroup>
2626
<ItemGroup>
2727
<InternalsVisibleTo Include="Tests" Key="$(ExposedPublicKey)" />

src/Elastic.Clients.Elasticsearch/Elastic.Clients.Elasticsearch.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<Nullable>annotations</Nullable>
2222
</PropertyGroup>
2323
<ItemGroup>
24-
<PackageReference Include="Elastic.Transport" Version="0.5.2" />
24+
<PackageReference Include="Elastic.Transport" Version="0.5.5" />
2525
</ItemGroup>
2626
<ItemGroup>
2727
<InternalsVisibleTo Include="Tests" Key="$(ExposedPublicKey)" />

src/Elastic.Clients.Elasticsearch/_Shared/Api/Esql/EsqlQueryRequest.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace Elastic.Clients.Elasticsearch.Esql;
1717

1818
internal sealed class EsqlResponseBuilder : TypedResponseBuilder<EsqlQueryResponse>
1919
{
20-
protected override EsqlQueryResponse? Build(ApiCallDetails apiCallDetails, RequestData requestData,
20+
protected override EsqlQueryResponse? Build(ApiCallDetails apiCallDetails, BoundConfiguration boundConfiguration,
2121
Stream responseStream,
2222
string contentType, long contentLength)
2323
{
@@ -38,7 +38,7 @@ static byte[] BytesFromStream(Stream stream)
3838
}
3939
}
4040

41-
protected override async Task<EsqlQueryResponse?> BuildAsync(ApiCallDetails apiCallDetails, RequestData requestData,
41+
protected override async Task<EsqlQueryResponse?> BuildAsync(ApiCallDetails apiCallDetails, BoundConfiguration boundConfiguration,
4242
Stream responseStream,
4343
string contentType, long contentLength, CancellationToken cancellationToken = default)
4444
{

src/Elastic.Clients.Elasticsearch/_Shared/Client/ElasticsearchClient.cs

+28-25
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System;
66
using System.Collections.Generic;
7+
using System.Diagnostics;
78
using System.Linq;
89
using System.Runtime.CompilerServices;
910
using System.Text.Json;
@@ -165,11 +166,11 @@ private ValueTask<TResponse> DoRequestCoreAsync<TRequest, TResponse, TRequestPar
165166
ValueTask<TResponse> SendRequest()
166167
{
167168
var (endpointPath, resolvedRouteValues, postData) = PrepareRequest<TRequest, TRequestParameters>(request);
168-
var openTelemetryData = PrepareOpenTelemetryData<TRequest, TRequestParameters>(request, resolvedRouteValues);
169+
var openTelemetryDataMutator = GetOpenTelemetryDataMutator<TRequest, TRequestParameters>(request, resolvedRouteValues);
169170

170171
return isAsync
171-
? new ValueTask<TResponse>(_transport.RequestAsync<TResponse>(endpointPath, postData, in openTelemetryData, request.RequestConfig, cancellationToken))
172-
: new ValueTask<TResponse>(_transport.Request<TResponse>(endpointPath, postData, in openTelemetryData, request.RequestConfig));
172+
? new ValueTask<TResponse>(_transport.RequestAsync<TResponse>(endpointPath, postData, openTelemetryDataMutator, request.RequestConfig, cancellationToken))
173+
: new ValueTask<TResponse>(_transport.Request<TResponse>(endpointPath, postData, openTelemetryDataMutator, request.RequestConfig));
173174
}
174175

175176
async ValueTask<TResponse> SendRequestWithProductCheck()
@@ -211,19 +212,19 @@ async ValueTask<TResponse> SendRequestWithProductCheckCore()
211212
// Send request
212213

213214
var (endpointPath, resolvedRouteValues, postData) = PrepareRequest<TRequest, TRequestParameters>(request);
214-
var openTelemetryData = PrepareOpenTelemetryData<TRequest, TRequestParameters>(request, resolvedRouteValues);
215+
var openTelemetryDataMutator = GetOpenTelemetryDataMutator<TRequest, TRequestParameters>(request, resolvedRouteValues);
215216

216217
TResponse response;
217218

218219
if (isAsync)
219220
{
220221
response = await _transport
221-
.RequestAsync<TResponse>(endpointPath, postData, in openTelemetryData, requestConfig, cancellationToken)
222+
.RequestAsync<TResponse>(endpointPath, postData, openTelemetryDataMutator, requestConfig, cancellationToken)
222223
.ConfigureAwait(false);
223224
}
224225
else
225226
{
226-
response = _transport.Request<TResponse>(endpointPath, postData, in openTelemetryData, requestConfig);
227+
response = _transport.Request<TResponse>(endpointPath, postData, openTelemetryDataMutator, requestConfig);
227228
}
228229

229230
// Evaluate product check result
@@ -252,39 +253,41 @@ async ValueTask<TResponse> SendRequestWithProductCheckCore()
252253
}
253254
}
254255

255-
private static OpenTelemetryData PrepareOpenTelemetryData<TRequest, TRequestParameters>(TRequest request, Dictionary<string, string> resolvedRouteValues)
256+
private static Action<Activity>? GetOpenTelemetryDataMutator<TRequest, TRequestParameters>(TRequest request, Dictionary<string, string>? resolvedRouteValues)
256257
where TRequest : Request<TRequestParameters>
257258
where TRequestParameters : RequestParameters, new()
258259
{
259260
// If there are no subscribed listeners, we avoid some work and allocations
260261
if (!Elastic.Transport.Diagnostics.OpenTelemetry.ElasticTransportActivitySourceHasListeners)
261-
return default;
262+
return null;
262263

263-
// We fall back to a general operation name in cases where the derived request fails to override the property
264-
var operationName = !string.IsNullOrEmpty(request.OperationName) ? request.OperationName : request.HttpMethod.GetStringValue();
264+
return OpenTelemetryDataMutator;
265265

266-
// TODO: Optimisation: We should consider caching these, either for cases where resolvedRouteValues is null, or
267-
// caching per combination of route values.
268-
// We should benchmark this first to assess the impact for common workloads.
269-
// The former is likely going to save some short-lived allocations, but only for requests to endpoints without required path parts.
270-
// The latter may bloat the cache as some combinations of path parts may rarely re-occur.
271-
var attributes = new Dictionary<string, object>
266+
void OpenTelemetryDataMutator(Activity activity)
272267
{
273-
[OpenTelemetry.SemanticConventions.DbOperation] = !string.IsNullOrEmpty(request.OperationName) ? request.OperationName : "unknown",
274-
[$"{OpenTelemetrySpanAttributePrefix}schema_url"] = OpenTelemetrySchemaVersion
275-
};
268+
// We fall back to a general operation name in cases where the derived request fails to override the property
269+
var operationName = !string.IsNullOrEmpty(request.OperationName) ? request.OperationName : request.HttpMethod.GetStringValue();
270+
271+
// TODO: Optimisation: We should consider caching these, either for cases where resolvedRouteValues is null, or
272+
// caching per combination of route values.
273+
// We should benchmark this first to assess the impact for common workloads.
274+
// The former is likely going to save some short-lived allocations, but only for requests to endpoints without required path parts.
275+
// The latter may bloat the cache as some combinations of path parts may rarely re-occur.
276+
277+
activity.DisplayName = operationName;
278+
279+
activity.SetTag(OpenTelemetry.SemanticConventions.DbOperation, !string.IsNullOrEmpty(request.OperationName) ? request.OperationName : "unknown");
280+
activity.SetTag($"{OpenTelemetrySpanAttributePrefix}schema_url", OpenTelemetrySchemaVersion);
281+
282+
if (resolvedRouteValues is null)
283+
return;
276284

277-
if (resolvedRouteValues is not null)
278-
{
279285
foreach (var value in resolvedRouteValues)
280286
{
281287
if (!string.IsNullOrEmpty(value.Key) && !string.IsNullOrEmpty(value.Value))
282-
attributes.Add($"{OpenTelemetrySpanAttributePrefix}path_parts.{value.Key}", value.Value);
288+
activity.SetTag($"{OpenTelemetrySpanAttributePrefix}path_parts.{value.Key}", value.Value);
283289
}
284290
}
285-
286-
var openTelemetryData = new OpenTelemetryData { SpanName = operationName, SpanAttributes = attributes };
287-
return openTelemetryData;
288291
}
289292

290293
private (EndpointPath endpointPath, Dictionary<string, string>? resolvedRouteValues, PostData data) PrepareRequest<TRequest, TRequestParameters>(TRequest request)

src/Playground/Playground.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<ItemGroup>
1111
<PackageReference Include="Moq" Version="4.18.2" />
1212
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
13-
<PackageReference Include="Elastic.Transport" Version="0.5.2" />
13+
<PackageReference Include="Elastic.Transport" Version="0.5.5" />
1414
<PackageReference Include="System.Text.Json" Version="8.0.5" />
1515
</ItemGroup>
1616

tests/Tests.Core/Client/FixedResponseClient.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public static ElasticsearchClient Create(
1717
object response,
1818
int statusCode = 200,
1919
Func<ElasticsearchClientSettings, ElasticsearchClientSettings> modifySettings = null,
20-
string contentType = RequestData.DefaultContentType,
20+
string contentType = BoundConfiguration.DefaultContentType,
2121
Exception exception = null
2222
)
2323
{
@@ -29,7 +29,7 @@ public static ElasticsearchClientSettings CreateConnectionSettings(
2929
object response,
3030
int statusCode = 200,
3131
Func<ElasticsearchClientSettings, ElasticsearchClientSettings> modifySettings = null,
32-
string contentType = RequestData.DefaultContentType,
32+
string contentType = BoundConfiguration.DefaultContentType,
3333
Exception exception = null,
3434
Serializer serializer = null
3535
)
@@ -46,7 +46,7 @@ public static ElasticsearchClientSettings CreateConnectionSettings(
4646
break;
4747
default:
4848
{
49-
responseBytes = contentType == RequestData.DefaultContentType
49+
responseBytes = contentType == BoundConfiguration.DefaultContentType
5050
? serializer.SerializeToBytes(response,
5151
TestClient.Default.ElasticsearchClientSettings.MemoryStreamFactory)
5252
: Encoding.UTF8.GetBytes(response.ToString());

tests/Tests/ClientConcepts/OpenTelemetry/OpenTelemetryTests.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -32,34 +32,34 @@ public async Task BasicOpenTelemetryTest()
3232

3333
client.Ping();
3434

35-
VerifyActivity(oTelActivity, "ping");
35+
VerifyActivity(oTelActivity, "ping", "HEAD");
3636

3737
await client.PingAsync();
3838

39-
VerifyActivity(oTelActivity, "ping");
39+
VerifyActivity(oTelActivity, "ping", "HEAD");
4040

4141
await client.SearchAsync<Project>(s => s.Index("test").Query(q => q.MatchAll(m => { })));
4242

43-
VerifyActivity(oTelActivity, "search", "http://localhost:9200/test/_search?pretty=true&error_trace=true");
43+
VerifyActivity(oTelActivity, "search", "POST", "http://localhost:9200/test/_search?pretty=true&error_trace=true");
4444

45-
static void VerifyActivity(Activity oTelActivity, string operation, string url = null)
45+
static void VerifyActivity(Activity oTelActivity, string displayName, string operation, string url = null)
4646
{
4747
oTelActivity.Should().NotBeNull();
4848

4949
oTelActivity.Kind.Should().Be(ActivityKind.Client);
5050

51-
oTelActivity.DisplayName.Should().Be(operation);
5251
oTelActivity.OperationName.Should().Be(operation);
52+
oTelActivity.DisplayName.Should().Be(displayName);
5353

5454
oTelActivity.Tags.Should().Contain(n => n.Key == "elastic.transport.product.name" && n.Value == "elasticsearch-net");
5555
oTelActivity.Tags.Should().Contain(n => n.Key == "db.system" && n.Value == "elasticsearch");
56-
oTelActivity.Tags.Should().Contain(n => n.Key == "db.operation" && n.Value == operation);
56+
oTelActivity.Tags.Should().Contain(n => n.Key == "db.operation" && n.Value == displayName);
5757
oTelActivity.Tags.Should().Contain(n => n.Key == "db.user" && n.Value == "elastic");
5858
oTelActivity.Tags.Should().Contain(n => n.Key == "url.full" && n.Value == (url ?? "http://localhost:9200/?pretty=true&error_trace=true"));
5959
oTelActivity.Tags.Should().Contain(n => n.Key == "server.address" && n.Value == "localhost");
60-
oTelActivity.Tags.Should().Contain(n => n.Key == "http.request.method" && n.Value == (operation == "ping" ? "HEAD" : "POST"));
60+
oTelActivity.Tags.Should().Contain(n => n.Key == "http.request.method" && n.Value == (displayName == "ping" ? "HEAD" : "POST"));
6161

62-
switch (operation)
62+
switch (displayName)
6363
{
6464
case "search":
6565
oTelActivity.Tags.Should().Contain(n => n.Key == "db.elasticsearch.path_parts.index" && n.Value == "test");

0 commit comments

Comments
 (0)