From 2f411bca4a8931d40a646dea1ff060f649c9b7b3 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Fri, 22 Mar 2024 17:00:45 -0400 Subject: [PATCH 1/2] feat: Expose public getter if the client is compatible with DirectPath --- .../InstantiatingGrpcChannelProvider.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java index bf8ffc81da..0c10b6a7a0 100644 --- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java +++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java @@ -370,10 +370,7 @@ private ManagedChannel createSingleChannel() throws IOException { // Check DirectPath traffic. boolean useDirectPathXds = false; - if (isDirectPathEnabled() - && isCredentialDirectPathCompatible() - && isOnComputeEngine() - && canUseDirectPathWithUniverseDomain()) { + if (isCompatibleForDirectPath()) { CallCredentials callCreds = MoreCallCredentials.from(credentials); ChannelCredentials channelCreds = GoogleDefaultChannelCredentials.newBuilder().callCredentials(callCreds).build(); @@ -446,6 +443,21 @@ && canUseDirectPathWithUniverseDomain()) { return managedChannel; } + /** + * DirectPath must be enabled via the settings and a few other configurations/settings + * must also be valid for the request to go through DirectPath (valid credentials, + * running on Compute, and routed through Google Servers). + * + * @return if DirectPath is enabled for the client and is compatible to be used + * with DirectPath + */ + public boolean isCompatibleForDirectPath() { + return isDirectPathEnabled() + && isCredentialDirectPathCompatible() + && isOnComputeEngine() + && canUseDirectPathWithUniverseDomain(); + } + /** The endpoint to be used for the channel. */ @Override public String getEndpoint() { From c601338a24d3b3fc3aef042d8770b358cf01bd8e Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Mon, 25 Mar 2024 16:59:03 -0400 Subject: [PATCH 2/2] feat: Retrieve DirectPath attributes from TransportChannel --- .../api/gax/grpc/GrpcTransportChannel.java | 8 +++- .../InstantiatingGrpcChannelProvider.java | 28 +++++++------ .../httpjson/HttpJsonTransportChannel.java | 6 ++- .../InstantiatingHttpJsonChannelProvider.java | 9 ++++- .../gax/httpjson/HttpJsonCallContextTest.java | 3 +- gax-java/gax/clirr-ignored-differences.xml | 10 +++++ .../com/google/api/gax/rpc/ClientContext.java | 10 ++++- .../google/api/gax/rpc/TransportChannel.java | 3 ++ .../api/gax/tracing/ApiTracerFactory.java | 35 +++++++++++++++++ .../api/gax/tracing/MetricsTracerFactory.java | 39 ++++++++++++++++++- .../gax/rpc/testing/FakeTransportChannel.java | 6 +++ 11 files changed, 137 insertions(+), 20 deletions(-) diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcTransportChannel.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcTransportChannel.java index 9e63bb2a63..7746a0db70 100644 --- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcTransportChannel.java +++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcTransportChannel.java @@ -35,6 +35,8 @@ import com.google.auto.value.AutoValue; import io.grpc.Channel; import io.grpc.ManagedChannel; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeUnit; /** Implementation of TransportChannel based on gRPC. */ @@ -100,17 +102,19 @@ public void close() { } public static Builder newBuilder() { - return new AutoValue_GrpcTransportChannel.Builder(); + return new AutoValue_GrpcTransportChannel.Builder().setConfigurations(new HashMap<>()); } public static GrpcTransportChannel create(ManagedChannel channel) { - return newBuilder().setManagedChannel(channel).build(); + return newBuilder().setManagedChannel(channel).setConfigurations(new HashMap<>()).build(); } @AutoValue.Builder public abstract static class Builder { public abstract Builder setManagedChannel(ManagedChannel value); + abstract Builder setConfigurations(Map configurations); + public abstract GrpcTransportChannel build(); } } diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java index 0c10b6a7a0..d6cb699129 100644 --- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java +++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java @@ -40,6 +40,7 @@ import com.google.api.gax.rpc.TransportChannelProvider; import com.google.api.gax.rpc.internal.EnvironmentProvider; import com.google.api.gax.rpc.mtls.MtlsProvider; +import com.google.api.gax.tracing.ApiTracerFactory; import com.google.auth.Credentials; import com.google.auth.oauth2.ComputeEngineCredentials; import com.google.common.annotations.VisibleForTesting; @@ -239,9 +240,15 @@ public TransportChannel getTransportChannel() throws IOException { } private TransportChannel createChannel() throws IOException { - return GrpcTransportChannel.create( - ChannelPool.create( - channelPoolSettings, InstantiatingGrpcChannelProvider.this::createSingleChannel)); + return GrpcTransportChannel.newBuilder() + .setManagedChannel( + ChannelPool.create( + channelPoolSettings, InstantiatingGrpcChannelProvider.this::createSingleChannel)) + .setConfigurations( + ImmutableMap.of( + ApiTracerFactory.MetricAttribute.DIRECTPATH_ENABLED.getAttribute(), + String.valueOf(isCompatibleForDirectPath()))) + .build(); } private boolean isDirectPathEnabled() { @@ -444,18 +451,17 @@ private ManagedChannel createSingleChannel() throws IOException { } /** - * DirectPath must be enabled via the settings and a few other configurations/settings - * must also be valid for the request to go through DirectPath (valid credentials, - * running on Compute, and routed through Google Servers). + * DirectPath must be enabled via the settings and a few other configurations/settings must also + * be valid for the request to go through DirectPath (valid credentials, running on Compute, and + * routed through Google Servers). * - * @return if DirectPath is enabled for the client and is compatible to be used - * with DirectPath + * @return if DirectPath is enabled for the client and is compatible to be used with DirectPath */ public boolean isCompatibleForDirectPath() { return isDirectPathEnabled() - && isCredentialDirectPathCompatible() - && isOnComputeEngine() - && canUseDirectPathWithUniverseDomain(); + && isCredentialDirectPathCompatible() + && isOnComputeEngine() + && canUseDirectPathWithUniverseDomain(); } /** The endpoint to be used for the channel. */ diff --git a/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonTransportChannel.java b/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonTransportChannel.java index 3551939645..22f3231dda 100644 --- a/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonTransportChannel.java +++ b/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonTransportChannel.java @@ -32,6 +32,8 @@ import com.google.api.core.InternalExtensionOnly; import com.google.api.gax.rpc.TransportChannel; import com.google.auto.value.AutoValue; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeUnit; /** Implementation of TransportChannel based on http/json. */ @@ -97,13 +99,15 @@ public static Builder newBuilder() { } public static HttpJsonTransportChannel create(ManagedHttpJsonChannel channel) { - return newBuilder().setManagedChannel(channel).build(); + return newBuilder().setManagedChannel(channel).setConfigurations(new HashMap<>()).build(); } @AutoValue.Builder public abstract static class Builder { public abstract Builder setManagedChannel(ManagedHttpJsonChannel value); + abstract Builder setConfigurations(Map configurations); + public abstract HttpJsonTransportChannel build(); } } diff --git a/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProvider.java b/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProvider.java index f92bdf299c..fa73785c29 100644 --- a/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProvider.java +++ b/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProvider.java @@ -37,8 +37,10 @@ import com.google.api.gax.rpc.HeaderProvider; import com.google.api.gax.rpc.TransportChannelProvider; import com.google.api.gax.rpc.mtls.MtlsProvider; +import com.google.api.gax.tracing.ApiTracerFactory; import com.google.auth.Credentials; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableMap; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.KeyStore; @@ -203,7 +205,12 @@ private HttpJsonTransportChannel createChannel() throws IOException, GeneralSecu } } - return HttpJsonTransportChannel.newBuilder().setManagedChannel(channel).build(); + return HttpJsonTransportChannel.newBuilder() + .setManagedChannel(channel) + .setConfigurations( + ImmutableMap.of( + ApiTracerFactory.MetricAttribute.DIRECTPATH_ENABLED.getAttribute(), "false")) + .build(); } /** The endpoint to be used for the channel. */ diff --git a/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpJsonCallContextTest.java b/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpJsonCallContextTest.java index fc872d3529..553275cdfa 100644 --- a/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpJsonCallContextTest.java +++ b/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpJsonCallContextTest.java @@ -86,8 +86,7 @@ public void testWithTransportChannel() { HttpJsonCallContext context = HttpJsonCallContext.createDefault() - .withTransportChannel( - HttpJsonTransportChannel.newBuilder().setManagedChannel(channel).build()); + .withTransportChannel(HttpJsonTransportChannel.create(channel)); Truth.assertThat(context.getChannel()).isSameInstanceAs(channel); } diff --git a/gax-java/gax/clirr-ignored-differences.xml b/gax-java/gax/clirr-ignored-differences.xml index c8e68444ff..435d8029c6 100644 --- a/gax-java/gax/clirr-ignored-differences.xml +++ b/gax-java/gax/clirr-ignored-differences.xml @@ -42,4 +42,14 @@ com/google/api/gax/rpc/ApiCallContext * validateUniverseDomain() + + 7012 + com/google/api/gax/rpc/TransportChannel + * getConfigurations() + + + 7012 + com/google/api/gax/tracing/ApiTracerFactory + * addAttributes(*) + diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index 409dbbada1..7991b445d5 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -154,6 +154,8 @@ public static ClientContext create(ClientSettings settings) throws IOException { * settings. */ public static ClientContext create(StubSettings settings) throws IOException { + Map clientInitializationOtelAttributes = new HashMap<>(); + ApiClock clock = settings.getClock(); ExecutorProvider backgroundExecutorProvider = settings.getBackgroundExecutorProvider(); @@ -224,6 +226,9 @@ public static ClientContext create(StubSettings settings) throws IOException { transportChannelProvider = transportChannelProvider.withEndpoint(endpoint); } TransportChannel transportChannel = transportChannelProvider.getTransportChannel(); + clientInitializationOtelAttributes.put( + "directpath_enabled", + String.valueOf(transportChannel.getConfigurations().get("directpath_enabled"))); ApiCallContext defaultCallContext = transportChannel.getEmptyCallContext().withTransportChannel(transportChannel); @@ -261,6 +266,9 @@ public static ClientContext create(StubSettings settings) throws IOException { backgroundResources.add(watchdog); } + ApiTracerFactory apiTracerFactory = settings.getTracerFactory(); + apiTracerFactory.addAttributes(clientInitializationOtelAttributes); + return newBuilder() .setBackgroundResources(backgroundResources.build()) .setExecutor(backgroundExecutor) @@ -276,7 +284,7 @@ public static ClientContext create(StubSettings settings) throws IOException { .setQuotaProjectId(settings.getQuotaProjectId()) .setStreamWatchdog(watchdog) .setStreamWatchdogCheckInterval(settings.getStreamWatchdogCheckInterval()) - .setTracerFactory(settings.getTracerFactory()) + .setTracerFactory(apiTracerFactory) .build(); } diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/TransportChannel.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/TransportChannel.java index d54352e9b2..16a20c76d8 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/TransportChannel.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/TransportChannel.java @@ -31,6 +31,7 @@ import com.google.api.core.InternalExtensionOnly; import com.google.api.gax.core.BackgroundResource; +import java.util.Map; /** Class whose instances can issue RPCs on a particular transport. */ @InternalExtensionOnly @@ -47,4 +48,6 @@ public interface TransportChannel extends BackgroundResource { * Returns an empty {@link ApiCallContext} that is compatible with this {@code TransportChannel}. */ ApiCallContext getEmptyCallContext(); + + Map getConfigurations(); } diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/ApiTracerFactory.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/ApiTracerFactory.java index bb8345b88c..33535a5daa 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/tracing/ApiTracerFactory.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/ApiTracerFactory.java @@ -31,6 +31,9 @@ import com.google.api.core.InternalApi; import com.google.api.core.InternalExtensionOnly; +import com.google.common.collect.ImmutableSet; +import java.util.Map; +import java.util.Set; /** * A factory to create new instances of {@link ApiTracer}s. @@ -53,6 +56,36 @@ enum OperationType { BidiStreaming } + enum MetricFlags { + DIRECTPATH( + ImmutableSet.of(MetricAttribute.DIRECTPATH_ENABLED, MetricAttribute.DIRECTPATH_USED)); + + private final Set otelAttributeKey; + + MetricFlags(Set otelAttributeKey) { + this.otelAttributeKey = otelAttributeKey; + } + + public Set getOtelAttributeKey() { + return otelAttributeKey; + } + } + + enum MetricAttribute { + DIRECTPATH_ENABLED("directpath_enabled"), + DIRECTPATH_USED("directpath_used"); + + private final String attribute; + + MetricAttribute(String attribute) { + this.attribute = attribute; + } + + public String getAttribute() { + return attribute; + } + } + /** * Create a new {@link ApiTracer} that will be a child of the current context. * @@ -61,4 +94,6 @@ enum OperationType { * @param operationType the type of operation that the tracer will trace */ ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType); + + default void addAttributes(Map attributes) {} } diff --git a/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracerFactory.java b/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracerFactory.java index d2b8d87fb4..af4d61490e 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracerFactory.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/tracing/MetricsTracerFactory.java @@ -31,6 +31,10 @@ import com.google.api.core.BetaApi; import com.google.api.core.InternalApi; +import com.google.common.collect.ImmutableSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; /** * A {@link ApiTracerFactory} to build instances of {@link MetricsTracer}. @@ -45,13 +49,44 @@ public class MetricsTracerFactory implements ApiTracerFactory { protected MetricsRecorder metricsRecorder; + private final Set metricFlagsSet; + + private final Map additionalDefaultAttributes; + public MetricsTracerFactory(MetricsRecorder metricsRecorder) { + this(metricsRecorder, ImmutableSet.of()); + } + + public MetricsTracerFactory(MetricsRecorder metricsRecorder, Set metricFlagsSet) { this.metricsRecorder = metricsRecorder; + this.metricFlagsSet = metricFlagsSet; + this.additionalDefaultAttributes = new HashMap<>(); } @Override public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) { - return new MetricsTracer( - MethodName.of(spanName.getClientName(), spanName.getMethodName()), metricsRecorder); + MetricsTracer metricsTracer = + new MetricsTracer( + MethodName.of(spanName.getClientName(), spanName.getMethodName()), metricsRecorder); + for (Map.Entry additionalDefaultAttribute : + additionalDefaultAttributes.entrySet()) { + metricsTracer.addAttributes( + additionalDefaultAttribute.getKey(), additionalDefaultAttribute.getValue()); + } + return metricsTracer; + } + + @Override + public void addAttributes(Map attributes) { + for (Map.Entry attributeEntry : attributes.entrySet()) { + String attribute = attributeEntry.getKey(); + for (MetricFlags metricFlags : metricFlagsSet) { + for (MetricAttribute metricAttribute : metricFlags.getOtelAttributeKey()) { + if (metricAttribute.getAttribute().equals(attribute)) { + additionalDefaultAttributes.put(attributeEntry.getKey(), attributeEntry.getValue()); + } + } + } + } } } diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeTransportChannel.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeTransportChannel.java index 0d4abac8f1..4f3e33655c 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeTransportChannel.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeTransportChannel.java @@ -31,6 +31,7 @@ import com.google.api.core.InternalApi; import com.google.api.gax.rpc.TransportChannel; +import com.google.common.collect.ImmutableMap; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -65,6 +66,11 @@ public FakeCallContext getEmptyCallContext() { return FakeCallContext.createDefault(); } + @Override + public Map getConfigurations() { + return ImmutableMap.of(); + } + @Override public void shutdown() { isShutdown = true;