Skip to content

Commit

Permalink
Update Elastic.Transport to 0.5.5 (#8421)
Browse files Browse the repository at this point in the history
  • Loading branch information
flobernd authored Nov 21, 2024
1 parent 3dd9edf commit b89de7a
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 54 deletions.
46 changes: 38 additions & 8 deletions docs/migration-guide.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -292,13 +292,43 @@ As a last resort, the low-level client `Elastic.Transport` can be used to create

[source,csharp]
----
public class MyRequestParameters : RequestParameters
{
public bool Pretty
{
get => Q<bool>("pretty");
init => Q("pretty", value);
}
}
// ...
var body = """
{
"name": "my-api-key",
"expiration": "1d",
"...": "..."
}
""";
var response = await client.Transport.RequestAsync<StringResponse>(HttpMethod.POST, "/_security/api_key", PostData.String(body));
{
"name": "my-api-key",
"expiration": "1d",
"...": "..."
}
""";
MyRequestParameters requestParameters = new()
{
Pretty = true
};
var pathAndQuery = requestParameters.CreatePathWithQueryStrings("/_security/api_key",
client.ElasticsearchClientSettings);
var endpointPath = new EndpointPath(Elastic.Transport.HttpMethod.POST, pathAndQuery);
// Or, if the path does not contain query parameters:
// new EndpointPath(Elastic.Transport.HttpMethod.POST, "my_path")
var response = await client.Transport
.RequestAsync<StringResponse>(
endpointPath,
PostData.String(body),
null,
null,
cancellationToken: default)
.ConfigureAwait(false);
----
9 changes: 5 additions & 4 deletions docs/usage/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ If you're new to {es}, make sure also to read {ref}/getting-started.html[Elastic

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

include::recommendations.asciidoc[]
include::aggregations.asciidoc[]
include::esql.asciidoc[]
include::examples.asciidoc[]
include::query.asciidoc[]
include::mappings.asciidoc[]
include::aggregations.asciidoc[]
include::esql.asciidoc[]
include::query.asciidoc[]
include::recommendations.asciidoc[]
include::transport.asciidoc[]
47 changes: 47 additions & 0 deletions docs/usage/transport.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[[transport]]
== Transport example

This page demonstrates how to use the low level transport to send requests.

[source,csharp]
----
public class MyRequestParameters : RequestParameters
{
public bool Pretty
{
get => Q<bool>("pretty");
init => Q("pretty", value);
}
}
// ...
var body = """
{
"name": "my-api-key",
"expiration": "1d",
"...": "..."
}
""";
MyRequestParameters requestParameters = new()
{
Pretty = true
};
var pathAndQuery = requestParameters.CreatePathWithQueryStrings("/_security/api_key",
client.ElasticsearchClientSettings);
var endpointPath = new EndpointPath(Elastic.Transport.HttpMethod.POST, pathAndQuery);
// Or, if the path does not contain query parameters:
// new EndpointPath(Elastic.Transport.HttpMethod.POST, "my_path")
var response = await client.Transport
.RequestAsync<StringResponse>(
endpointPath,
PostData.String(body),
null,
null,
cancellationToken: default)
.ConfigureAwait(false);
----
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public class ApiVersionMetaHeaderProducer : MetaHeaderProducer

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

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

public ApiVersionMetaHeaderProducer(VersionInfo version)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Elastic.Transport" Version="0.5.2" />
<PackageReference Include="Elastic.Transport" Version="0.5.5" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Tests" Key="$(ExposedPublicKey)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Elastic.Transport" Version="0.5.2" />
<PackageReference Include="Elastic.Transport" Version="0.5.5" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Tests" Key="$(ExposedPublicKey)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Elastic.Clients.Elasticsearch.Esql;

internal sealed class EsqlResponseBuilder : TypedResponseBuilder<EsqlQueryResponse>
{
protected override EsqlQueryResponse? Build(ApiCallDetails apiCallDetails, RequestData requestData,
protected override EsqlQueryResponse? Build(ApiCallDetails apiCallDetails, BoundConfiguration boundConfiguration,
Stream responseStream,
string contentType, long contentLength)
{
Expand All @@ -38,7 +38,7 @@ static byte[] BytesFromStream(Stream stream)
}
}

protected override async Task<EsqlQueryResponse?> BuildAsync(ApiCallDetails apiCallDetails, RequestData requestData,
protected override async Task<EsqlQueryResponse?> BuildAsync(ApiCallDetails apiCallDetails, BoundConfiguration boundConfiguration,
Stream responseStream,
string contentType, long contentLength, CancellationToken cancellationToken = default)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Json;
Expand Down Expand Up @@ -165,11 +166,11 @@ private ValueTask<TResponse> DoRequestCoreAsync<TRequest, TResponse, TRequestPar
ValueTask<TResponse> SendRequest()
{
var (endpointPath, resolvedRouteValues, postData) = PrepareRequest<TRequest, TRequestParameters>(request);
var openTelemetryData = PrepareOpenTelemetryData<TRequest, TRequestParameters>(request, resolvedRouteValues);
var openTelemetryDataMutator = GetOpenTelemetryDataMutator<TRequest, TRequestParameters>(request, resolvedRouteValues);

return isAsync
? new ValueTask<TResponse>(_transport.RequestAsync<TResponse>(endpointPath, postData, in openTelemetryData, request.RequestConfig, cancellationToken))
: new ValueTask<TResponse>(_transport.Request<TResponse>(endpointPath, postData, in openTelemetryData, request.RequestConfig));
? new ValueTask<TResponse>(_transport.RequestAsync<TResponse>(endpointPath, postData, openTelemetryDataMutator, request.RequestConfig, cancellationToken))
: new ValueTask<TResponse>(_transport.Request<TResponse>(endpointPath, postData, openTelemetryDataMutator, request.RequestConfig));
}

async ValueTask<TResponse> SendRequestWithProductCheck()
Expand Down Expand Up @@ -211,19 +212,19 @@ async ValueTask<TResponse> SendRequestWithProductCheckCore()
// Send request

var (endpointPath, resolvedRouteValues, postData) = PrepareRequest<TRequest, TRequestParameters>(request);
var openTelemetryData = PrepareOpenTelemetryData<TRequest, TRequestParameters>(request, resolvedRouteValues);
var openTelemetryDataMutator = GetOpenTelemetryDataMutator<TRequest, TRequestParameters>(request, resolvedRouteValues);

TResponse response;

if (isAsync)
{
response = await _transport
.RequestAsync<TResponse>(endpointPath, postData, in openTelemetryData, requestConfig, cancellationToken)
.RequestAsync<TResponse>(endpointPath, postData, openTelemetryDataMutator, requestConfig, cancellationToken)
.ConfigureAwait(false);
}
else
{
response = _transport.Request<TResponse>(endpointPath, postData, in openTelemetryData, requestConfig);
response = _transport.Request<TResponse>(endpointPath, postData, openTelemetryDataMutator, requestConfig);
}

// Evaluate product check result
Expand Down Expand Up @@ -252,39 +253,41 @@ async ValueTask<TResponse> SendRequestWithProductCheckCore()
}
}

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

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

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

// TODO: Optimisation: We should consider caching these, either for cases where resolvedRouteValues is null, or
// caching per combination of route values.
// We should benchmark this first to assess the impact for common workloads.
// The former is likely going to save some short-lived allocations, but only for requests to endpoints without required path parts.
// The latter may bloat the cache as some combinations of path parts may rarely re-occur.

activity.DisplayName = operationName;

activity.SetTag(OpenTelemetry.SemanticConventions.DbOperation, !string.IsNullOrEmpty(request.OperationName) ? request.OperationName : "unknown");
activity.SetTag($"{OpenTelemetrySpanAttributePrefix}schema_url", OpenTelemetrySchemaVersion);

if (resolvedRouteValues is null)
return;

if (resolvedRouteValues is not null)
{
foreach (var value in resolvedRouteValues)
{
if (!string.IsNullOrEmpty(value.Key) && !string.IsNullOrEmpty(value.Value))
attributes.Add($"{OpenTelemetrySpanAttributePrefix}path_parts.{value.Key}", value.Value);
activity.SetTag($"{OpenTelemetrySpanAttributePrefix}path_parts.{value.Key}", value.Value);
}
}

var openTelemetryData = new OpenTelemetryData { SpanName = operationName, SpanAttributes = attributes };
return openTelemetryData;
}

private (EndpointPath endpointPath, Dictionary<string, string>? resolvedRouteValues, PostData data) PrepareRequest<TRequest, TRequestParameters>(TRequest request)
Expand Down
2 changes: 1 addition & 1 deletion src/Playground/Playground.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Elastic.Transport" Version="0.5.2" />
<PackageReference Include="Elastic.Transport" Version="0.5.5" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
</ItemGroup>

Expand Down
6 changes: 3 additions & 3 deletions tests/Tests.Core/Client/FixedResponseClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static ElasticsearchClient Create(
object response,
int statusCode = 200,
Func<ElasticsearchClientSettings, ElasticsearchClientSettings> modifySettings = null,
string contentType = RequestData.DefaultContentType,
string contentType = BoundConfiguration.DefaultContentType,
Exception exception = null
)
{
Expand All @@ -29,7 +29,7 @@ public static ElasticsearchClientSettings CreateConnectionSettings(
object response,
int statusCode = 200,
Func<ElasticsearchClientSettings, ElasticsearchClientSettings> modifySettings = null,
string contentType = RequestData.DefaultContentType,
string contentType = BoundConfiguration.DefaultContentType,
Exception exception = null,
Serializer serializer = null
)
Expand All @@ -46,7 +46,7 @@ public static ElasticsearchClientSettings CreateConnectionSettings(
break;
default:
{
responseBytes = contentType == RequestData.DefaultContentType
responseBytes = contentType == BoundConfiguration.DefaultContentType
? serializer.SerializeToBytes(response,
TestClient.Default.ElasticsearchClientSettings.MemoryStreamFactory)
: Encoding.UTF8.GetBytes(response.ToString());
Expand Down
16 changes: 8 additions & 8 deletions tests/Tests/ClientConcepts/OpenTelemetry/OpenTelemetryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,34 +32,34 @@ public async Task BasicOpenTelemetryTest()

client.Ping();

VerifyActivity(oTelActivity, "ping");
VerifyActivity(oTelActivity, "ping", "HEAD");

await client.PingAsync();

VerifyActivity(oTelActivity, "ping");
VerifyActivity(oTelActivity, "ping", "HEAD");

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

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

static void VerifyActivity(Activity oTelActivity, string operation, string url = null)
static void VerifyActivity(Activity oTelActivity, string displayName, string operation, string url = null)
{
oTelActivity.Should().NotBeNull();

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

oTelActivity.DisplayName.Should().Be(operation);
oTelActivity.OperationName.Should().Be(operation);
oTelActivity.DisplayName.Should().Be(displayName);

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

switch (operation)
switch (displayName)
{
case "search":
oTelActivity.Tags.Should().Contain(n => n.Key == "db.elasticsearch.path_parts.index" && n.Value == "test");
Expand Down

0 comments on commit b89de7a

Please sign in to comment.