Skip to content

Commit 1721e7c

Browse files
authored
feat(datastore): Enable Otel metrics for custom Otel (#12969)
Mark `setMetricsEnabled(boolean enabled)` as public in DatastoreOpenTelemetryOptions. Some additional clean up about the Otel object and small fixes
1 parent 622955b commit 1721e7c

7 files changed

Lines changed: 109 additions & 61 deletions

File tree

java-datastore/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreOpenTelemetryOptions.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
package com.google.cloud.datastore;
1818

1919
import com.google.api.core.BetaApi;
20+
import com.google.common.base.Preconditions;
2021
import io.opentelemetry.api.OpenTelemetry;
2122
import javax.annotation.Nonnull;
22-
import javax.annotation.Nullable;
2323

2424
/**
2525
* Represents the options that are used to configure the use of OpenTelemetry for telemetry
@@ -29,14 +29,15 @@ public class DatastoreOpenTelemetryOptions {
2929
private final boolean tracingEnabled;
3030
private final boolean metricsEnabled;
3131
private final boolean exportBuiltinMetricsToGoogleCloudMonitoring;
32-
private final @Nullable OpenTelemetry openTelemetry;
32+
private final OpenTelemetry openTelemetry;
3333

3434
DatastoreOpenTelemetryOptions(Builder builder) {
3535
this.tracingEnabled = builder.tracingEnabled;
3636
this.metricsEnabled = builder.metricsEnabled;
3737
this.exportBuiltinMetricsToGoogleCloudMonitoring =
3838
builder.exportBuiltinMetricsToGoogleCloudMonitoring;
39-
this.openTelemetry = builder.openTelemetry;
39+
this.openTelemetry =
40+
builder.openTelemetry == null ? OpenTelemetry.noop() : builder.openTelemetry;
4041
}
4142

4243
/**
@@ -88,11 +89,13 @@ public boolean isExportBuiltinMetricsToGoogleCloudMonitoring() {
8889
}
8990

9091
/**
91-
* Returns the custom {@link OpenTelemetry} instance, if one was provided.
92+
* Returns the configured custom {@link OpenTelemetry} instance.
9293
*
93-
* @return the custom {@link OpenTelemetry} instance, or {@code null} if none was provided.
94+
* @return the configured {@link OpenTelemetry} instance, or the global instance if a custom one
95+
* was not provided. If there is no global instance, then {@code OpenTelemetry.noop()} is
96+
* returned.
9497
*/
95-
@Nullable
98+
@Nonnull
9699
public OpenTelemetry getOpenTelemetry() {
97100
return openTelemetry;
98101
}
@@ -123,7 +126,7 @@ public static class Builder {
123126
private boolean metricsEnabled;
124127
private boolean exportBuiltinMetricsToGoogleCloudMonitoring;
125128

126-
@Nullable private OpenTelemetry openTelemetry;
129+
private OpenTelemetry openTelemetry;
127130

128131
private Builder() {
129132
tracingEnabled = false;
@@ -159,8 +162,8 @@ public DatastoreOpenTelemetryOptions.Builder setTracingEnabled(boolean enabled)
159162
* @param enabled Whether metrics should be enabled.
160163
* @return this builder instance.
161164
*/
162-
@Nonnull
163-
DatastoreOpenTelemetryOptions.Builder setMetricsEnabled(boolean enabled) {
165+
@BetaApi
166+
public DatastoreOpenTelemetryOptions.Builder setMetricsEnabled(boolean enabled) {
164167
this.metricsEnabled = enabled;
165168
return this;
166169
}
@@ -193,6 +196,7 @@ public DatastoreOpenTelemetryOptions.Builder setExportBuiltinMetricsToGoogleClou
193196
@Nonnull
194197
public DatastoreOpenTelemetryOptions.Builder setOpenTelemetry(
195198
@Nonnull OpenTelemetry openTelemetry) {
199+
Preconditions.checkNotNull(openTelemetry, "OpenTelemetry instance cannot be null");
196200
this.openTelemetry = openTelemetry;
197201
return this;
198202
}

java-datastore/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DatastoreMetricsRecorder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ static DatastoreMetricsRecorder getInstance(
122122
// Note: Metrics will not be sent if an emulator is enabled.
123123
if (otelOptions.isMetricsEnabled()) {
124124
OpenTelemetry customOtel = otelOptions.getOpenTelemetry();
125-
if (customOtel == null) {
125+
if (customOtel.getMeterProvider() == OpenTelemetry.noop().getMeterProvider()) {
126126
customOtel = GlobalOpenTelemetry.get();
127127
}
128128
recorders.add(

java-datastore/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@
2222
import com.google.api.core.ApiFutures;
2323
import com.google.api.core.InternalApi;
2424
import com.google.cloud.datastore.DatastoreOptions;
25-
import com.google.cloud.datastore.telemetry.TraceUtil.Context;
26-
import com.google.cloud.datastore.telemetry.TraceUtil.Scope;
27-
import com.google.cloud.datastore.telemetry.TraceUtil.Span;
2825
import com.google.common.base.Throwables;
2926
import io.grpc.ManagedChannelBuilder;
3027
import io.opentelemetry.api.GlobalOpenTelemetry;
@@ -51,16 +48,12 @@ public class EnabledTraceUtil implements TraceUtil {
5148
private final DatastoreOptions datastoreOptions;
5249

5350
EnabledTraceUtil(DatastoreOptions datastoreOptions) {
54-
OpenTelemetry openTelemetry = datastoreOptions.getOpenTelemetryOptions().getOpenTelemetry();
55-
56-
// If tracing is enabled, but an OpenTelemetry instance is not provided, fall back
57-
// to using GlobalOpenTelemetry.
58-
if (openTelemetry == null) {
59-
openTelemetry = GlobalOpenTelemetry.get();
60-
}
61-
6251
this.datastoreOptions = datastoreOptions;
63-
this.openTelemetry = openTelemetry;
52+
OpenTelemetry otel = datastoreOptions.getOpenTelemetryOptions().getOpenTelemetry();
53+
if (otel.getTracerProvider() == TracerProvider.noop()) {
54+
otel = GlobalOpenTelemetry.get();
55+
}
56+
this.openTelemetry = otel;
6457
this.tracer = openTelemetry.getTracer(LIBRARY_NAME);
6558
}
6659

java-datastore/google-cloud-datastore/src/test/java/com/google/cloud/datastore/DatastoreOpenTelemetryOptionsTestHelper.java

Lines changed: 0 additions & 34 deletions
This file was deleted.

java-datastore/google-cloud-datastore/src/test/java/com/google/cloud/datastore/DatastoreOptionsTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static org.junit.Assert.assertNotEquals;
2323
import static org.junit.Assert.assertSame;
2424
import static org.junit.Assert.assertTrue;
25+
import static org.junit.Assert.fail;
2526

2627
import com.google.api.gax.grpc.ChannelPoolSettings;
2728
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
@@ -159,6 +160,45 @@ public void testTelemetrySignalsMixedEnabled() {
159160
assertTrue(o2.isEnabled());
160161
}
161162

163+
@Test
164+
public void testOpenTelemetryMetricsAndCloudMonitoringMixed() {
165+
DatastoreOpenTelemetryOptions o1 =
166+
DatastoreOpenTelemetryOptions.newBuilder()
167+
.setMetricsEnabled(true)
168+
.setExportBuiltinMetricsToGoogleCloudMonitoring(false)
169+
.build();
170+
assertTrue(o1.isMetricsEnabled());
171+
assertFalse(o1.isExportBuiltinMetricsToGoogleCloudMonitoring());
172+
assertTrue(o1.isEnabled());
173+
174+
DatastoreOpenTelemetryOptions o2 =
175+
DatastoreOpenTelemetryOptions.newBuilder()
176+
.setMetricsEnabled(false)
177+
.setExportBuiltinMetricsToGoogleCloudMonitoring(true)
178+
.build();
179+
assertFalse(o2.isMetricsEnabled());
180+
assertTrue(o2.isExportBuiltinMetricsToGoogleCloudMonitoring());
181+
assertFalse(o2.isEnabled());
182+
}
183+
184+
@Test
185+
public void testOpenTelemetryOptionsDefaultInstance() {
186+
DatastoreOpenTelemetryOptions telemetryOptions =
187+
DatastoreOpenTelemetryOptions.newBuilder().build();
188+
assertThat(telemetryOptions.getOpenTelemetry())
189+
.isSameInstanceAs(io.opentelemetry.api.OpenTelemetry.noop());
190+
}
191+
192+
@Test
193+
public void testOpenTelemetryOptionsSetNullThrowsNPE() {
194+
try {
195+
DatastoreOpenTelemetryOptions.newBuilder().setOpenTelemetry(null);
196+
fail("Expected NullPointerException");
197+
} catch (NullPointerException e) {
198+
assertThat(e.getMessage()).isEqualTo("OpenTelemetry instance cannot be null");
199+
}
200+
}
201+
162202
@Test
163203
public void testNamespace() {
164204
assertTrue(options.build().getNamespace().isEmpty());

java-datastore/google-cloud-datastore/src/test/java/com/google/cloud/datastore/ITDatastoreBuiltInAndCustomMetrics.java renamed to java-datastore/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITDatastoreClientSideMetrics.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.google.cloud.datastore;
17+
package com.google.cloud.datastore.it;
1818

1919
import static com.google.common.truth.Truth.assertThat;
2020
import static com.google.common.truth.Truth.assertWithMessage;
2121
import static org.junit.Assume.assumeNotNull;
2222

2323
import com.google.cloud.TransportOptions;
24+
import com.google.cloud.datastore.Datastore;
25+
import com.google.cloud.datastore.DatastoreOpenTelemetryOptions;
26+
import com.google.cloud.datastore.DatastoreOptions;
27+
import com.google.cloud.datastore.Entity;
28+
import com.google.cloud.datastore.Key;
2429
import com.google.cloud.datastore.telemetry.TelemetryConstants;
2530
import com.google.cloud.grpc.GrpcTransportOptions;
2631
import com.google.cloud.http.HttpTransportOptions;
@@ -59,16 +64,15 @@
5964
*/
6065
@RunWith(Parameterized.class)
6166
@SuppressWarnings("checkstyle:abbreviationaswordinname")
62-
public class ITDatastoreBuiltInAndCustomMetrics {
67+
public class ITDatastoreClientSideMetrics {
6368

6469
private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT");
6570
private static final String DATABASE_ID =
6671
System.getenv().getOrDefault("DATASTORE_DATABASE_ID", "");
67-
private boolean isDatastoreClosed = false;
6872

6973
private final TransportOptions transportOptions;
7074

71-
public ITDatastoreBuiltInAndCustomMetrics(TransportOptions transportOptions) {
75+
public ITDatastoreClientSideMetrics(TransportOptions transportOptions) {
7276
this.transportOptions = transportOptions;
7377
}
7478

@@ -134,7 +138,7 @@ public void setUp() {
134138

135139
@After
136140
public void tearDown() throws Exception {
137-
if (datastore != null && !isDatastoreClosed) {
141+
if (datastore != null) {
138142
Key key = datastore.newKeyFactory().setKind(kind).newKey("metrics-it-entity");
139143
try {
140144
datastore.delete(key);

java-datastore/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DatastoreMetricsRecorderTest.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,45 @@ public void openTelemetryRecorderCreatedWithExplicitOpenTelemetry() {
109109

110110
assertThat(recorder.getOpenTelemetry()).isSameInstanceAs(openTelemetry);
111111
}
112+
113+
@Test
114+
public void builtInDisabledAndCustomEnabled_returnsOneRecorder() {
115+
DatastoreOptions options =
116+
baseOptions()
117+
.setOpenTelemetryOptions(
118+
DatastoreOpenTelemetryOptions.newBuilder()
119+
.setExportBuiltinMetricsToGoogleCloudMonitoring(false)
120+
.setMetricsEnabled(true)
121+
.setOpenTelemetry(OpenTelemetry.noop())
122+
.build())
123+
.build();
124+
OpenTelemetry builtInOtel = EasyMock.createMock(OpenTelemetry.class);
125+
EasyMock.replay(builtInOtel);
126+
127+
DatastoreMetricsRecorder recorder = DatastoreMetricsRecorder.getInstance(options, builtInOtel);
128+
assertThat(recorder).isInstanceOf(CompositeDatastoreMetricsRecorder.class);
129+
CompositeDatastoreMetricsRecorder compositeRecorder =
130+
(CompositeDatastoreMetricsRecorder) recorder;
131+
assertThat(compositeRecorder.getMetricRecorders().size()).isEqualTo(1);
132+
}
133+
134+
@Test
135+
public void bothEnabled_returnsTwoRecorders() {
136+
DatastoreOptions options =
137+
baseOptions()
138+
.setOpenTelemetryOptions(
139+
DatastoreOpenTelemetryOptions.newBuilder()
140+
.setExportBuiltinMetricsToGoogleCloudMonitoring(true)
141+
.setMetricsEnabled(true)
142+
.setOpenTelemetry(OpenTelemetry.noop())
143+
.build())
144+
.build();
145+
OpenTelemetry builtInOtel = OpenTelemetry.noop();
146+
147+
DatastoreMetricsRecorder recorder = DatastoreMetricsRecorder.getInstance(options, builtInOtel);
148+
assertThat(recorder).isInstanceOf(CompositeDatastoreMetricsRecorder.class);
149+
CompositeDatastoreMetricsRecorder compositeRecorder =
150+
(CompositeDatastoreMetricsRecorder) recorder;
151+
assertThat(compositeRecorder.getMetricRecorders().size()).isEqualTo(2);
152+
}
112153
}

0 commit comments

Comments
 (0)