Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ private static String hashClientUId(String uuid) {
*/
@Nullable
public OpenTelemetry createOpenTelemetry(@Nonnull DatastoreOptions options) {
// If built-in metrics export is disabled, return no-op OpenTelemetry to avoid instantiating
// a real SdkMeterProvider. Otherwise, the SDK-internal PeriodicMetricReader will start
// and attempt to export diagnostic metrics, leading to log spam if the exporter fails.
if (!options.getOpenTelemetryOptions().isExportBuiltinMetricsToGoogleCloudMonitoring()) {
return OpenTelemetry.noop();
}
Credentials credentials =
Preconditions.checkNotNull(
options.getCredentials(), "Credentials cannot be null for built in metrics");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ public CompletableResultCode export(@Nonnull Collection<MetricData> collection)
return CompletableResultCode.ofFailure();
}

if (datastoreTimeSeries.isEmpty()) {
return CompletableResultCode.ofSuccess();
}

ProjectName projectName = ProjectName.of(projectId);

// Perform the actual network call to Cloud Monitoring.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,12 @@ static List<TimeSeries> convertToDatastoreTimeSeries(
List<MetricData> collection, Map<String, String> clientAttributes) {
List<TimeSeries> allTimeSeries = new ArrayList<>();

// Metrics should already been filtered for Gax and Datastore related ones
// Only convert metrics that belong to Datastore/GAX (starting with METRIC_PREFIX)
// to filter out OpenTelemetry internal diagnostic metrics.
for (MetricData metricData : collection) {
if (!metricData.getName().startsWith(TelemetryConstants.METRIC_PREFIX)) {
continue;
}
// TODO(b/405457573): The monitored resource is currently written to `global` because the
// Firestore namespace in Cloud Monitoring has not been deployed yet. Once the namespace
// is available, database_id and location labels should be added here using
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.auth.CredentialTypeForMetrics;
import com.google.auth.Credentials;
import com.google.cloud.NoCredentials;
import com.google.cloud.datastore.DatastoreOpenTelemetryOptions;
import com.google.cloud.datastore.DatastoreOptions;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.sdk.OpenTelemetrySdk;
Expand Down Expand Up @@ -69,6 +70,10 @@ public void testCreateOpenTelemetry_returnsNonNull() {
.setProjectId(PROJECT_ID)
.setDatabaseId("test-db")
.setCredentials(credentials)
.setOpenTelemetryOptions(
DatastoreOpenTelemetryOptions.newBuilder()
.setExportBuiltinMetricsToGoogleCloudMonitoring(true)
.build())
.build();

OpenTelemetry otel = BuiltInDatastoreMetricsProvider.INSTANCE.createOpenTelemetry(options);
Expand Down Expand Up @@ -96,13 +101,21 @@ public void testCreateOpenTelemetry_eachCallReturnsDistinctInstance() {
.setProjectId(PROJECT_ID)
.setDatabaseId("test-db")
.setCredentials(credentials1)
.setOpenTelemetryOptions(
DatastoreOpenTelemetryOptions.newBuilder()
.setExportBuiltinMetricsToGoogleCloudMonitoring(true)
.build())
.build();

DatastoreOptions options2 =
DatastoreOptions.newBuilder()
.setProjectId(PROJECT_ID)
.setDatabaseId("test-db")
.setCredentials(credentials2)
.setOpenTelemetryOptions(
DatastoreOpenTelemetryOptions.newBuilder()
.setExportBuiltinMetricsToGoogleCloudMonitoring(true)
.build())
.build();

OpenTelemetry otel1 = BuiltInDatastoreMetricsProvider.INSTANCE.createOpenTelemetry(options1);
Expand Down Expand Up @@ -137,4 +150,21 @@ public void testCreateOpenTelemetry_withEmulatorHostProperty_returnsNoOp() {
System.clearProperty(DatastoreOptions.LOCAL_HOST_ENV_VAR);
}
}

@Test
public void testCreateOpenTelemetry_exportDisabled_returnsNoOp() {
Credentials credentials = EasyMock.mock(Credentials.class);
EasyMock.replay(credentials);

DatastoreOptions options =
DatastoreOptions.newBuilder()
.setProjectId(PROJECT_ID)
.setDatabaseId("test-db")
.setCredentials(credentials)
// export is disabled by default
.build();

OpenTelemetry otel = BuiltInDatastoreMetricsProvider.INSTANCE.createOpenTelemetry(options);
assertThat(otel).isSameInstanceAs(OpenTelemetry.noop());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.google.monitoring.v3.TimeSeries;
import com.google.protobuf.Empty;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
import io.opentelemetry.sdk.metrics.data.LongPointData;
Expand Down Expand Up @@ -190,6 +191,35 @@ public void testClientCacheReferenceCounting() {
verify(mockClient);
}

@Test
public void testExportingIgnoredMetrics() {
// No expectations on mockMetricServiceStub means we expect NO calls to it.
replay(mockMetricServiceStub);

long fakeValue = 11L;
long startEpoch = 10;
long endEpoch = 15;
LongPointData longPointData =
ImmutableLongPointData.create(startEpoch, endEpoch, attributes, fakeValue);

String ignoredMetricName = "otel.sdk.metric_reader.collection.duration";
MetricData ignoredData =
ImmutableMetricData.createLongSum(
resource,
scope,
ignoredMetricName,
"description",
"1",
ImmutableSumData.create(
true, AggregationTemporality.CUMULATIVE, ImmutableList.of(longPointData)));

CompletableResultCode result = exporter.export(Collections.singletonList(ignoredData));

assertThat(result.isSuccess()).isTrue();

verify(mockMetricServiceStub);
}

private static class FakeMetricServiceClient extends MetricServiceClient {
protected FakeMetricServiceClient(MetricServiceStub stub) {
super(stub);
Expand Down
Loading