Skip to content
This repository was archived by the owner on May 14, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
package com.google.api.gax.grpc;

import com.google.api.core.InternalApi;
import com.google.api.gax.tracing.ClientMetricsTracer;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -80,11 +81,22 @@ class ChannelPool extends ManagedChannel {
private final AtomicInteger indexTicker = new AtomicInteger();
private final String authority;

private ClientMetricsTracer clientMetricsTracer;
static ChannelPool create(ChannelPoolSettings settings, ChannelFactory channelFactory)
throws IOException {
throws IOException {
return new ChannelPool(settings, channelFactory, Executors.newSingleThreadScheduledExecutor());
}

static ChannelPool create(ChannelPoolSettings settings, ChannelFactory channelFactory, ClientMetricsTracer clientMetricsTracer)
throws IOException {
ChannelPool channelPool = new ChannelPool(settings, channelFactory, Executors.newSingleThreadScheduledExecutor());
channelPool.clientMetricsTracer = clientMetricsTracer;
if (channelPool.clientMetricsTracer != null) {
channelPool.clientMetricsTracer.recordCurrentChannelSize(1);
}
return channelPool;
}

/**
* Initializes the channel pool. Assumes that all channels have the same authority.
*
Expand Down Expand Up @@ -298,6 +310,7 @@ void resize() {

shrink(dampenedTarget);
}
clientMetricsTracer.recordCurrentChannelSize(localEntries.size());
}

/** Not threadsafe, must be called under the entryWriteLock monitor */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.ClientMetricsTracer;
import com.google.auth.Credentials;
import com.google.auth.oauth2.ComputeEngineCredentials;
import com.google.common.annotations.VisibleForTesting;
Expand Down Expand Up @@ -112,7 +113,7 @@ public final class InstantiatingGrpcChannelProvider implements TransportChannelP
@Nullable private final Boolean allowNonDefaultServiceAccount;
@VisibleForTesting final ImmutableMap<String, ?> directPathServiceConfig;
@Nullable private final MtlsProvider mtlsProvider;

@Nullable private ClientMetricsTracer clientMetricsTracer;
@Nullable
private final ApiFunction<ManagedChannelBuilder, ManagedChannelBuilder> channelConfigurator;

Expand Down Expand Up @@ -178,6 +179,11 @@ public String getTransportName() {
return GrpcTransportChannel.getGrpcTransportName();
}

@Override
public void setClientMetricsTracer(ClientMetricsTracer clientMetricsTracer) {
this.clientMetricsTracer = clientMetricsTracer;
}

@Override
public boolean needsEndpoint() {
return endpoint == null;
Expand Down Expand Up @@ -235,7 +241,7 @@ public TransportChannel getTransportChannel() throws IOException {
private TransportChannel createChannel() throws IOException {
return GrpcTransportChannel.create(
ChannelPool.create(
channelPoolSettings, InstantiatingGrpcChannelProvider.this::createSingleChannel));
channelPoolSettings, InstantiatingGrpcChannelProvider.this::createSingleChannel, clientMetricsTracer));
}

private boolean isDirectPathEnabled() {
Expand Down
12 changes: 12 additions & 0 deletions gax-java/gax/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@
<artifactId>graal-sdk</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.google.api.gax.rpc.mtls.MtlsProvider;
import com.google.api.gax.tracing.ApiTracerFactory;
import com.google.api.gax.tracing.BaseApiTracerFactory;
import com.google.api.gax.tracing.ClientMetricsTracer;
import com.google.auth.Credentials;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -198,6 +199,9 @@ public static ClientContext create(StubSettings settings) throws IOException {
if (transportChannelProvider.needsEndpoint()) {
transportChannelProvider = transportChannelProvider.withEndpoint(endpoint);
}
ClientMetricsTracer clientMetricsTracer = settings.getTracerFactory().newClientMetricsTracer();
transportChannelProvider.setClientMetricsTracer(clientMetricsTracer);

TransportChannel transportChannel = transportChannelProvider.getTransportChannel();

ApiCallContext defaultCallContext =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import com.google.api.core.BetaApi;
import com.google.api.core.InternalExtensionOnly;
import com.google.api.gax.tracing.ClientMetricsTracer;
import com.google.auth.Credentials;
import java.io.IOException;
import java.util.Map;
Expand Down Expand Up @@ -142,4 +143,6 @@ public interface TransportChannelProvider {
* <p>This string can be used for identifying transports for switching logic.
*/
String getTransportName();

default void setClientMetricsTracer(ClientMetricsTracer clientMetricsTracer) {};
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ public interface ApiTracer {
/** Adds an annotation that the attempt succeeded. */
void attemptSucceeded();

//This is for libraries to override to intended name
default String attemptLatencyName() {

@mutianf mutianf Jun 27, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going to provide a default implementation, I wonder instead of override the attempt name, maybe we can provide a general class, something like ApiTracerRecorder and provide functions like apiTracerInstrument.record(latency, attributes). So client libraries can define their own meter definition. Similar to https://github.com/googleapis/java-bigtable/pull/1796/files#diff-f2ab39ff606949b18fa0ea0a25b6149352064c8b1f775a78cb79eb8acfddde6f BigtableInsturment and BuiltinInstruments (I'm going to rename them to BgitableRecorder and BuiltinRecorder)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see the need of another abstraction layer for customizing some attributes(like extract this method to something like MetricNames), however, I think most of things, like description and unit should be the same for all services, so that we can have a consistent experience for all services. Let me know if I'm missing something.

return "attempt_latency";
};

/** Add an annotation that the attempt was cancelled by the user. */
void attemptCancelled();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,9 @@ enum OperationType {
* @param operationType the type of operation that the tracer will trace
*/
ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType);

//This probably needs to be moved to a new factory
default ClientMetricsTracer newClientMetricsTracer() {
return null;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.google.api.gax.tracing;

public interface ClientMetricsTracer {

void recordCurrentChannelSize(int channelSize);

default String channelSizeName() {
return "channel_size";
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.google.api.gax.tracing;

import io.opentelemetry.api.metrics.Meter;

public class OpenTelemetryClientMetricsTracer implements ClientMetricsTracer {

private Meter meter;
public OpenTelemetryClientMetricsTracer(Meter meter) {
this.meter = meter;
}

@Override
public void recordCurrentChannelSize(int channelSize) {
meter
.gaugeBuilder(channelSizeName())
.setDescription("Channel Size")
.setUnit("1")
.ofLongs()
.buildWithCallback(measurement -> measurement.record(channelSize));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* Copyright 2023 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.google.api.gax.tracing;

import com.google.common.base.Stopwatch;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;
import org.threeten.bp.Duration;

import java.util.concurrent.TimeUnit;

import static io.opentelemetry.api.common.AttributeKey.stringKey;

public class OpenTelemetryMetricsTracer implements ApiTracer {
protected Meter meter;

private Stopwatch attemptTimer;

private SpanName spanName;

public OpenTelemetryMetricsTracer(Meter meter, SpanName spanName) {
this.meter = meter;
this.spanName = spanName;
}

@Override
public Scope inScope() {
return () -> {};
}

@Override
public void operationSucceeded() {

}

@Override
public void operationCancelled() {

}

@Override
public void operationFailed(Throwable error) {

}

@Override
public void connectionSelected(String id) {

}

@Override
public void attemptStarted(int attemptNumber) {

}

@Override
public void attemptStarted(Object request, int attemptNumber) {
attemptTimer = Stopwatch.createStarted();
LongCounter longCounter = meter.counterBuilder("attempt_count")
.setDescription("Attempt Count")
.setUnit("1")
.build();
longCounter.add(1);
}

@Override
public void attemptSucceeded() {
DoubleHistogram doubleHistogram = meter.histogramBuilder(attemptLatencyName())
.setDescription("Duration of an individual operation attempt")
.setUnit("ms")
.build();
Attributes attributes = Attributes.of(stringKey("method_name"), spanName.toString());
doubleHistogram.record(attemptTimer.elapsed(TimeUnit.MILLISECONDS), attributes);
}

@Override
public void attemptCancelled() {

}

@Override
public void attemptFailed(Throwable error, Duration delay) {

}

@Override
public void attemptFailedRetriesExhausted(Throwable error) {

}

@Override
public void attemptPermanentFailure(Throwable error) {

}

@Override
public void lroStartFailed(Throwable error) {

}

@Override
public void lroStartSucceeded() {

}

@Override
public void responseReceived() {

}

@Override
public void requestSent() {

}

@Override
public void batchRequestSent(long elementCount, long requestSize) {

}
}
Loading