Skip to content

Commit

Permalink
feat: Allow Adding Client Level Attributes to MetricsTracerFactory (#…
Browse files Browse the repository at this point in the history
…2614)

Allow the MetricsTracerFactory to take in a second parameter (Map of
attributes) that will be treated as client level attributes. These
attributes will be added to every single MetricsTracer created
throughout the lifecycle of the client.

Was able to verify this behavior inside Cloud Monitoring: 

![image](https://github.com/googleapis/sdk-platform-java/assets/6621793/832f485e-2834-4765-b381-9a15e2913412)

Additional Attribute was recorded.

Via:
```
    InstantiatingGrpcChannelProvider channelProvider =
            InstantiatingGrpcChannelProvider.newBuilder().build();

    Map<String, String> clientAttributesMapping = new HashMap<>();
    clientAttributesMapping.put("directpath_enabled", String.valueOf(channelProvider.canUseDirectPath()));

    ...
    options
      .setApiTracerFactory(new MetricsTracerFactory(recorder, clientAttributesMapping))
      .build();
```

---------

Co-authored-by: Blake Li <blakeli@google.com>
  • Loading branch information
lqiu96 and blakeli0 authored Jun 3, 2024
1 parent dc88ea2 commit f122c6f
Show file tree
Hide file tree
Showing 6 changed files with 448 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import com.google.api.core.ApiFunction;
import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
import com.google.api.core.InternalExtensionOnly;
import com.google.api.gax.core.ExecutorProvider;
import com.google.api.gax.rpc.FixedHeaderProvider;
import com.google.api.gax.rpc.HeaderProvider;
Expand Down Expand Up @@ -82,13 +81,26 @@
* <p>The client lib header and generator header values are used to form a value that goes into the
* http header of requests to the service.
*/
@InternalExtensionOnly
public final class InstantiatingGrpcChannelProvider implements TransportChannelProvider {

static String systemProductName;

static {
try {
systemProductName =
Files.asCharSource(new File("/sys/class/dmi/id/product_name"), StandardCharsets.UTF_8)
.readFirstLine();
} catch (IOException e) {
// If not on Compute Engine, FileNotFoundException will be thrown. Use empty string
// as it won't match with the GCE_PRODUCTION_NAME constants
systemProductName = "";
}
}

@VisibleForTesting
static final Logger LOG = Logger.getLogger(InstantiatingGrpcChannelProvider.class.getName());

private static final String DIRECT_PATH_ENV_DISABLE_DIRECT_PATH =
"GOOGLE_CLOUD_DISABLE_DIRECT_PATH";
static final String DIRECT_PATH_ENV_DISABLE_DIRECT_PATH = "GOOGLE_CLOUD_DISABLE_DIRECT_PATH";
private static final String DIRECT_PATH_ENV_ENABLE_XDS = "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS";
static final long DIRECT_PATH_KEEP_ALIVE_TIME_SECONDS = 3600;
static final long DIRECT_PATH_KEEP_ALIVE_TIMEOUT_SECONDS = 20;
Expand Down Expand Up @@ -147,6 +159,19 @@ private InstantiatingGrpcChannelProvider(Builder builder) {
: builder.directPathServiceConfig;
}

/**
* Package-Private constructor that is only visible for testing DirectPath functionality inside
* tests. This overrides the computed systemProductName when the class is initialized to help
* configure the result of {@link #isOnComputeEngine()} check.
*
* <p>If productName is null, that represents the result of an IOException
*/
@VisibleForTesting
InstantiatingGrpcChannelProvider(Builder builder, String productName) {
this(builder);
systemProductName = productName;
}

/**
* @deprecated If executor is not set, this channel provider will create channels with default
* grpc executor.
Expand Down Expand Up @@ -257,8 +282,8 @@ private boolean isDirectPathEnabled() {
return false;
}

@VisibleForTesting
boolean isDirectPathXdsEnabled() {
@InternalApi
public boolean isDirectPathXdsEnabled() {
// Method 1: Enable DirectPath xDS by option.
if (Boolean.TRUE.equals(attemptDirectPathXds)) {
return true;
Expand Down Expand Up @@ -320,15 +345,9 @@ boolean isCredentialDirectPathCompatible() {
static boolean isOnComputeEngine() {
String osName = System.getProperty("os.name");
if ("Linux".equals(osName)) {
try {
String result =
Files.asCharSource(new File("/sys/class/dmi/id/product_name"), StandardCharsets.UTF_8)
.readFirstLine();
return result.contains(GCE_PRODUCTION_NAME_PRIOR_2016)
|| result.contains(GCE_PRODUCTION_NAME_AFTER_2016);
} catch (IOException ignored) {
return false;
}
// systemProductName will be empty string if not on Compute Engine
return systemProductName.contains(GCE_PRODUCTION_NAME_PRIOR_2016)
|| systemProductName.contains(GCE_PRODUCTION_NAME_AFTER_2016);
}
return false;
}
Expand Down Expand Up @@ -370,10 +389,7 @@ private ManagedChannel createSingleChannel() throws IOException {

// Check DirectPath traffic.
boolean useDirectPathXds = false;
if (isDirectPathEnabled()
&& isCredentialDirectPathCompatible()
&& isOnComputeEngine()
&& canUseDirectPathWithUniverseDomain()) {
if (canUseDirectPath()) {
CallCredentials callCreds = MoreCallCredentials.from(credentials);
ChannelCredentials channelCreds =
GoogleDefaultChannelCredentials.newBuilder().callCredentials(callCreds).build();
Expand Down Expand Up @@ -446,6 +462,24 @@ && canUseDirectPathWithUniverseDomain()) {
return managedChannel;
}

/**
* Marked as Internal Api and intended for internal use. DirectPath must be enabled via the
* settings and a few other configurations/settings must also be valid for the request to go
* through DirectPath.
*
* <p>Checks: 1. Credentials are compatible 2.Running on Compute Engine 3. Universe Domain is
* configured to for the Google Default Universe
*
* @return if DirectPath is enabled for the client AND if the configurations are valid
*/
@InternalApi
public boolean canUseDirectPath() {
return isDirectPathEnabled()
&& isCredentialDirectPathCompatible()
&& isOnComputeEngine()
&& canUseDirectPathWithUniverseDomain();
}

/** The endpoint to be used for the channel. */
@Override
public String getEndpoint() {
Expand Down Expand Up @@ -753,6 +787,12 @@ public Builder setAttemptDirectPathXds() {
return this;
}

@VisibleForTesting
Builder setEnvProvider(EnvironmentProvider envProvider) {
this.envProvider = envProvider;
return this;
}

/**
* Sets a service config for direct path. If direct path is not enabled, the provided service
* config will be ignored.
Expand Down
Loading

0 comments on commit f122c6f

Please sign in to comment.