diff --git a/src/Elastic.Clients.Elasticsearch.Serverless/Core/ElasticsearchClientProductRegistration.cs b/src/Elastic.Clients.Elasticsearch.Serverless/Core/ElasticsearchClientProductRegistration.cs index 1427878606..cfe03c5161 100644 --- a/src/Elastic.Clients.Elasticsearch.Serverless/Core/ElasticsearchClientProductRegistration.cs +++ b/src/Elastic.Clients.Elasticsearch.Serverless/Core/ElasticsearchClientProductRegistration.cs @@ -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) { diff --git a/src/Elastic.Clients.Elasticsearch.Serverless/Elastic.Clients.Elasticsearch.Serverless.csproj b/src/Elastic.Clients.Elasticsearch.Serverless/Elastic.Clients.Elasticsearch.Serverless.csproj index b35a3290ea..3f46babf24 100644 --- a/src/Elastic.Clients.Elasticsearch.Serverless/Elastic.Clients.Elasticsearch.Serverless.csproj +++ b/src/Elastic.Clients.Elasticsearch.Serverless/Elastic.Clients.Elasticsearch.Serverless.csproj @@ -21,7 +21,7 @@ annotations - + diff --git a/src/Elastic.Clients.Elasticsearch/Elastic.Clients.Elasticsearch.csproj b/src/Elastic.Clients.Elasticsearch/Elastic.Clients.Elasticsearch.csproj index 71cdf552e8..c4e6648318 100644 --- a/src/Elastic.Clients.Elasticsearch/Elastic.Clients.Elasticsearch.csproj +++ b/src/Elastic.Clients.Elasticsearch/Elastic.Clients.Elasticsearch.csproj @@ -21,7 +21,7 @@ annotations - + diff --git a/src/Elastic.Clients.Elasticsearch/_Shared/Api/Esql/EsqlQueryRequest.cs b/src/Elastic.Clients.Elasticsearch/_Shared/Api/Esql/EsqlQueryRequest.cs index f4b002621f..981a599fcc 100644 --- a/src/Elastic.Clients.Elasticsearch/_Shared/Api/Esql/EsqlQueryRequest.cs +++ b/src/Elastic.Clients.Elasticsearch/_Shared/Api/Esql/EsqlQueryRequest.cs @@ -17,7 +17,7 @@ namespace Elastic.Clients.Elasticsearch.Esql; internal sealed class EsqlResponseBuilder : TypedResponseBuilder { - protected override EsqlQueryResponse? Build(ApiCallDetails apiCallDetails, RequestData requestData, + protected override EsqlQueryResponse? Build(ApiCallDetails apiCallDetails, BoundConfiguration boundConfiguration, Stream responseStream, string contentType, long contentLength) { @@ -38,7 +38,7 @@ static byte[] BytesFromStream(Stream stream) } } - protected override async Task BuildAsync(ApiCallDetails apiCallDetails, RequestData requestData, + protected override async Task BuildAsync(ApiCallDetails apiCallDetails, BoundConfiguration boundConfiguration, Stream responseStream, string contentType, long contentLength, CancellationToken cancellationToken = default) { diff --git a/src/Elastic.Clients.Elasticsearch/_Shared/Client/ElasticsearchClient.cs b/src/Elastic.Clients.Elasticsearch/_Shared/Client/ElasticsearchClient.cs index 1e61176db5..faee0c33fb 100644 --- a/src/Elastic.Clients.Elasticsearch/_Shared/Client/ElasticsearchClient.cs +++ b/src/Elastic.Clients.Elasticsearch/_Shared/Client/ElasticsearchClient.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Text.Json; @@ -165,11 +166,11 @@ private ValueTask DoRequestCoreAsync SendRequest() { var (endpointPath, resolvedRouteValues, postData) = PrepareRequest(request); - var openTelemetryData = PrepareOpenTelemetryData(request, resolvedRouteValues); + var openTelemetryDataMutator = GetOpenTelemetryDataMutator(request, resolvedRouteValues); return isAsync - ? new ValueTask(_transport.RequestAsync(endpointPath, postData, in openTelemetryData, request.RequestConfig, cancellationToken)) - : new ValueTask(_transport.Request(endpointPath, postData, in openTelemetryData, request.RequestConfig)); + ? new ValueTask(_transport.RequestAsync(endpointPath, postData, openTelemetryDataMutator, request.RequestConfig, cancellationToken)) + : new ValueTask(_transport.Request(endpointPath, postData, openTelemetryDataMutator, request.RequestConfig)); } async ValueTask SendRequestWithProductCheck() @@ -211,19 +212,19 @@ async ValueTask SendRequestWithProductCheckCore() // Send request var (endpointPath, resolvedRouteValues, postData) = PrepareRequest(request); - var openTelemetryData = PrepareOpenTelemetryData(request, resolvedRouteValues); + var openTelemetryDataMutator = GetOpenTelemetryDataMutator(request, resolvedRouteValues); TResponse response; if (isAsync) { response = await _transport - .RequestAsync(endpointPath, postData, in openTelemetryData, requestConfig, cancellationToken) + .RequestAsync(endpointPath, postData, openTelemetryDataMutator, requestConfig, cancellationToken) .ConfigureAwait(false); } else { - response = _transport.Request(endpointPath, postData, in openTelemetryData, requestConfig); + response = _transport.Request(endpointPath, postData, openTelemetryDataMutator, requestConfig); } // Evaluate product check result @@ -252,39 +253,41 @@ async ValueTask SendRequestWithProductCheckCore() } } - private static OpenTelemetryData PrepareOpenTelemetryData(TRequest request, Dictionary resolvedRouteValues) + private static Action? GetOpenTelemetryDataMutator(TRequest request, Dictionary? resolvedRouteValues) where TRequest : Request 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 + 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? resolvedRouteValues, PostData data) PrepareRequest(TRequest request) diff --git a/src/Playground/Playground.csproj b/src/Playground/Playground.csproj index 455e7a6ebd..d26d64adac 100644 --- a/src/Playground/Playground.csproj +++ b/src/Playground/Playground.csproj @@ -10,7 +10,7 @@ - +