Skip to content

chore: add support for OpenTelemetry metrics to Connection API #2896

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,20 @@ If you are using Maven without the BOM, add this to your dependencies:
If you are using Gradle 5.x or later, add this to your dependencies:

```Groovy
implementation platform('com.google.cloud:libraries-bom:26.32.0')
implementation platform('com.google.cloud:libraries-bom:26.33.0')

implementation 'com.google.cloud:google-cloud-spanner'
```
If you are using Gradle without BOM, add this to your dependencies:

```Groovy
implementation 'com.google.cloud:google-cloud-spanner:6.59.0'
implementation 'com.google.cloud:google-cloud-spanner:6.60.1'
```

If you are using SBT, add this to your dependencies:

```Scala
libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.59.0"
libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.60.1"
```
<!-- {x-version-update-end} -->

Expand Down Expand Up @@ -643,7 +643,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
[kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java11.html
[stability-image]: https://img.shields.io/badge/stability-stable-green
[maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-spanner.svg
[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.59.0
[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.60.1
[authentication]: https://github.com/googleapis/google-cloud-java#authentication
[auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes
[predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
import io.opentelemetry.api.OpenTelemetry;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
Expand Down Expand Up @@ -484,6 +485,7 @@ public static class Builder {
private List<StatementExecutionInterceptor> statementExecutionInterceptors =
Collections.emptyList();
private SpannerOptionsConfigurator configurator;
private OpenTelemetry openTelemetry;

private Builder() {}

Expand Down Expand Up @@ -633,6 +635,11 @@ Builder setCredentials(Credentials credentials) {
return this;
}

public Builder setOpenTelemetry(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
return this;
}

/** @return the {@link ConnectionOptions} */
public ConnectionOptions build() {
Preconditions.checkState(this.uri != null, "Connection URI is required");
Expand Down Expand Up @@ -691,6 +698,7 @@ public static Builder newBuilder() {
private final boolean retryAbortsInternally;
private final boolean useVirtualThreads;
private final boolean useVirtualGrpcTransportThreads;
private final OpenTelemetry openTelemetry;
private final List<StatementExecutionInterceptor> statementExecutionInterceptors;
private final SpannerOptionsConfigurator configurator;

Expand Down Expand Up @@ -792,6 +800,7 @@ private ConnectionOptions(Builder builder) {
this.retryAbortsInternally = parseRetryAbortsInternally(this.uri);
this.useVirtualThreads = parseUseVirtualThreads(this.uri);
this.useVirtualGrpcTransportThreads = parseUseVirtualGrpcTransportThreads(this.uri);
this.openTelemetry = builder.openTelemetry;
this.statementExecutionInterceptors =
Collections.unmodifiableList(builder.statementExecutionInterceptors);
this.configurator = builder.configurator;
Expand Down Expand Up @@ -856,6 +865,14 @@ private static Integer parseIntegerProperty(String propertyName, String value) {
return null;
}

/**
* @return an instance of OpenTelemetry. If OpenTelemetry object is not set then <code>null</code>
* will be returned.
*/
OpenTelemetry getOpenTelemetry() {
return this.openTelemetry;
}

SpannerOptionsConfigurator getConfigurator() {
return configurator;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Ticker;
import io.grpc.ManagedChannelBuilder;
import io.opentelemetry.api.OpenTelemetry;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -156,6 +157,7 @@ static class SpannerPoolKey {
private final String databaseRole;
private final boolean routeToLeader;
private final boolean useVirtualGrpcTransportThreads;
private final OpenTelemetry openTelemetry;

@VisibleForTesting
static SpannerPoolKey of(ConnectionOptions options) {
Expand Down Expand Up @@ -183,6 +185,7 @@ private SpannerPoolKey(ConnectionOptions options) throws IOException {
this.userAgent = options.getUserAgent();
this.routeToLeader = options.isRouteToLeader();
this.useVirtualGrpcTransportThreads = options.isUseVirtualGrpcTransportThreads();
this.openTelemetry = options.getOpenTelemetry();
}

@Override
Expand All @@ -201,7 +204,8 @@ public boolean equals(Object o) {
&& Objects.equals(this.userAgent, other.userAgent)
&& Objects.equals(this.routeToLeader, other.routeToLeader)
&& Objects.equals(
this.useVirtualGrpcTransportThreads, other.useVirtualGrpcTransportThreads);
this.useVirtualGrpcTransportThreads, other.useVirtualGrpcTransportThreads)
&& Objects.equals(this.openTelemetry, other.openTelemetry);
}

@Override
Expand All @@ -216,7 +220,8 @@ public int hashCode() {
this.databaseRole,
this.userAgent,
this.routeToLeader,
this.useVirtualGrpcTransportThreads);
this.useVirtualGrpcTransportThreads,
this.openTelemetry);
}
}

Expand Down Expand Up @@ -349,6 +354,9 @@ Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) {
.setDatabaseRole(options.getDatabaseRole())
.setCredentials(options.getCredentials());
builder.setSessionPoolOption(key.sessionPoolOptions);
if (key.openTelemetry != null) {
builder.setOpenTelemetry(key.openTelemetry);
}
if (key.numChannels != null) {
builder.setNumChannels(key.numChannels);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import com.google.cloud.spanner.connection.SpannerPool.SpannerPoolKey;
import com.google.common.base.Ticker;
import com.google.common.testing.FakeTicker;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -69,6 +71,10 @@ public class SpannerPoolTest {
private ConnectionOptions options7 = mock(ConnectionOptions.class);
private ConnectionOptions options8 = mock(ConnectionOptions.class);

private ConnectionOptions optionsOpenTelemetry1 = mock(ConnectionOptions.class);
private ConnectionOptions optionsOpenTelemetry2 = mock(ConnectionOptions.class);
private ConnectionOptions optionsOpenTelemetry3 = mock(ConnectionOptions.class);

private SpannerPool createSubjectAndMocks() {
return createSubjectAndMocks(0L, Ticker.systemTicker());
}
Expand All @@ -83,6 +89,9 @@ Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) {
}
};

OpenTelemetry openTelemetry1 = OpenTelemetrySdk.builder().build();
OpenTelemetry openTelemetry2 = OpenTelemetrySdk.builder().build();

when(options1.getCredentialsUrl()).thenReturn(credentials1);
when(options1.getProjectId()).thenReturn("test-project-1");
when(options2.getCredentialsUrl()).thenReturn(credentials2);
Expand All @@ -101,6 +110,13 @@ Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) {
when(options8.getProjectId()).thenReturn("test-project-3");
when(options8.isRouteToLeader()).thenReturn(false);

when(optionsOpenTelemetry1.getProjectId()).thenReturn("test-project-1");
when(optionsOpenTelemetry1.getOpenTelemetry()).thenReturn(openTelemetry1);
when(optionsOpenTelemetry2.getProjectId()).thenReturn("test-project-1");
when(optionsOpenTelemetry2.getOpenTelemetry()).thenReturn(openTelemetry1);
when(optionsOpenTelemetry3.getProjectId()).thenReturn("test-project-1");
when(optionsOpenTelemetry3.getOpenTelemetry()).thenReturn(openTelemetry2);

return pool;
}

Expand Down Expand Up @@ -498,4 +514,21 @@ public void testSpannerPoolKeyEquality() {
assertEquals(key3, key4);
assertNotEquals(key4, key5);
}

@Test
public void testOpenTelemetry() {
SpannerPool pool = createSubjectAndMocks();
Spanner spanner1;
Spanner spanner2;

// assert equal
spanner1 = pool.getSpanner(optionsOpenTelemetry1, connection1);
spanner2 = pool.getSpanner(optionsOpenTelemetry2, connection2);
assertEquals(spanner1, spanner2);

// assert not equal
spanner1 = pool.getSpanner(optionsOpenTelemetry1, connection1);
spanner2 = pool.getSpanner(optionsOpenTelemetry3, connection2);
assertNotEquals(spanner1, spanner2);
}
}