()
+ .put("Received", response.getFoundCount())
+ .put("Missing", response.getMissingCount())
+ .put("Deferred", response.getDeferredCount())
+ .build());
+ return response;
}
},
retrySettings,
@@ -465,10 +482,10 @@ public com.google.datastore.v1.LookupResponse call() throws DatastoreException {
: TRANSACTION_OPERATION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
index 21321897d..a4f25813a 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
@@ -61,6 +61,11 @@ public TraceUtil.Span setAttribute(String key, String value) {
return this;
}
+ @Override
+ public TraceUtil.Span setAttribute(String key, boolean value) {
+ return this;
+ }
+
@Override
public Scope makeCurrent() {
return new Scope();
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
index 8a5b0b36e..3bf6a7466 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
@@ -175,6 +175,12 @@ public TraceUtil.Span setAttribute(String key, String value) {
return this;
}
+ @Override
+ public TraceUtil.Span setAttribute(String key, boolean value) {
+ span.setAttribute(ATTRIBUTE_SERVICE_PREFIX + key, value);
+ return this;
+ }
+
@Override
public Scope makeCurrent() {
try (io.opentelemetry.context.Scope scope = span.makeCurrent()) {
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index 4e55a1ff6..c867a5525 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -32,6 +32,7 @@ public interface TraceUtil {
static final String ENABLE_TRACING_ENV_VAR = "DATASTORE_ENABLE_TRACING";
static final String LIBRARY_NAME = "com.google.cloud.datastore";
+ static final String SPAN_NAME_LOOKUP = "Lookup";
/**
* Creates and returns an instance of the TraceUtil class.
*
@@ -80,6 +81,9 @@ interface Span {
/** Adds the given attribute to this span. */
Span setAttribute(String key, String value);
+ /** Adds the given attribute to this span. */
+ Span setAttribute(String key, boolean value);
+
/** Marks this span as the current span. */
Scope makeCurrent();
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/testing/RemoteDatastoreHelper.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/testing/RemoteDatastoreHelper.java
index 596ce96d8..6167cedca 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/testing/RemoteDatastoreHelper.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/testing/RemoteDatastoreHelper.java
@@ -19,13 +19,16 @@
import com.google.api.core.InternalApi;
import com.google.api.gax.retrying.RetrySettings;
import com.google.cloud.datastore.Datastore;
+import com.google.cloud.datastore.DatastoreOpenTelemetryOptions;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Key;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.QueryResults;
import com.google.cloud.datastore.StructuredQuery;
import com.google.cloud.http.HttpTransportOptions;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
import java.util.UUID;
+import javax.annotation.Nullable;
import org.threeten.bp.Duration;
/**
@@ -38,13 +41,13 @@
* RetrySettings#getTotalTimeout()} is {@code 120000} and {@link
* RetrySettings#getInitialRetryDelay()} is {@code 250}. {@link
* HttpTransportOptions#getConnectTimeout()} and {@link HttpTransportOptions#getReadTimeout()} are
- * both both set to {@code 60000}.
+ * both both set to {@code 60000}. If an OpenTelemetrySdk object is passed in, OpenTelemetry Trace
+ * collection will be enabled for the Client application.
*
* Internal testing use only
*/
@InternalApi
public class RemoteDatastoreHelper {
-
private final DatastoreOptions options;
private final Datastore datastore;
private final String namespace;
@@ -78,18 +81,30 @@ public static RemoteDatastoreHelper create() {
}
/** Creates a {@code RemoteStorageHelper} object. */
- public static RemoteDatastoreHelper create(String databaseId) {
+ public static RemoteDatastoreHelper create(
+ String databaseId, @Nullable OpenTelemetrySdk openTelemetrySdk) {
HttpTransportOptions transportOptions = DatastoreOptions.getDefaultHttpTransportOptions();
transportOptions =
transportOptions.toBuilder().setConnectTimeout(60000).setReadTimeout(60000).build();
- DatastoreOptions datastoreOption =
+ DatastoreOptions.Builder datastoreOptionBuilder =
DatastoreOptions.newBuilder()
.setDatabaseId(databaseId)
.setNamespace(UUID.randomUUID().toString())
.setRetrySettings(retrySettings())
- .setTransportOptions(transportOptions)
- .build();
- return new RemoteDatastoreHelper(datastoreOption);
+ .setTransportOptions(transportOptions);
+
+ if (openTelemetrySdk != null) {
+ datastoreOptionBuilder.setOpenTelemetryOptions(
+ DatastoreOpenTelemetryOptions.newBuilder()
+ .setOpenTelemetry(openTelemetrySdk)
+ .setTracingEnabled(true)
+ .build());
+ }
+ return new RemoteDatastoreHelper(datastoreOptionBuilder.build());
+ }
+
+ public static RemoteDatastoreHelper create(String databaseId) {
+ return create(databaseId, /*openTelemetrySdk=*/ null);
}
private static RetrySettings retrySettings() {
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
new file mode 100644
index 000000000..24a9a7149
--- /dev/null
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -0,0 +1,530 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.datastore.it;
+
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
+import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.api.gax.rpc.NotFoundException;
+import com.google.cloud.datastore.Datastore;
+import com.google.cloud.datastore.DatastoreOptions;
+import com.google.cloud.datastore.Entity;
+import com.google.cloud.datastore.Key;
+import com.google.cloud.datastore.testing.RemoteDatastoreHelper;
+import com.google.cloud.opentelemetry.trace.TraceConfiguration;
+import com.google.cloud.opentelemetry.trace.TraceExporter;
+import com.google.cloud.trace.v1.TraceServiceClient;
+import com.google.common.base.Preconditions;
+import com.google.devtools.cloudtrace.v1.Trace;
+import com.google.devtools.cloudtrace.v1.TraceSpan;
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanContext;
+import io.opentelemetry.api.trace.TraceFlags;
+import io.opentelemetry.api.trace.TraceState;
+import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.Scope;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
+import io.opentelemetry.sdk.common.CompletableResultCode;
+import io.opentelemetry.sdk.resources.Resource;
+import io.opentelemetry.sdk.trace.SdkTracerProvider;
+import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
+import io.opentelemetry.sdk.trace.samplers.Sampler;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+// This End-to-End test verifies Client-side Tracing Functionality instrumented using the
+// OpenTelemetry API.
+// The test depends on the following external APIs/Services:
+// 1. Java OpenTelemetry SDK
+// 2. Cloud Trace Exporter
+// 3. TraceServiceClient from Cloud Trace API v1.
+//
+// Permissions required to run this test (https://cloud.google.com/trace/docs/iam#trace-roles):
+// 1. gcloud auth application-default login must be run with the test user.
+// 2. To write traces, test user must have one of roles/cloudtrace.[admin|agent|user] roles.
+// 3. To read traces, test user must have one of roles/cloudtrace.[admin|user] roles.
+//
+// Each test-case has the following workflow:
+// 1. OpenTelemetry SDK is initialized with Cloud Trace Exporter and 100% Trace Sampling
+// 2. On initialization, Datastore client is provided the OpenTelemetry SDK object from (1)
+// 3. A custom TraceID is generated and injected using a custom SpanContext
+// 4. Datastore operations are run inside a root TraceSpan created using the custom SpanContext from
+// (3).
+// 5. Traces are read-back using TraceServiceClient and verified against expected Call Stacks.
+@RunWith(TestParameterInjector.class)
+public class ITE2ETracingTest {
+ protected boolean isUsingGlobalOpenTelemetrySDK() {
+ return useGlobalOpenTelemetrySDK;
+ }
+
+ protected String datastoreNamedDatabase() {
+ return datastoreNamedDatabase;
+ }
+
+ // Helper class to track call-stacks in a trace
+ protected static class TraceContainer {
+
+ // Maps Span ID to TraceSpan
+ private final Map idSpanMap;
+
+ // Maps Parent Span ID to a list of Child SpanIDs, useful for top-down traversal
+ private final Map> parentChildIdMap;
+
+ // Tracks the Root Span ID
+ private long rootId;
+
+ public TraceContainer(String rootSpanName, Trace trace) {
+ idSpanMap = new TreeMap<>();
+ parentChildIdMap = new TreeMap<>();
+ for (TraceSpan span : trace.getSpansList()) {
+ long spanId = span.getSpanId();
+ idSpanMap.put(spanId, span);
+ if (rootSpanName.equals(span.getName())) {
+ rootId = span.getSpanId();
+ }
+
+ // Add self as a child of the parent span
+ if (!parentChildIdMap.containsKey(span.getParentSpanId())) {
+ parentChildIdMap.put(span.getParentSpanId(), new ArrayList<>());
+ }
+ parentChildIdMap.get(span.getParentSpanId()).add(spanId);
+ }
+ }
+
+ String spanName(long spanId) {
+ return idSpanMap.get(spanId).getName();
+ }
+
+ List childSpans(long spanId) {
+ return parentChildIdMap.get(spanId);
+ }
+
+ // This method only works for matching call stacks with traces which have children of distinct
+ // type at all levels. This is good enough as the intention is to validate if the e2e path is
+ // WAI - the intention is not to validate Cloud Trace's correctness w.r.t. durability of all
+ // kinds of traces.
+ boolean containsCallStack(String... callStack) throws RuntimeException {
+ List expectedCallStack = Arrays.asList(callStack);
+ if (expectedCallStack.isEmpty()) {
+ throw new RuntimeException("Input callStack is empty");
+ }
+ return dfsContainsCallStack(rootId, expectedCallStack);
+ }
+
+ // Depth-first check for call stack in the trace
+ private boolean dfsContainsCallStack(long spanId, List expectedCallStack) {
+ logger.info(
+ "span="
+ + spanName(spanId)
+ + ", expectedCallStack[0]="
+ + (expectedCallStack.isEmpty() ? "null" : expectedCallStack.get(0)));
+ if (expectedCallStack.isEmpty()) {
+ return false;
+ }
+ if (spanName(spanId).equals(expectedCallStack.get(0))) {
+ // Recursion termination
+ if (childSpans(spanId) == null) {
+ logger.info("No more children for " + spanName(spanId));
+ return expectedCallStack.size() <= 1;
+ } else {
+ // Examine the child spans
+ for (Long childSpan : childSpans(spanId)) {
+ int callStackListSize = expectedCallStack.size();
+ logger.info(
+ "childSpan="
+ + spanName(childSpan)
+ + ", expectedCallStackSize="
+ + callStackListSize);
+ if (dfsContainsCallStack(
+ childSpan,
+ expectedCallStack.subList(
+ /*fromIndexInclusive=*/ 1, /*toIndexExclusive*/ callStackListSize))) {
+ return true;
+ }
+ }
+ }
+ } else {
+ logger.info(spanName(spanId) + " didn't match " + expectedCallStack.get(0));
+ }
+ return false;
+ }
+ }
+
+ private static final Logger logger = Logger.getLogger(ITE2ETracingTest.class.getName());
+
+ private static final String RUN_AGGREGATION_QUERY_RPC_NAME = "RunAggregationQuery";
+
+ private static final String RUN_QUERY_RPC_NAME = "RunQuery";
+
+ private static final int NUM_TRACE_ID_BYTES = 32;
+
+ private static final int NUM_SPAN_ID_BYTES = 16;
+
+ private static final int GET_TRACE_RETRY_COUNT = 60;
+
+ private static final int GET_TRACE_RETRY_BACKOFF_MILLIS = 1000;
+
+ private static final int TRACE_FORCE_FLUSH_MILLIS = 5000;
+
+ private static final int TRACE_PROVIDER_SHUTDOWN_MILLIS = 1000;
+
+ private static Key KEY1;
+
+ // Random int generator for trace ID and span ID
+ private static Random random;
+
+ private static TraceExporter traceExporter;
+
+ // Required for reading back traces from Cloud Trace for validation
+ private static TraceServiceClient traceClient_v1;
+
+ // Custom SpanContext for each test, required for TraceID injection
+ private static SpanContext customSpanContext;
+
+ // Trace read back from Cloud Trace using traceClient_v1 for verification
+ private static Trace retrievedTrace;
+
+ private static String rootSpanName;
+ private static Tracer tracer;
+
+ // Required to set custom-root span
+ private static OpenTelemetrySdk openTelemetrySdk;
+
+ private static String projectId;
+
+ private static DatastoreOptions options;
+
+ private static Datastore datastore;
+
+ @TestParameter boolean useGlobalOpenTelemetrySDK;
+
+ @TestParameter({"default", "test-db"})
+ String datastoreNamedDatabase;
+
+ @BeforeClass
+ public static void setup() throws IOException {
+ projectId = DatastoreOptions.getDefaultProjectId();
+ traceExporter =
+ TraceExporter.createWithConfiguration(
+ TraceConfiguration.builder().setProjectId(projectId).build());
+ traceClient_v1 = TraceServiceClient.create();
+ random = new Random();
+ }
+
+ @Before
+ public void before() throws Exception {
+ // Set up OTel SDK
+ Resource resource =
+ Resource.getDefault().merge(Resource.builder().put(SERVICE_NAME, "Sparky").build());
+
+ if (isUsingGlobalOpenTelemetrySDK()) {
+ openTelemetrySdk =
+ OpenTelemetrySdk.builder()
+ .setTracerProvider(
+ SdkTracerProvider.builder()
+ .setResource(resource)
+ .addSpanProcessor(BatchSpanProcessor.builder(traceExporter).build())
+ .setSampler(Sampler.alwaysOn())
+ .build())
+ .buildAndRegisterGlobal();
+ } else {
+ openTelemetrySdk =
+ OpenTelemetrySdk.builder()
+ .setTracerProvider(
+ SdkTracerProvider.builder()
+ .setResource(resource)
+ .addSpanProcessor(BatchSpanProcessor.builder(traceExporter).build())
+ .setSampler(Sampler.alwaysOn())
+ .build())
+ .build();
+ }
+
+ // Initialize the Datastore DB w/ the OTel SDK. Ideally we'd do this is the @BeforeAll method
+ // but because gRPC traces need to be deterministically force-flushed for every test
+ String namedDb = datastoreNamedDatabase();
+ logger.log(Level.INFO, "Integration test using named database " + namedDb);
+ RemoteDatastoreHelper remoteDatastoreHelper =
+ RemoteDatastoreHelper.create(namedDb, openTelemetrySdk);
+ options = remoteDatastoreHelper.getOptions();
+ datastore = options.getService();
+
+ Preconditions.checkNotNull(
+ datastore,
+ "Error instantiating Datastore. Check that the service account credentials "
+ + "were properly set.");
+
+ String projectId = options.getProjectId();
+ String kind1 = "kind1";
+ KEY1 = Key.newBuilder(projectId, kind1, "name", options.getDatabaseId()).build();
+
+ // Set up the tracer for custom TraceID injection
+ rootSpanName =
+ String.format("%s%d", this.getClass().getSimpleName(), System.currentTimeMillis());
+ if (isUsingGlobalOpenTelemetrySDK()) {
+ tracer = GlobalOpenTelemetry.getTracer(rootSpanName);
+ } else {
+ tracer =
+ datastore
+ .getOptions()
+ .getOpenTelemetryOptions()
+ .getOpenTelemetry()
+ .getTracer(rootSpanName);
+ }
+
+ // Get up a new SpanContext (ergo TraceId) for each test
+ customSpanContext = getNewSpanContext();
+ assertNotNull(customSpanContext);
+ assertNull(retrievedTrace);
+ }
+
+ @After
+ public void after() throws Exception {
+ if (isUsingGlobalOpenTelemetrySDK()) {
+ GlobalOpenTelemetry.resetForTest();
+ }
+ rootSpanName = null;
+ tracer = null;
+ retrievedTrace = null;
+ customSpanContext = null;
+ }
+
+ @AfterClass
+ public static void teardown() throws Exception {
+ traceClient_v1.close();
+ CompletableResultCode completableResultCode =
+ openTelemetrySdk.getSdkTracerProvider().shutdown();
+ completableResultCode.join(TRACE_PROVIDER_SHUTDOWN_MILLIS, TimeUnit.MILLISECONDS);
+ }
+
+ // Generates a random hex string of length `numBytes`
+ private String generateRandomHexString(int numBytes) {
+ StringBuilder newTraceId = new StringBuilder();
+ while (newTraceId.length() < numBytes) {
+ newTraceId.append(Integer.toHexString(random.nextInt()));
+ }
+ return newTraceId.substring(0, numBytes);
+ }
+
+ protected String generateNewTraceId() {
+ return generateRandomHexString(NUM_TRACE_ID_BYTES);
+ }
+
+ // Generates a random 16-byte hex string
+ protected String generateNewSpanId() {
+ return generateRandomHexString(NUM_SPAN_ID_BYTES);
+ }
+
+ // Generates a new SpanContext w/ random traceId,spanId
+ protected SpanContext getNewSpanContext() {
+ String traceId = generateNewTraceId();
+ String spanId = generateNewSpanId();
+ logger.info("traceId=" + traceId + ", spanId=" + spanId);
+
+ return SpanContext.create(traceId, spanId, TraceFlags.getSampled(), TraceState.getDefault());
+ }
+
+ protected Span getNewRootSpanWithContext() {
+ // Execute the DB operation in the context of the custom root span.
+ return tracer
+ .spanBuilder(rootSpanName)
+ .setParent(Context.root().with(Span.wrap(customSpanContext)))
+ .startSpan();
+ }
+
+ protected void waitForTracesToComplete() throws Exception {
+ logger.info("Flushing traces...");
+ CompletableResultCode completableResultCode =
+ openTelemetrySdk.getSdkTracerProvider().forceFlush();
+ completableResultCode.join(TRACE_FORCE_FLUSH_MILLIS, TimeUnit.MILLISECONDS);
+ }
+
+ // Validates `retrievedTrace`. Cloud Trace indexes traces w/ eventual consistency, even when
+ // indexing traceId, therefore the test must retry a few times before the complete trace is
+ // available.
+ // For Transaction traces, there may be more spans than in the trace than specified in
+ // `callStack`. So `numExpectedSpans` is the expected total number of spans (and not just the
+ // spans in `callStack`)
+ protected void fetchAndValidateTrace(
+ String traceId, int numExpectedSpans, List> callStackList)
+ throws InterruptedException {
+ // Large enough count to accommodate eventually consistent Cloud Trace backend
+ int numRetries = GET_TRACE_RETRY_COUNT;
+ // Account for rootSpanName
+ numExpectedSpans++;
+
+ // Fetch traces
+ do {
+ try {
+ retrievedTrace = traceClient_v1.getTrace(projectId, traceId);
+ assertEquals(traceId, retrievedTrace.getTraceId());
+
+ logger.info(
+ "expectedSpanCount="
+ + numExpectedSpans
+ + ", retrievedSpanCount="
+ + retrievedTrace.getSpansCount());
+ } catch (NotFoundException notFound) {
+ logger.info("Trace not found, retrying in " + GET_TRACE_RETRY_BACKOFF_MILLIS + " ms");
+ } catch (IndexOutOfBoundsException outOfBoundsException) {
+ logger.info("Call stack not found in trace. Retrying.");
+ }
+ if (retrievedTrace == null || numExpectedSpans != retrievedTrace.getSpansCount()) {
+ Thread.sleep(GET_TRACE_RETRY_BACKOFF_MILLIS);
+ }
+ } while (numRetries-- > 0
+ && (retrievedTrace == null || numExpectedSpans != retrievedTrace.getSpansCount()));
+
+ if (retrievedTrace == null || numExpectedSpans != retrievedTrace.getSpansCount()) {
+ throw new RuntimeException(
+ "Expected number of spans: "
+ + numExpectedSpans
+ + ", Actual number of spans: "
+ + (retrievedTrace != null
+ ? retrievedTrace.getSpansList().toString()
+ : "Trace NOT_FOUND"));
+ }
+
+ TraceContainer traceContainer = new TraceContainer(rootSpanName, retrievedTrace);
+
+ for (List callStack : callStackList) {
+ // Update all call stacks to be rooted at rootSpanName
+ ArrayList expectedCallStack = new ArrayList<>(callStack);
+
+ // numExpectedSpans should account for rootSpanName (not passed in callStackList)
+ expectedCallStack.add(0, rootSpanName);
+
+ // *May be* the full trace was returned
+ logger.info("Checking if TraceContainer contains the callStack");
+ String[] expectedCallList = new String[expectedCallStack.size()];
+ if (!traceContainer.containsCallStack(expectedCallStack.toArray(expectedCallList))) {
+ throw new RuntimeException(
+ "Expected spans: "
+ + Arrays.toString(expectedCallList)
+ + ", Actual spans: "
+ + (retrievedTrace != null
+ ? retrievedTrace.getSpansList().toString()
+ : "Trace NOT_FOUND"));
+ }
+ logger.severe("CallStack not found in TraceContainer.");
+ }
+ }
+
+ // Validates `retrievedTrace`. Cloud Trace indexes traces w/ eventual consistency, even when
+ // indexing traceId, therefore the test must retry a few times before the complete trace is
+ // available.
+ // For Non-Transaction traces, there is a 1:1 ratio of spans in `spanNames` and in the trace.
+ protected void fetchAndValidateTrace(String traceId, String... spanNames)
+ throws InterruptedException {
+ fetchAndValidateTrace(traceId, spanNames.length, Arrays.asList(Arrays.asList(spanNames)));
+ }
+
+ @Test
+ public void traceContainerTest() throws Exception {
+ // Make sure the test has a new SpanContext (and TraceId for injection)
+ assertNotNull(customSpanContext);
+
+ // Inject new trace ID
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ Entity entity = datastore.get(KEY1);
+ assertNull(entity);
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ Trace traceResp = null;
+ int expectedSpanCount = 2;
+
+ int numRetries = GET_TRACE_RETRY_COUNT;
+ do {
+ try {
+ traceResp = traceClient_v1.getTrace(projectId, customSpanContext.getTraceId());
+ if (traceResp.getSpansCount() == expectedSpanCount) {
+ logger.info("Success: Got " + expectedSpanCount + " spans.");
+ break;
+ }
+ } catch (NotFoundException notFoundException) {
+ Thread.sleep(GET_TRACE_RETRY_BACKOFF_MILLIS);
+ logger.info("Trace not found, retrying in " + GET_TRACE_RETRY_BACKOFF_MILLIS + " ms");
+ }
+ logger.info(
+ "Trace Found. The trace did not contain "
+ + expectedSpanCount
+ + " spans. Going to retry.");
+ numRetries--;
+ } while (numRetries > 0);
+
+ // Make sure we got as many spans as we expected.
+ assertNotNull(traceResp);
+ assertEquals(expectedSpanCount, traceResp.getSpansCount());
+
+ TraceContainer traceCont = new TraceContainer(rootSpanName, traceResp);
+
+ // Contains exact path
+ assertTrue(traceCont.containsCallStack(rootSpanName, SPAN_NAME_LOOKUP));
+
+ // Top-level mismatch
+ assertFalse(traceCont.containsCallStack(SPAN_NAME_LOOKUP, RUN_QUERY_RPC_NAME));
+
+ // Leaf-level mismatch/missing
+ assertFalse(
+ traceCont.containsCallStack(
+ rootSpanName, SPAN_NAME_LOOKUP, RUN_AGGREGATION_QUERY_RPC_NAME));
+ }
+
+ @Test
+ public void lookupTraceTest() throws Exception {
+ // Make sure the test has a new SpanContext (and TraceId for injection)
+ assertNotNull(customSpanContext);
+
+ // Inject new trace ID
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ Entity entity = datastore.get(KEY1);
+ assertNull(entity);
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_LOOKUP);
+ }
+}
From 052adf7b1aa5820fce423d453d85480f41e497fe Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Mon, 20 May 2024 11:13:55 -0700
Subject: [PATCH 03/38] feat: Adding Commit RPC Trace Instrumentation (#1440)
- Added end-to-end test for Datastore operationsput, add, update and delete.
- Updated E2E Test to use the namespace correctly for efficient clean-up of test data
---
.../google/cloud/datastore/DatastoreImpl.java | 11 +-
.../cloud/datastore/telemetry/TraceUtil.java | 3 +
.../cloud/datastore/it/ITE2ETracingTest.java | 109 +++++++++++++++++-
3 files changed, 115 insertions(+), 8 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index 401e3ed54..cb60685c7 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -619,8 +619,11 @@ private com.google.datastore.v1.CommitResponse commitMutation(
com.google.datastore.v1.CommitResponse commit(
final com.google.datastore.v1.CommitRequest requestPb) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_COMMIT);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT);
+ span.setAttribute("isTransactional", requestPb.hasTransaction());
+
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
() -> datastoreRpc.commit(requestPb),
retrySettings,
@@ -629,10 +632,10 @@ com.google.datastore.v1.CommitResponse commit(
: TRANSACTION_OPERATION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index c867a5525..fe4effb1d 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -33,6 +33,9 @@ public interface TraceUtil {
static final String LIBRARY_NAME = "com.google.cloud.datastore";
static final String SPAN_NAME_LOOKUP = "Lookup";
+
+ static final String SPAN_NAME_COMMIT = "Commit";
+
/**
* Creates and returns an instance of the TraceUtil class.
*
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 24a9a7149..2fb139289 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -16,6 +16,7 @@
package com.google.cloud.datastore.it;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
@@ -207,6 +208,8 @@ private boolean dfsContainsCallStack(long spanId, List expectedCallStack
private static Key KEY1;
+ private static Key KEY2;
+
// Random int generator for trace ID and span ID
private static Random random;
@@ -233,9 +236,15 @@ private boolean dfsContainsCallStack(long spanId, List expectedCallStack
private static Datastore datastore;
+ private static RemoteDatastoreHelper remoteDatastoreHelper;
+
@TestParameter boolean useGlobalOpenTelemetrySDK;
- @TestParameter({"default", "test-db"})
+ @TestParameter({
+ /*(default)*/
+ "",
+ "test-db"
+ })
String datastoreNamedDatabase;
@BeforeClass
@@ -280,8 +289,7 @@ public void before() throws Exception {
// but because gRPC traces need to be deterministically force-flushed for every test
String namedDb = datastoreNamedDatabase();
logger.log(Level.INFO, "Integration test using named database " + namedDb);
- RemoteDatastoreHelper remoteDatastoreHelper =
- RemoteDatastoreHelper.create(namedDb, openTelemetrySdk);
+ remoteDatastoreHelper = RemoteDatastoreHelper.create(namedDb, openTelemetrySdk);
options = remoteDatastoreHelper.getOptions();
datastore = options.getService();
@@ -292,7 +300,14 @@ public void before() throws Exception {
String projectId = options.getProjectId();
String kind1 = "kind1";
- KEY1 = Key.newBuilder(projectId, kind1, "name", options.getDatabaseId()).build();
+ KEY1 =
+ Key.newBuilder(projectId, kind1, "name1", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
+ KEY2 =
+ Key.newBuilder(projectId, kind1, "name2", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
// Set up the tracer for custom TraceID injection
rootSpanName =
@@ -319,6 +334,7 @@ public void after() throws Exception {
if (isUsingGlobalOpenTelemetrySDK()) {
GlobalOpenTelemetry.resetForTest();
}
+ remoteDatastoreHelper.deleteNamespace();
rootSpanName = null;
tracer = null;
retrievedTrace = null;
@@ -527,4 +543,89 @@ public void lookupTraceTest() throws Exception {
fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_LOOKUP);
}
+
+ @Test
+ public void commitTraceTest() throws Exception {
+ assertNotNull(customSpanContext);
+
+ Span rootSpan = getNewRootSpanWithContext();
+
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ Entity response = datastore.add(entity1);
+ assertEquals(entity1, response);
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
+ }
+
+ @Test
+ public void putTraceTest() throws Exception {
+ assertNotNull(customSpanContext);
+
+ Span rootSpan = getNewRootSpanWithContext();
+
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ Entity response = datastore.put(entity1);
+ assertEquals(entity1, response);
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
+ }
+
+ @Test
+ public void updateTraceTest() throws Exception {
+ assertNotNull(customSpanContext);
+
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ Span rootSpan = getNewRootSpanWithContext();
+
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ Entity entity1_update =
+ Entity.newBuilder(entity1).set("test_field", "new_test_value1").build();
+ Entity entity2_update =
+ Entity.newBuilder(entity2).set("test_field", "new_test_value1").build();
+ datastore.update(entity1_update, entity2_update);
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
+ }
+
+ @Test
+ public void deleteTraceTest() throws Exception {
+ assertNotNull(customSpanContext);
+
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
+ Entity response = datastore.put(entity1);
+ assertEquals(entity1, response);
+
+ Span rootSpan = getNewRootSpanWithContext();
+
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ datastore.delete(entity1.getKey());
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
+ }
}
From f29a1cd95a9d69c736cf8c5961cd17e5cb11c0e8 Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Thu, 23 May 2024 10:15:00 -0700
Subject: [PATCH 04/38] feat: RunQuery trace instrumentation (#1441)
* feat: RunQuery trace instrumentation
---
.../google/cloud/datastore/DatastoreImpl.java | 37 ++++++++++++------
.../cloud/datastore/telemetry/TraceUtil.java | 3 +-
.../cloud/datastore/it/ITE2ETracingTest.java | 38 +++++++++++++++++--
3 files changed, 61 insertions(+), 17 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index cb60685c7..ebf5aa7e9 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -35,6 +35,7 @@
import com.google.datastore.v1.ExplainOptions;
import com.google.datastore.v1.ReadOptions;
import com.google.datastore.v1.ReserveIdsRequest;
+import com.google.datastore.v1.RunQueryResponse;
import com.google.datastore.v1.TransactionOptions;
import com.google.protobuf.ByteString;
import io.opencensus.common.Scope;
@@ -240,20 +241,34 @@ public AggregationResults runAggregation(
com.google.datastore.v1.RunQueryResponse runQuery(
final com.google.datastore.v1.RunQueryRequest requestPb) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_RUNQUERY);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
- return RetryHelper.runWithRetries(
- () -> datastoreRpc.runQuery(requestPb),
- retrySettings,
- requestPb.getReadOptions().getTransaction().isEmpty()
- ? EXCEPTION_HANDLER
- : TRANSACTION_OPERATION_EXCEPTION_HANDLER,
- getOptions().getClock());
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY);
+ ReadOptions readOptions = requestPb.getReadOptions();
+ span.setAttribute(
+ "isTransactional", readOptions.hasTransaction() || readOptions.hasNewTransaction());
+ span.setAttribute("readConsistency", readOptions.getReadConsistency().toString());
+
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
+ RunQueryResponse response =
+ RetryHelper.runWithRetries(
+ () -> datastoreRpc.runQuery(requestPb),
+ retrySettings,
+ requestPb.getReadOptions().getTransaction().isEmpty()
+ ? EXCEPTION_HANDLER
+ : TRANSACTION_OPERATION_EXCEPTION_HANDLER,
+ getOptions().getClock());
+ span.addEvent(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY + ": Completed",
+ new ImmutableMap.Builder()
+ .put("Received", response.getBatch().getEntityResultsCount())
+ .put("More results", response.getBatch().getMoreResults().toString())
+ .build());
+ return response;
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index fe4effb1d..ccb5cfe7a 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -31,10 +31,9 @@ public interface TraceUtil {
static final String ATTRIBUTE_SERVICE_PREFIX = "gcp.datastore.";
static final String ENABLE_TRACING_ENV_VAR = "DATASTORE_ENABLE_TRACING";
static final String LIBRARY_NAME = "com.google.cloud.datastore";
-
static final String SPAN_NAME_LOOKUP = "Lookup";
-
static final String SPAN_NAME_COMMIT = "Commit";
+ static final String SPAN_NAME_RUN_QUERY = "RunQuery";
/**
* Creates and returns an instance of the TraceUtil class.
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 2fb139289..0212b5e42 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -18,6 +18,7 @@
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -30,6 +31,9 @@
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Key;
+import com.google.cloud.datastore.Query;
+import com.google.cloud.datastore.QueryResults;
+import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
import com.google.cloud.datastore.testing.RemoteDatastoreHelper;
import com.google.cloud.opentelemetry.trace.TraceConfiguration;
import com.google.cloud.opentelemetry.trace.TraceExporter;
@@ -301,11 +305,11 @@ public void before() throws Exception {
String projectId = options.getProjectId();
String kind1 = "kind1";
KEY1 =
- Key.newBuilder(projectId, kind1, "name1", options.getDatabaseId())
+ Key.newBuilder(projectId, kind1, "key1", options.getDatabaseId())
.setNamespace(options.getNamespace())
.build();
KEY2 =
- Key.newBuilder(projectId, kind1, "name2", options.getDatabaseId())
+ Key.newBuilder(projectId, kind1, "key2", options.getDatabaseId())
.setNamespace(options.getNamespace())
.build();
@@ -594,7 +598,6 @@ public void updateTraceTest() throws Exception {
assertEquals(entityList, response);
Span rootSpan = getNewRootSpanWithContext();
-
try (Scope ignored = rootSpan.makeCurrent()) {
Entity entity1_update =
Entity.newBuilder(entity1).set("test_field", "new_test_value1").build();
@@ -625,7 +628,34 @@ public void deleteTraceTest() throws Exception {
rootSpan.end();
}
waitForTracesToComplete();
-
fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
}
+
+ @Test
+ public void runQueryTraceTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
+ Query query =
+ Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
+ QueryResults queryResults = datastore.run(query);
+ assertTrue(queryResults.hasNext());
+ assertEquals(entity1, queryResults.next());
+ assertFalse(queryResults.hasNext());
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_QUERY);
+ }
}
From 931e69c74d29c1722a6ee8f6afb8acc73e9eed37 Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Thu, 23 May 2024 10:46:31 -0700
Subject: [PATCH 05/38] feat: RunAggregationQuery instrumentation (#1447)
* feat: RunQuery trace instrumentation
* Formatting
* Formatting
* Refactor: s/RUNQUERY/RUN_QUERY
* feat: RunAggregationQuery Trace Instrumentation
* Build: retiring test assertions for OpenCensus spans - will be replacing this in hermetic integration tests for OpenTelemetry using in-memory span exports (in addition to ITE2ETraceTest.java).
* Formatting
* Fixing @Test annotation missed after merge
* Formatting
---
.../RetryAndTraceDatastoreRpcDecorator.java | 19 ++---
.../cloud/datastore/telemetry/TraceUtil.java | 1 +
...etryAndTraceDatastoreRpcDecoratorTest.java | 14 +---
.../cloud/datastore/it/ITE2ETracingTest.java | 79 ++++++++++++++++++-
4 files changed, 89 insertions(+), 24 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java
index c4a85caab..ba4adb5ff 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java
@@ -16,7 +16,6 @@
package com.google.cloud.datastore;
import static com.google.cloud.BaseService.EXCEPTION_HANDLER;
-import static com.google.cloud.datastore.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import com.google.api.core.InternalApi;
import com.google.api.gax.retrying.RetrySettings;
@@ -39,9 +38,6 @@
import com.google.datastore.v1.RunAggregationQueryResponse;
import com.google.datastore.v1.RunQueryRequest;
import com.google.datastore.v1.RunQueryResponse;
-import io.opencensus.common.Scope;
-import io.opencensus.trace.Span;
-import io.opencensus.trace.Status;
import java.util.concurrent.Callable;
/**
@@ -52,7 +48,7 @@
public class RetryAndTraceDatastoreRpcDecorator implements DatastoreRpc {
private final DatastoreRpc datastoreRpc;
- private final TraceUtil traceUtil;
+ private final com.google.cloud.datastore.telemetry.TraceUtil otelTraceUtil;
private final RetrySettings retrySettings;
private final DatastoreOptions datastoreOptions;
@@ -62,9 +58,9 @@ public RetryAndTraceDatastoreRpcDecorator(
RetrySettings retrySettings,
DatastoreOptions datastoreOptions) {
this.datastoreRpc = datastoreRpc;
- this.traceUtil = traceUtil;
this.retrySettings = retrySettings;
this.datastoreOptions = datastoreOptions;
+ this.otelTraceUtil = datastoreOptions.getTraceUtil();
}
@Override
@@ -106,19 +102,20 @@ public RunQueryResponse runQuery(RunQueryRequest request) {
@Override
public RunAggregationQueryResponse runAggregationQuery(RunAggregationQueryRequest request) {
return invokeRpc(
- () -> datastoreRpc.runAggregationQuery(request), SPAN_NAME_RUN_AGGREGATION_QUERY);
+ () -> datastoreRpc.runAggregationQuery(request),
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY);
}
public O invokeRpc(Callable block, String startSpan) {
- Span span = traceUtil.startSpan(startSpan);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(startSpan);
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
block, this.retrySettings, EXCEPTION_HANDLER, this.datastoreOptions.getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index ccb5cfe7a..00e9f2376 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -34,6 +34,7 @@ public interface TraceUtil {
static final String SPAN_NAME_LOOKUP = "Lookup";
static final String SPAN_NAME_COMMIT = "Commit";
static final String SPAN_NAME_RUN_QUERY = "RunQuery";
+ static final String SPAN_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
/**
* Creates and returns an instance of the TraceUtil class.
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java
index b86355afa..b01bcab82 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java
@@ -15,11 +15,8 @@
*/
package com.google.cloud.datastore;
-import static com.google.cloud.datastore.TraceUtil.END_SPAN_OPTIONS;
-import static com.google.cloud.datastore.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import static com.google.common.truth.Truth.assertThat;
import static com.google.rpc.Code.UNAVAILABLE;
-import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
@@ -29,8 +26,6 @@
import com.google.cloud.datastore.spi.v1.DatastoreRpc;
import com.google.datastore.v1.RunAggregationQueryRequest;
import com.google.datastore.v1.RunAggregationQueryResponse;
-import io.opencensus.trace.Span;
-import io.opencensus.trace.Tracer;
import org.junit.Before;
import org.junit.Test;
@@ -49,7 +44,6 @@ public class RetryAndTraceDatastoreRpcDecoratorTest {
@Before
public void setUp() throws Exception {
mockDatastoreRpc = createStrictMock(DatastoreRpc.class);
- mockTraceUtil = createStrictMock(TraceUtil.class);
datastoreRpcDecorator =
new RetryAndTraceDatastoreRpcDecorator(
mockDatastoreRpc, mockTraceUtil, retrySettings, datastoreOptions);
@@ -57,7 +51,6 @@ public void setUp() throws Exception {
@Test
public void testRunAggregationQuery() {
- Span mockSpan = createStrictMock(Span.class);
RunAggregationQueryRequest aggregationQueryRequest =
RunAggregationQueryRequest.getDefaultInstance();
RunAggregationQueryResponse aggregationQueryResponse =
@@ -69,16 +62,13 @@ public void testRunAggregationQuery() {
UNAVAILABLE.getNumber(), "API not accessible currently", UNAVAILABLE.name()))
.times(2)
.andReturn(aggregationQueryResponse);
- expect(mockTraceUtil.startSpan(SPAN_NAME_RUN_AGGREGATION_QUERY)).andReturn(mockSpan);
- expect(mockTraceUtil.getTracer()).andReturn(createNiceMock(Tracer.class));
- mockSpan.end(END_SPAN_OPTIONS);
- replay(mockDatastoreRpc, mockTraceUtil, mockSpan);
+ replay(mockDatastoreRpc);
RunAggregationQueryResponse actualAggregationQueryResponse =
datastoreRpcDecorator.runAggregationQuery(aggregationQueryRequest);
assertThat(actualAggregationQueryResponse).isSameInstanceAs(aggregationQueryResponse);
- verify(mockDatastoreRpc, mockTraceUtil, mockSpan);
+ verify(mockDatastoreRpc);
}
}
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 0212b5e42..357e748f1 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -16,9 +16,12 @@
package com.google.cloud.datastore.it;
+import static com.google.cloud.datastore.aggregation.Aggregation.count;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
+import static com.google.common.truth.Truth.assertThat;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -27,12 +30,16 @@
import static org.junit.Assert.assertTrue;
import com.google.api.gax.rpc.NotFoundException;
+import com.google.cloud.datastore.AggregationQuery;
+import com.google.cloud.datastore.AggregationResult;
+import com.google.cloud.datastore.AggregationResults;
import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Key;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.QueryResults;
+import com.google.cloud.datastore.StructuredQuery;
import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
import com.google.cloud.datastore.testing.RemoteDatastoreHelper;
import com.google.cloud.opentelemetry.trace.TraceConfiguration;
@@ -95,6 +102,7 @@
// 5. Traces are read-back using TraceServiceClient and verified against expected Call Stacks.
@RunWith(TestParameterInjector.class)
public class ITE2ETracingTest {
+
protected boolean isUsingGlobalOpenTelemetrySDK() {
return useGlobalOpenTelemetrySDK;
}
@@ -214,6 +222,10 @@ private boolean dfsContainsCallStack(long spanId, List expectedCallStack
private static Key KEY2;
+ private static Key KEY3;
+
+ private static Key KEY4;
+
// Random int generator for trace ID and span ID
private static Random random;
@@ -309,10 +321,17 @@ public void before() throws Exception {
.setNamespace(options.getNamespace())
.build();
KEY2 =
+ Key.newBuilder(projectId, kind1, "key3", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
+ KEY3 =
+ Key.newBuilder(projectId, kind1, "key4", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
+ KEY4 =
Key.newBuilder(projectId, kind1, "key2", options.getDatabaseId())
.setNamespace(options.getNamespace())
.build();
-
// Set up the tracer for custom TraceID injection
rootSpanName =
String.format("%s%d", this.getClass().getSimpleName(), System.currentTimeMillis());
@@ -658,4 +677,62 @@ public void runQueryTraceTest() throws Exception {
fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_QUERY);
}
+
+ @Test
+ public void runAggregationQueryTraceTest() throws Exception {
+ Entity entity1 =
+ Entity.newBuilder(KEY1)
+ .set("pepper_name", "jalapeno")
+ .set("max_scoville_level", 10000)
+ .build();
+ Entity entity2 =
+ Entity.newBuilder(KEY2)
+ .set("pepper_name", "serrano")
+ .set("max_scoville_level", 25000)
+ .build();
+ Entity entity3 =
+ Entity.newBuilder(KEY3)
+ .set("pepper_name", "habanero")
+ .set("max_scoville_level", 350000)
+ .build();
+ Entity entity4 =
+ Entity.newBuilder(KEY4)
+ .set("pepper_name", "ghost")
+ .set("max_scoville_level", 1500000)
+ .build();
+
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+ entityList.add(entity3);
+ entityList.add(entity4);
+
+ List response = datastore.add(entity1, entity2, entity3, entity4);
+ assertEquals(entityList, response);
+
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ PropertyFilter mediumSpicyFilters = PropertyFilter.lt("max_scoville_level", 100000);
+ StructuredQuery mediumSpicyQuery =
+ Query.newEntityQueryBuilder()
+ .setKind(KEY1.getKind())
+ .setFilter(mediumSpicyFilters)
+ .build();
+ AggregationQuery countSpicyPeppers =
+ Query.newAggregationQueryBuilder()
+ .addAggregation(count().as("count"))
+ .over(mediumSpicyQuery)
+ .build();
+ AggregationResults results = datastore.runAggregation(countSpicyPeppers);
+ assertThat(results.size()).isEqualTo(1);
+ AggregationResult result = results.get(0);
+ assertThat(result.getLong("count")).isEqualTo(2L);
+ } finally {
+ rootSpan.end();
+ }
+
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_AGGREGATION_QUERY);
+ }
}
From d40e9e3a190dd97d36ce2b9feff72b1f79d2b0bf Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Wed, 15 May 2024 16:25:18 -0700
Subject: [PATCH 06/38] feat: RunQuery trace instrumentation
---
.../google/cloud/datastore/DatastoreImpl.java | 48 ++--
.../cloud/datastore/telemetry/TraceUtil.java | 5 +-
.../cloud/datastore/it/ITE2ETracingTest.java | 218 +-----------------
3 files changed, 21 insertions(+), 250 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index ebf5aa7e9..401e3ed54 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -35,7 +35,6 @@
import com.google.datastore.v1.ExplainOptions;
import com.google.datastore.v1.ReadOptions;
import com.google.datastore.v1.ReserveIdsRequest;
-import com.google.datastore.v1.RunQueryResponse;
import com.google.datastore.v1.TransactionOptions;
import com.google.protobuf.ByteString;
import io.opencensus.common.Scope;
@@ -241,34 +240,20 @@ public AggregationResults runAggregation(
com.google.datastore.v1.RunQueryResponse runQuery(
final com.google.datastore.v1.RunQueryRequest requestPb) {
- com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY);
- ReadOptions readOptions = requestPb.getReadOptions();
- span.setAttribute(
- "isTransactional", readOptions.hasTransaction() || readOptions.hasNewTransaction());
- span.setAttribute("readConsistency", readOptions.getReadConsistency().toString());
-
- try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
- RunQueryResponse response =
- RetryHelper.runWithRetries(
- () -> datastoreRpc.runQuery(requestPb),
- retrySettings,
- requestPb.getReadOptions().getTransaction().isEmpty()
- ? EXCEPTION_HANDLER
- : TRANSACTION_OPERATION_EXCEPTION_HANDLER,
- getOptions().getClock());
- span.addEvent(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY + ": Completed",
- new ImmutableMap.Builder()
- .put("Received", response.getBatch().getEntityResultsCount())
- .put("More results", response.getBatch().getMoreResults().toString())
- .build());
- return response;
+ Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_RUNQUERY);
+ try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ return RetryHelper.runWithRetries(
+ () -> datastoreRpc.runQuery(requestPb),
+ retrySettings,
+ requestPb.getReadOptions().getTransaction().isEmpty()
+ ? EXCEPTION_HANDLER
+ : TRANSACTION_OPERATION_EXCEPTION_HANDLER,
+ getOptions().getClock());
} catch (RetryHelperException e) {
- span.end(e);
+ span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end();
+ span.end(TraceUtil.END_SPAN_OPTIONS);
}
}
@@ -634,11 +619,8 @@ private com.google.datastore.v1.CommitResponse commitMutation(
com.google.datastore.v1.CommitResponse commit(
final com.google.datastore.v1.CommitRequest requestPb) {
- com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT);
- span.setAttribute("isTransactional", requestPb.hasTransaction());
-
- try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
+ Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_COMMIT);
+ try (Scope scope = traceUtil.getTracer().withSpan(span)) {
return RetryHelper.runWithRetries(
() -> datastoreRpc.commit(requestPb),
retrySettings,
@@ -647,10 +629,10 @@ com.google.datastore.v1.CommitResponse commit(
: TRANSACTION_OPERATION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.end(e);
+ span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end();
+ span.end(TraceUtil.END_SPAN_OPTIONS);
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index 00e9f2376..c867a5525 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -31,11 +31,8 @@ public interface TraceUtil {
static final String ATTRIBUTE_SERVICE_PREFIX = "gcp.datastore.";
static final String ENABLE_TRACING_ENV_VAR = "DATASTORE_ENABLE_TRACING";
static final String LIBRARY_NAME = "com.google.cloud.datastore";
- static final String SPAN_NAME_LOOKUP = "Lookup";
- static final String SPAN_NAME_COMMIT = "Commit";
- static final String SPAN_NAME_RUN_QUERY = "RunQuery";
- static final String SPAN_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
+ static final String SPAN_NAME_LOOKUP = "Lookup";
/**
* Creates and returns an instance of the TraceUtil class.
*
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 357e748f1..24a9a7149 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -16,12 +16,7 @@
package com.google.cloud.datastore.it;
-import static com.google.cloud.datastore.aggregation.Aggregation.count;
-import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
-import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
-import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
-import static com.google.common.truth.Truth.assertThat;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -30,17 +25,10 @@
import static org.junit.Assert.assertTrue;
import com.google.api.gax.rpc.NotFoundException;
-import com.google.cloud.datastore.AggregationQuery;
-import com.google.cloud.datastore.AggregationResult;
-import com.google.cloud.datastore.AggregationResults;
import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Key;
-import com.google.cloud.datastore.Query;
-import com.google.cloud.datastore.QueryResults;
-import com.google.cloud.datastore.StructuredQuery;
-import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
import com.google.cloud.datastore.testing.RemoteDatastoreHelper;
import com.google.cloud.opentelemetry.trace.TraceConfiguration;
import com.google.cloud.opentelemetry.trace.TraceExporter;
@@ -102,7 +90,6 @@
// 5. Traces are read-back using TraceServiceClient and verified against expected Call Stacks.
@RunWith(TestParameterInjector.class)
public class ITE2ETracingTest {
-
protected boolean isUsingGlobalOpenTelemetrySDK() {
return useGlobalOpenTelemetrySDK;
}
@@ -220,12 +207,6 @@ private boolean dfsContainsCallStack(long spanId, List expectedCallStack
private static Key KEY1;
- private static Key KEY2;
-
- private static Key KEY3;
-
- private static Key KEY4;
-
// Random int generator for trace ID and span ID
private static Random random;
@@ -252,15 +233,9 @@ private boolean dfsContainsCallStack(long spanId, List expectedCallStack
private static Datastore datastore;
- private static RemoteDatastoreHelper remoteDatastoreHelper;
-
@TestParameter boolean useGlobalOpenTelemetrySDK;
- @TestParameter({
- /*(default)*/
- "",
- "test-db"
- })
+ @TestParameter({"default", "test-db"})
String datastoreNamedDatabase;
@BeforeClass
@@ -305,7 +280,8 @@ public void before() throws Exception {
// but because gRPC traces need to be deterministically force-flushed for every test
String namedDb = datastoreNamedDatabase();
logger.log(Level.INFO, "Integration test using named database " + namedDb);
- remoteDatastoreHelper = RemoteDatastoreHelper.create(namedDb, openTelemetrySdk);
+ RemoteDatastoreHelper remoteDatastoreHelper =
+ RemoteDatastoreHelper.create(namedDb, openTelemetrySdk);
options = remoteDatastoreHelper.getOptions();
datastore = options.getService();
@@ -316,22 +292,8 @@ public void before() throws Exception {
String projectId = options.getProjectId();
String kind1 = "kind1";
- KEY1 =
- Key.newBuilder(projectId, kind1, "key1", options.getDatabaseId())
- .setNamespace(options.getNamespace())
- .build();
- KEY2 =
- Key.newBuilder(projectId, kind1, "key3", options.getDatabaseId())
- .setNamespace(options.getNamespace())
- .build();
- KEY3 =
- Key.newBuilder(projectId, kind1, "key4", options.getDatabaseId())
- .setNamespace(options.getNamespace())
- .build();
- KEY4 =
- Key.newBuilder(projectId, kind1, "key2", options.getDatabaseId())
- .setNamespace(options.getNamespace())
- .build();
+ KEY1 = Key.newBuilder(projectId, kind1, "name", options.getDatabaseId()).build();
+
// Set up the tracer for custom TraceID injection
rootSpanName =
String.format("%s%d", this.getClass().getSimpleName(), System.currentTimeMillis());
@@ -357,7 +319,6 @@ public void after() throws Exception {
if (isUsingGlobalOpenTelemetrySDK()) {
GlobalOpenTelemetry.resetForTest();
}
- remoteDatastoreHelper.deleteNamespace();
rootSpanName = null;
tracer = null;
retrievedTrace = null;
@@ -566,173 +527,4 @@ public void lookupTraceTest() throws Exception {
fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_LOOKUP);
}
-
- @Test
- public void commitTraceTest() throws Exception {
- assertNotNull(customSpanContext);
-
- Span rootSpan = getNewRootSpanWithContext();
-
- Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
- try (Scope ignored = rootSpan.makeCurrent()) {
- Entity response = datastore.add(entity1);
- assertEquals(entity1, response);
- } finally {
- rootSpan.end();
- }
- waitForTracesToComplete();
-
- fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
- }
-
- @Test
- public void putTraceTest() throws Exception {
- assertNotNull(customSpanContext);
-
- Span rootSpan = getNewRootSpanWithContext();
-
- Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
- try (Scope ignored = rootSpan.makeCurrent()) {
- Entity response = datastore.put(entity1);
- assertEquals(entity1, response);
- } finally {
- rootSpan.end();
- }
- waitForTracesToComplete();
-
- fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
- }
-
- @Test
- public void updateTraceTest() throws Exception {
- assertNotNull(customSpanContext);
-
- Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
- Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
- List entityList = new ArrayList<>();
- entityList.add(entity1);
- entityList.add(entity2);
-
- List response = datastore.add(entity1, entity2);
- assertEquals(entityList, response);
-
- Span rootSpan = getNewRootSpanWithContext();
- try (Scope ignored = rootSpan.makeCurrent()) {
- Entity entity1_update =
- Entity.newBuilder(entity1).set("test_field", "new_test_value1").build();
- Entity entity2_update =
- Entity.newBuilder(entity2).set("test_field", "new_test_value1").build();
- datastore.update(entity1_update, entity2_update);
- } finally {
- rootSpan.end();
- }
- waitForTracesToComplete();
-
- fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
- }
-
- @Test
- public void deleteTraceTest() throws Exception {
- assertNotNull(customSpanContext);
-
- Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
- Entity response = datastore.put(entity1);
- assertEquals(entity1, response);
-
- Span rootSpan = getNewRootSpanWithContext();
-
- try (Scope ignored = rootSpan.makeCurrent()) {
- datastore.delete(entity1.getKey());
- } finally {
- rootSpan.end();
- }
- waitForTracesToComplete();
- fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
- }
-
- @Test
- public void runQueryTraceTest() throws Exception {
- Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
- Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
- List entityList = new ArrayList<>();
- entityList.add(entity1);
- entityList.add(entity2);
-
- List response = datastore.add(entity1, entity2);
- assertEquals(entityList, response);
-
- Span rootSpan = getNewRootSpanWithContext();
- try (Scope ignored = rootSpan.makeCurrent()) {
- PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
- Query query =
- Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
- QueryResults queryResults = datastore.run(query);
- assertTrue(queryResults.hasNext());
- assertEquals(entity1, queryResults.next());
- assertFalse(queryResults.hasNext());
- } finally {
- rootSpan.end();
- }
- waitForTracesToComplete();
-
- fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_QUERY);
- }
-
- @Test
- public void runAggregationQueryTraceTest() throws Exception {
- Entity entity1 =
- Entity.newBuilder(KEY1)
- .set("pepper_name", "jalapeno")
- .set("max_scoville_level", 10000)
- .build();
- Entity entity2 =
- Entity.newBuilder(KEY2)
- .set("pepper_name", "serrano")
- .set("max_scoville_level", 25000)
- .build();
- Entity entity3 =
- Entity.newBuilder(KEY3)
- .set("pepper_name", "habanero")
- .set("max_scoville_level", 350000)
- .build();
- Entity entity4 =
- Entity.newBuilder(KEY4)
- .set("pepper_name", "ghost")
- .set("max_scoville_level", 1500000)
- .build();
-
- List entityList = new ArrayList<>();
- entityList.add(entity1);
- entityList.add(entity2);
- entityList.add(entity3);
- entityList.add(entity4);
-
- List response = datastore.add(entity1, entity2, entity3, entity4);
- assertEquals(entityList, response);
-
- Span rootSpan = getNewRootSpanWithContext();
- try (Scope ignored = rootSpan.makeCurrent()) {
- PropertyFilter mediumSpicyFilters = PropertyFilter.lt("max_scoville_level", 100000);
- StructuredQuery mediumSpicyQuery =
- Query.newEntityQueryBuilder()
- .setKind(KEY1.getKind())
- .setFilter(mediumSpicyFilters)
- .build();
- AggregationQuery countSpicyPeppers =
- Query.newAggregationQueryBuilder()
- .addAggregation(count().as("count"))
- .over(mediumSpicyQuery)
- .build();
- AggregationResults results = datastore.runAggregation(countSpicyPeppers);
- assertThat(results.size()).isEqualTo(1);
- AggregationResult result = results.get(0);
- assertThat(result.getLong("count")).isEqualTo(2L);
- } finally {
- rootSpan.end();
- }
-
- waitForTracesToComplete();
-
- fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_AGGREGATION_QUERY);
- }
}
From f981126da7e312aeb061443b886714061de46ddc Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Wed, 15 May 2024 16:38:29 -0700
Subject: [PATCH 07/38] Formatting
---
.../java/com/google/cloud/datastore/telemetry/TraceUtil.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index c867a5525..14d8801fc 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -33,6 +33,9 @@ public interface TraceUtil {
static final String LIBRARY_NAME = "com.google.cloud.datastore";
static final String SPAN_NAME_LOOKUP = "Lookup";
+
+ static final String SPAN_NAME_RUNQUERY = "RunQuery";
+
/**
* Creates and returns an instance of the TraceUtil class.
*
From c38420f6b571eec6004e07761c682fc1afa89fef Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Wed, 15 May 2024 16:39:55 -0700
Subject: [PATCH 08/38] Formatting
---
.../cloud/datastore/it/ITE2ETracingTest.java | 54 +++++++++++++++++--
1 file changed, 50 insertions(+), 4 deletions(-)
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 24a9a7149..d498d38ba 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -17,6 +17,7 @@
package com.google.cloud.datastore.it;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUNQUERY;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -29,6 +30,9 @@
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Key;
+import com.google.cloud.datastore.Query;
+import com.google.cloud.datastore.QueryResults;
+import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
import com.google.cloud.datastore.testing.RemoteDatastoreHelper;
import com.google.cloud.opentelemetry.trace.TraceConfiguration;
import com.google.cloud.opentelemetry.trace.TraceExporter;
@@ -207,6 +211,8 @@ private boolean dfsContainsCallStack(long spanId, List expectedCallStack
private static Key KEY1;
+ private static Key KEY2;
+
// Random int generator for trace ID and span ID
private static Random random;
@@ -233,9 +239,14 @@ private boolean dfsContainsCallStack(long spanId, List expectedCallStack
private static Datastore datastore;
+ private static RemoteDatastoreHelper remoteDatastoreHelper;
+
@TestParameter boolean useGlobalOpenTelemetrySDK;
- @TestParameter({"default", "test-db"})
+ @TestParameter({
+ /*(default)*/
+ "", "test-db"
+ })
String datastoreNamedDatabase;
@BeforeClass
@@ -280,8 +291,7 @@ public void before() throws Exception {
// but because gRPC traces need to be deterministically force-flushed for every test
String namedDb = datastoreNamedDatabase();
logger.log(Level.INFO, "Integration test using named database " + namedDb);
- RemoteDatastoreHelper remoteDatastoreHelper =
- RemoteDatastoreHelper.create(namedDb, openTelemetrySdk);
+ remoteDatastoreHelper = RemoteDatastoreHelper.create(namedDb, openTelemetrySdk);
options = remoteDatastoreHelper.getOptions();
datastore = options.getService();
@@ -292,7 +302,14 @@ public void before() throws Exception {
String projectId = options.getProjectId();
String kind1 = "kind1";
- KEY1 = Key.newBuilder(projectId, kind1, "name", options.getDatabaseId()).build();
+ KEY1 =
+ Key.newBuilder(projectId, kind1, "key1", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
+ KEY2 =
+ Key.newBuilder(projectId, kind1, "key2", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
// Set up the tracer for custom TraceID injection
rootSpanName =
@@ -319,6 +336,7 @@ public void after() throws Exception {
if (isUsingGlobalOpenTelemetrySDK()) {
GlobalOpenTelemetry.resetForTest();
}
+ remoteDatastoreHelper.deleteNamespace();
rootSpanName = null;
tracer = null;
retrievedTrace = null;
@@ -527,4 +545,32 @@ public void lookupTraceTest() throws Exception {
fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_LOOKUP);
}
+
+ @Test
+ public void runQueryTraceTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
+ Query query =
+ Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
+ QueryResults queryResults = datastore.run(query);
+ assertTrue(queryResults.hasNext());
+ assertEquals(entity1, queryResults.next());
+ assertFalse(queryResults.hasNext());
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUNQUERY);
+ }
}
From 43fb599173c08e1080db5ba9ef1d53c0db0ac0e9 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Thu, 16 May 2024 10:49:34 -0700
Subject: [PATCH 09/38] Refactor: s/RUNQUERY/RUN_QUERY
---
.../google/cloud/datastore/DatastoreImpl.java | 37 +++++++++++++------
.../cloud/datastore/telemetry/TraceUtil.java | 2 -
.../cloud/datastore/it/ITE2ETracingTest.java | 4 +-
3 files changed, 28 insertions(+), 15 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index 401e3ed54..cf84d62b6 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -35,6 +35,7 @@
import com.google.datastore.v1.ExplainOptions;
import com.google.datastore.v1.ReadOptions;
import com.google.datastore.v1.ReserveIdsRequest;
+import com.google.datastore.v1.RunQueryResponse;
import com.google.datastore.v1.TransactionOptions;
import com.google.protobuf.ByteString;
import io.opencensus.common.Scope;
@@ -240,20 +241,34 @@ public AggregationResults runAggregation(
com.google.datastore.v1.RunQueryResponse runQuery(
final com.google.datastore.v1.RunQueryRequest requestPb) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_RUNQUERY);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
- return RetryHelper.runWithRetries(
- () -> datastoreRpc.runQuery(requestPb),
- retrySettings,
- requestPb.getReadOptions().getTransaction().isEmpty()
- ? EXCEPTION_HANDLER
- : TRANSACTION_OPERATION_EXCEPTION_HANDLER,
- getOptions().getClock());
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUNQUERY);
+ ReadOptions readOptions = requestPb.getReadOptions();
+ span.setAttribute(
+ "isTransactional", readOptions.hasTransaction() || readOptions.hasNewTransaction());
+ span.setAttribute("readConsistency", readOptions.getReadConsistency().toString());
+
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
+ RunQueryResponse response =
+ RetryHelper.runWithRetries(
+ () -> datastoreRpc.runQuery(requestPb),
+ retrySettings,
+ requestPb.getReadOptions().getTransaction().isEmpty()
+ ? EXCEPTION_HANDLER
+ : TRANSACTION_OPERATION_EXCEPTION_HANDLER,
+ getOptions().getClock());
+ span.addEvent(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUNQUERY + ": Completed",
+ new ImmutableMap.Builder()
+ .put("Received", response.getBatch().getEntityResultsCount())
+ .put("More results", response.getBatch().getMoreResults().toString())
+ .build());
+ return response;
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index 14d8801fc..e59584958 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -31,9 +31,7 @@ public interface TraceUtil {
static final String ATTRIBUTE_SERVICE_PREFIX = "gcp.datastore.";
static final String ENABLE_TRACING_ENV_VAR = "DATASTORE_ENABLE_TRACING";
static final String LIBRARY_NAME = "com.google.cloud.datastore";
-
static final String SPAN_NAME_LOOKUP = "Lookup";
-
static final String SPAN_NAME_RUNQUERY = "RunQuery";
/**
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index d498d38ba..8ce565b1e 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -17,7 +17,7 @@
package com.google.cloud.datastore.it;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
-import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUNQUERY;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -571,6 +571,6 @@ public void runQueryTraceTest() throws Exception {
}
waitForTracesToComplete();
- fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUNQUERY);
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_QUERY);
}
}
From f2999de8de40167c62c0aa99587ae2ef03e12787 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Thu, 16 May 2024 15:14:25 -0700
Subject: [PATCH 10/38] feat: RunAggregationQuery Trace Instrumentation
---
.../cloud/datastore/telemetry/TraceUtil.java | 2 +-
.../cloud/datastore/it/ITE2ETracingTest.java | 79 ++++++++++++++++++-
2 files changed, 79 insertions(+), 2 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index e59584958..5bf505638 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -32,7 +32,7 @@ public interface TraceUtil {
static final String ENABLE_TRACING_ENV_VAR = "DATASTORE_ENABLE_TRACING";
static final String LIBRARY_NAME = "com.google.cloud.datastore";
static final String SPAN_NAME_LOOKUP = "Lookup";
- static final String SPAN_NAME_RUNQUERY = "RunQuery";
+ static final String SPAN_NAME_RUN_QUERY = "RunQuery";
/**
* Creates and returns an instance of the TraceUtil class.
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 8ce565b1e..4b2391725 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -16,8 +16,11 @@
package com.google.cloud.datastore.it;
+import static com.google.cloud.datastore.aggregation.Aggregation.count;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
+import static com.google.common.truth.Truth.assertThat;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -26,12 +29,16 @@
import static org.junit.Assert.assertTrue;
import com.google.api.gax.rpc.NotFoundException;
+import com.google.cloud.datastore.AggregationQuery;
+import com.google.cloud.datastore.AggregationResult;
+import com.google.cloud.datastore.AggregationResults;
import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Key;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.QueryResults;
+import com.google.cloud.datastore.StructuredQuery;
import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
import com.google.cloud.datastore.testing.RemoteDatastoreHelper;
import com.google.cloud.opentelemetry.trace.TraceConfiguration;
@@ -94,6 +101,7 @@
// 5. Traces are read-back using TraceServiceClient and verified against expected Call Stacks.
@RunWith(TestParameterInjector.class)
public class ITE2ETracingTest {
+
protected boolean isUsingGlobalOpenTelemetrySDK() {
return useGlobalOpenTelemetrySDK;
}
@@ -213,6 +221,10 @@ private boolean dfsContainsCallStack(long spanId, List expectedCallStack
private static Key KEY2;
+ private static Key KEY3;
+
+ private static Key KEY4;
+
// Random int generator for trace ID and span ID
private static Random random;
@@ -307,10 +319,17 @@ public void before() throws Exception {
.setNamespace(options.getNamespace())
.build();
KEY2 =
+ Key.newBuilder(projectId, kind1, "key3", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
+ KEY3 =
+ Key.newBuilder(projectId, kind1, "key4", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
+ KEY4 =
Key.newBuilder(projectId, kind1, "key2", options.getDatabaseId())
.setNamespace(options.getNamespace())
.build();
-
// Set up the tracer for custom TraceID injection
rootSpanName =
String.format("%s%d", this.getClass().getSimpleName(), System.currentTimeMillis());
@@ -573,4 +592,62 @@ public void runQueryTraceTest() throws Exception {
fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_QUERY);
}
+
+ @Test
+ public void runAggregationQueryTraceTest() throws Exception {
+ Entity entity1 =
+ Entity.newBuilder(KEY1)
+ .set("pepper_name", "jalapeno")
+ .set("max_scoville_level", 10000)
+ .build();
+ Entity entity2 =
+ Entity.newBuilder(KEY2)
+ .set("pepper_name", "serrano")
+ .set("max_scoville_level", 25000)
+ .build();
+ Entity entity3 =
+ Entity.newBuilder(KEY3)
+ .set("pepper_name", "habanero")
+ .set("max_scoville_level", 350000)
+ .build();
+ Entity entity4 =
+ Entity.newBuilder(KEY4)
+ .set("pepper_name", "ghost")
+ .set("max_scoville_level", 1500000)
+ .build();
+
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+ entityList.add(entity3);
+ entityList.add(entity4);
+
+ List response = datastore.add(entity1, entity2, entity3, entity4);
+ assertEquals(entityList, response);
+
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ PropertyFilter mediumSpicyFilters = PropertyFilter.lt("max_scoville_level", 100000);
+ StructuredQuery mediumSpicyQuery =
+ Query.newEntityQueryBuilder()
+ .setKind(KEY1.getKind())
+ .setFilter(mediumSpicyFilters)
+ .build();
+ AggregationQuery countSpicyPeppers =
+ Query.newAggregationQueryBuilder()
+ .addAggregation(count().as("count"))
+ .over(mediumSpicyQuery)
+ .build();
+ AggregationResults results = datastore.runAggregation(countSpicyPeppers);
+ assertThat(results.size()).isEqualTo(1);
+ AggregationResult result = results.get(0);
+ assertThat(result.getLong("count")).isEqualTo(2L);
+ } finally {
+ rootSpan.end();
+ }
+
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_AGGREGATION_QUERY);
+ }
}
From e2ca6496efe2e2d2e77e9dd32e5c4fac7ce35803 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Thu, 16 May 2024 16:13:14 -0700
Subject: [PATCH 11/38] Build: retiring test assertions for OpenCensus spans -
will be replacing this in hermetic integration tests for OpenTelemetry using
in-memory span exports (in addition to ITE2ETraceTest.java).
---
.../datastore/RetryAndTraceDatastoreRpcDecoratorTest.java | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java
index b01bcab82..13b63a037 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java
@@ -26,6 +26,10 @@
import com.google.cloud.datastore.spi.v1.DatastoreRpc;
import com.google.datastore.v1.RunAggregationQueryRequest;
import com.google.datastore.v1.RunAggregationQueryResponse;
+<<<<<<< HEAD
+=======
+
+>>>>>>> ec777fc (Build: retiring test assertions for OpenCensus spans - will be replacing this in hermetic integration tests for OpenTelemetry using in-memory span exports (in addition to ITE2ETraceTest.java).)
import org.junit.Before;
import org.junit.Test;
From 6dec8c54f7a15d18cbc54332d9ba93f0065291a7 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Fri, 17 May 2024 09:48:52 -0700
Subject: [PATCH 12/38] Formatting
---
...etryAndTraceDatastoreRpcDecoratorTest.java | 78 -------------------
1 file changed, 78 deletions(-)
delete mode 100644 google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java
deleted file mode 100644
index 13b63a037..000000000
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecoratorTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2022 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.cloud.datastore;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.rpc.Code.UNAVAILABLE;
-import static org.easymock.EasyMock.createStrictMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
-
-import com.google.api.gax.retrying.RetrySettings;
-import com.google.cloud.datastore.spi.v1.DatastoreRpc;
-import com.google.datastore.v1.RunAggregationQueryRequest;
-import com.google.datastore.v1.RunAggregationQueryResponse;
-<<<<<<< HEAD
-=======
-
->>>>>>> ec777fc (Build: retiring test assertions for OpenCensus spans - will be replacing this in hermetic integration tests for OpenTelemetry using in-memory span exports (in addition to ITE2ETraceTest.java).)
-import org.junit.Before;
-import org.junit.Test;
-
-public class RetryAndTraceDatastoreRpcDecoratorTest {
-
- public static final int MAX_ATTEMPTS = 3;
- private DatastoreRpc mockDatastoreRpc;
- private TraceUtil mockTraceUtil;
- private DatastoreOptions datastoreOptions =
- DatastoreOptions.newBuilder().setProjectId("project-id").build();
- private RetrySettings retrySettings =
- RetrySettings.newBuilder().setMaxAttempts(MAX_ATTEMPTS).build();
-
- private RetryAndTraceDatastoreRpcDecorator datastoreRpcDecorator;
-
- @Before
- public void setUp() throws Exception {
- mockDatastoreRpc = createStrictMock(DatastoreRpc.class);
- datastoreRpcDecorator =
- new RetryAndTraceDatastoreRpcDecorator(
- mockDatastoreRpc, mockTraceUtil, retrySettings, datastoreOptions);
- }
-
- @Test
- public void testRunAggregationQuery() {
- RunAggregationQueryRequest aggregationQueryRequest =
- RunAggregationQueryRequest.getDefaultInstance();
- RunAggregationQueryResponse aggregationQueryResponse =
- RunAggregationQueryResponse.getDefaultInstance();
-
- expect(mockDatastoreRpc.runAggregationQuery(aggregationQueryRequest))
- .andThrow(
- new DatastoreException(
- UNAVAILABLE.getNumber(), "API not accessible currently", UNAVAILABLE.name()))
- .times(2)
- .andReturn(aggregationQueryResponse);
-
- replay(mockDatastoreRpc);
-
- RunAggregationQueryResponse actualAggregationQueryResponse =
- datastoreRpcDecorator.runAggregationQuery(aggregationQueryRequest);
-
- assertThat(actualAggregationQueryResponse).isSameInstanceAs(aggregationQueryResponse);
- verify(mockDatastoreRpc);
- }
-}
From b3a1506cc4ea852659dce54d8d9bce2e07c16f5f Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Mon, 20 May 2024 11:37:22 -0700
Subject: [PATCH 13/38] Fixing @Test annotation missed after merge
---
.../cloud/datastore/it/ITE2ETracingTest.java | 151 +++++++++---------
1 file changed, 79 insertions(+), 72 deletions(-)
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 4b2391725..f33a7e23a 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -16,11 +16,9 @@
package com.google.cloud.datastore.it;
-import static com.google.cloud.datastore.aggregation.Aggregation.count;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
-import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
-import static com.google.common.truth.Truth.assertThat;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -29,16 +27,12 @@
import static org.junit.Assert.assertTrue;
import com.google.api.gax.rpc.NotFoundException;
-import com.google.cloud.datastore.AggregationQuery;
-import com.google.cloud.datastore.AggregationResult;
-import com.google.cloud.datastore.AggregationResults;
import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Key;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.QueryResults;
-import com.google.cloud.datastore.StructuredQuery;
import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
import com.google.cloud.datastore.testing.RemoteDatastoreHelper;
import com.google.cloud.opentelemetry.trace.TraceConfiguration;
@@ -101,7 +95,6 @@
// 5. Traces are read-back using TraceServiceClient and verified against expected Call Stacks.
@RunWith(TestParameterInjector.class)
public class ITE2ETracingTest {
-
protected boolean isUsingGlobalOpenTelemetrySDK() {
return useGlobalOpenTelemetrySDK;
}
@@ -221,10 +214,6 @@ private boolean dfsContainsCallStack(long spanId, List expectedCallStack
private static Key KEY2;
- private static Key KEY3;
-
- private static Key KEY4;
-
// Random int generator for trace ID and span ID
private static Random random;
@@ -256,8 +245,9 @@ private boolean dfsContainsCallStack(long spanId, List expectedCallStack
@TestParameter boolean useGlobalOpenTelemetrySDK;
@TestParameter({
- /*(default)*/
- "", "test-db"
+ /*(default)*/
+ "",
+ "test-db"
})
String datastoreNamedDatabase;
@@ -319,17 +309,10 @@ public void before() throws Exception {
.setNamespace(options.getNamespace())
.build();
KEY2 =
- Key.newBuilder(projectId, kind1, "key3", options.getDatabaseId())
- .setNamespace(options.getNamespace())
- .build();
- KEY3 =
- Key.newBuilder(projectId, kind1, "key4", options.getDatabaseId())
- .setNamespace(options.getNamespace())
- .build();
- KEY4 =
Key.newBuilder(projectId, kind1, "key2", options.getDatabaseId())
.setNamespace(options.getNamespace())
.build();
+
// Set up the tracer for custom TraceID injection
rootSpanName =
String.format("%s%d", this.getClass().getSimpleName(), System.currentTimeMillis());
@@ -566,7 +549,45 @@ public void lookupTraceTest() throws Exception {
}
@Test
- public void runQueryTraceTest() throws Exception {
+ public void commitTraceTest() throws Exception {
+ assertNotNull(customSpanContext);
+
+ Span rootSpan = getNewRootSpanWithContext();
+
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ Entity response = datastore.add(entity1);
+ assertEquals(entity1, response);
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
+ }
+
+ @Test
+ public void putTraceTest() throws Exception {
+ assertNotNull(customSpanContext);
+
+ Span rootSpan = getNewRootSpanWithContext();
+
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ Entity response = datastore.put(entity1);
+ assertEquals(entity1, response);
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
+ }
+
+ @Test
+ public void updateTraceTest() throws Exception {
+ assertNotNull(customSpanContext);
+
Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
List entityList = new ArrayList<>();
@@ -578,76 +599,62 @@ public void runQueryTraceTest() throws Exception {
Span rootSpan = getNewRootSpanWithContext();
try (Scope ignored = rootSpan.makeCurrent()) {
- PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
- Query query =
- Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
- QueryResults queryResults = datastore.run(query);
- assertTrue(queryResults.hasNext());
- assertEquals(entity1, queryResults.next());
- assertFalse(queryResults.hasNext());
+ Entity entity1_update =
+ Entity.newBuilder(entity1).set("test_field", "new_test_value1").build();
+ Entity entity2_update =
+ Entity.newBuilder(entity2).set("test_field", "new_test_value1").build();
+ datastore.update(entity1_update, entity2_update);
} finally {
rootSpan.end();
}
waitForTracesToComplete();
- fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_QUERY);
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
}
@Test
- public void runAggregationQueryTraceTest() throws Exception {
- Entity entity1 =
- Entity.newBuilder(KEY1)
- .set("pepper_name", "jalapeno")
- .set("max_scoville_level", 10000)
- .build();
- Entity entity2 =
- Entity.newBuilder(KEY2)
- .set("pepper_name", "serrano")
- .set("max_scoville_level", 25000)
- .build();
- Entity entity3 =
- Entity.newBuilder(KEY3)
- .set("pepper_name", "habanero")
- .set("max_scoville_level", 350000)
- .build();
- Entity entity4 =
- Entity.newBuilder(KEY4)
- .set("pepper_name", "ghost")
- .set("max_scoville_level", 1500000)
- .build();
+ public void deleteTraceTest() throws Exception {
+ assertNotNull(customSpanContext);
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
+ Entity response = datastore.put(entity1);
+ assertEquals(entity1, response);
+
+ Span rootSpan = getNewRootSpanWithContext();
+
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ datastore.delete(entity1.getKey());
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
+ }
+
+ public void runQueryTraceTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
List entityList = new ArrayList<>();
entityList.add(entity1);
entityList.add(entity2);
- entityList.add(entity3);
- entityList.add(entity4);
- List response = datastore.add(entity1, entity2, entity3, entity4);
+ List response = datastore.add(entity1, entity2);
assertEquals(entityList, response);
Span rootSpan = getNewRootSpanWithContext();
try (Scope ignored = rootSpan.makeCurrent()) {
- PropertyFilter mediumSpicyFilters = PropertyFilter.lt("max_scoville_level", 100000);
- StructuredQuery mediumSpicyQuery =
- Query.newEntityQueryBuilder()
- .setKind(KEY1.getKind())
- .setFilter(mediumSpicyFilters)
- .build();
- AggregationQuery countSpicyPeppers =
- Query.newAggregationQueryBuilder()
- .addAggregation(count().as("count"))
- .over(mediumSpicyQuery)
- .build();
- AggregationResults results = datastore.runAggregation(countSpicyPeppers);
- assertThat(results.size()).isEqualTo(1);
- AggregationResult result = results.get(0);
- assertThat(result.getLong("count")).isEqualTo(2L);
+ PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
+ Query query =
+ Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
+ QueryResults queryResults = datastore.run(query);
+ assertTrue(queryResults.hasNext());
+ assertEquals(entity1, queryResults.next());
+ assertFalse(queryResults.hasNext());
} finally {
rootSpan.end();
}
-
waitForTracesToComplete();
- fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_AGGREGATION_QUERY);
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_QUERY);
}
}
From 67099d540b7936f81024aabddd7a3ce38d026585 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Mon, 20 May 2024 14:01:37 -0700
Subject: [PATCH 14/38] Formatting
---
.../java/com/google/cloud/datastore/it/ITE2ETracingTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index f33a7e23a..9a4a99106 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -632,7 +632,7 @@ public void deleteTraceTest() throws Exception {
}
public void runQueryTraceTest() throws Exception {
- Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
List entityList = new ArrayList<>();
entityList.add(entity1);
From 895f615e77fef0d61d57535a495add2df76542b9 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Mon, 20 May 2024 17:17:11 -0700
Subject: [PATCH 15/38] feat: Add Transaction tracing test:
transactionalLookupTest
---
.../google/cloud/datastore/DatastoreImpl.java | 15 ++--
.../RetryAndTraceDatastoreRpcDecorator.java | 12 ++-
.../cloud/datastore/telemetry/TraceUtil.java | 2 +
.../cloud/datastore/it/ITE2ETracingTest.java | 80 ++++++++++++++++++-
4 files changed, 99 insertions(+), 10 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index cf84d62b6..ebf5aa7e9 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -242,7 +242,7 @@ public AggregationResults runAggregation(
com.google.datastore.v1.RunQueryResponse runQuery(
final com.google.datastore.v1.RunQueryRequest requestPb) {
com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUNQUERY);
+ otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY);
ReadOptions readOptions = requestPb.getReadOptions();
span.setAttribute(
"isTransactional", readOptions.hasTransaction() || readOptions.hasNewTransaction());
@@ -258,7 +258,7 @@ com.google.datastore.v1.RunQueryResponse runQuery(
: TRANSACTION_OPERATION_EXCEPTION_HANDLER,
getOptions().getClock());
span.addEvent(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUNQUERY + ": Completed",
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY + ": Completed",
new ImmutableMap.Builder()
.put("Received", response.getBatch().getEntityResultsCount())
.put("More results", response.getBatch().getMoreResults().toString())
@@ -634,8 +634,11 @@ private com.google.datastore.v1.CommitResponse commitMutation(
com.google.datastore.v1.CommitResponse commit(
final com.google.datastore.v1.CommitRequest requestPb) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_COMMIT);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT);
+ span.setAttribute("isTransactional", requestPb.hasTransaction());
+
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
() -> datastoreRpc.commit(requestPb),
retrySettings,
@@ -644,10 +647,10 @@ com.google.datastore.v1.CommitResponse commit(
: TRANSACTION_OPERATION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java
index ba4adb5ff..7abf1d360 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java
@@ -30,6 +30,7 @@
import com.google.datastore.v1.CommitResponse;
import com.google.datastore.v1.LookupRequest;
import com.google.datastore.v1.LookupResponse;
+import com.google.datastore.v1.ReadOptions;
import com.google.datastore.v1.ReserveIdsRequest;
import com.google.datastore.v1.ReserveIdsResponse;
import com.google.datastore.v1.RollbackRequest;
@@ -101,9 +102,14 @@ public RunQueryResponse runQuery(RunQueryRequest request) {
@Override
public RunAggregationQueryResponse runAggregationQuery(RunAggregationQueryRequest request) {
- return invokeRpc(
- () -> datastoreRpc.runAggregationQuery(request),
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY);
+ ReadOptions readOptions = request.getReadOptions();
+ boolean isTransactional = readOptions.hasTransaction() || readOptions.hasNewTransaction();
+ String spanName =
+ (isTransactional
+ ? com.google.cloud.datastore.telemetry.TraceUtil
+ .SPAN_NAME_TRANSACTION_RUN_AGGREGATION_QUERY
+ : com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY);
+ return invokeRpc(() -> datastoreRpc.runAggregationQuery(request), spanName);
}
public O invokeRpc(Callable block, String startSpan) {
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index 5bf505638..00e9f2376 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -32,7 +32,9 @@ public interface TraceUtil {
static final String ENABLE_TRACING_ENV_VAR = "DATASTORE_ENABLE_TRACING";
static final String LIBRARY_NAME = "com.google.cloud.datastore";
static final String SPAN_NAME_LOOKUP = "Lookup";
+ static final String SPAN_NAME_COMMIT = "Commit";
static final String SPAN_NAME_RUN_QUERY = "RunQuery";
+ static final String SPAN_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
/**
* Creates and returns an instance of the TraceUtil class.
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 9a4a99106..357e748f1 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -16,9 +16,12 @@
package com.google.cloud.datastore.it;
+import static com.google.cloud.datastore.aggregation.Aggregation.count;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
+import static com.google.common.truth.Truth.assertThat;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -27,12 +30,16 @@
import static org.junit.Assert.assertTrue;
import com.google.api.gax.rpc.NotFoundException;
+import com.google.cloud.datastore.AggregationQuery;
+import com.google.cloud.datastore.AggregationResult;
+import com.google.cloud.datastore.AggregationResults;
import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Key;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.QueryResults;
+import com.google.cloud.datastore.StructuredQuery;
import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
import com.google.cloud.datastore.testing.RemoteDatastoreHelper;
import com.google.cloud.opentelemetry.trace.TraceConfiguration;
@@ -95,6 +102,7 @@
// 5. Traces are read-back using TraceServiceClient and verified against expected Call Stacks.
@RunWith(TestParameterInjector.class)
public class ITE2ETracingTest {
+
protected boolean isUsingGlobalOpenTelemetrySDK() {
return useGlobalOpenTelemetrySDK;
}
@@ -214,6 +222,10 @@ private boolean dfsContainsCallStack(long spanId, List expectedCallStack
private static Key KEY2;
+ private static Key KEY3;
+
+ private static Key KEY4;
+
// Random int generator for trace ID and span ID
private static Random random;
@@ -309,10 +321,17 @@ public void before() throws Exception {
.setNamespace(options.getNamespace())
.build();
KEY2 =
+ Key.newBuilder(projectId, kind1, "key3", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
+ KEY3 =
+ Key.newBuilder(projectId, kind1, "key4", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
+ KEY4 =
Key.newBuilder(projectId, kind1, "key2", options.getDatabaseId())
.setNamespace(options.getNamespace())
.build();
-
// Set up the tracer for custom TraceID injection
rootSpanName =
String.format("%s%d", this.getClass().getSimpleName(), System.currentTimeMillis());
@@ -631,6 +650,7 @@ public void deleteTraceTest() throws Exception {
fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_COMMIT);
}
+ @Test
public void runQueryTraceTest() throws Exception {
Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
@@ -657,4 +677,62 @@ public void runQueryTraceTest() throws Exception {
fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_QUERY);
}
+
+ @Test
+ public void runAggregationQueryTraceTest() throws Exception {
+ Entity entity1 =
+ Entity.newBuilder(KEY1)
+ .set("pepper_name", "jalapeno")
+ .set("max_scoville_level", 10000)
+ .build();
+ Entity entity2 =
+ Entity.newBuilder(KEY2)
+ .set("pepper_name", "serrano")
+ .set("max_scoville_level", 25000)
+ .build();
+ Entity entity3 =
+ Entity.newBuilder(KEY3)
+ .set("pepper_name", "habanero")
+ .set("max_scoville_level", 350000)
+ .build();
+ Entity entity4 =
+ Entity.newBuilder(KEY4)
+ .set("pepper_name", "ghost")
+ .set("max_scoville_level", 1500000)
+ .build();
+
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+ entityList.add(entity3);
+ entityList.add(entity4);
+
+ List response = datastore.add(entity1, entity2, entity3, entity4);
+ assertEquals(entityList, response);
+
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ PropertyFilter mediumSpicyFilters = PropertyFilter.lt("max_scoville_level", 100000);
+ StructuredQuery mediumSpicyQuery =
+ Query.newEntityQueryBuilder()
+ .setKind(KEY1.getKind())
+ .setFilter(mediumSpicyFilters)
+ .build();
+ AggregationQuery countSpicyPeppers =
+ Query.newAggregationQueryBuilder()
+ .addAggregation(count().as("count"))
+ .over(mediumSpicyQuery)
+ .build();
+ AggregationResults results = datastore.runAggregation(countSpicyPeppers);
+ assertThat(results.size()).isEqualTo(1);
+ AggregationResult result = results.get(0);
+ assertThat(result.getLong("count")).isEqualTo(2L);
+ } finally {
+ rootSpan.end();
+ }
+
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_AGGREGATION_QUERY);
+ }
}
From 8c03ba632f9d911a704f3ec4710d23036ae39b26 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Tue, 21 May 2024 10:10:17 -0700
Subject: [PATCH 16/38] test: Transaction test for RunInTransaction - need to
fix trace instrumentation for RunIn..
---
.../cloud/datastore/it/ITE2ETracingTest.java | 41 +++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 357e748f1..ecb2a84da 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -17,10 +17,12 @@
package com.google.cloud.datastore.it;
import static com.google.cloud.datastore.aggregation.Aggregation.count;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_BEGIN_TRANSACTION;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_LOOKUP;
import static com.google.common.truth.Truth.assertThat;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
@@ -39,8 +41,10 @@
import com.google.cloud.datastore.Key;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.QueryResults;
+import com.google.cloud.datastore.ReadOption;
import com.google.cloud.datastore.StructuredQuery;
import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
+import com.google.cloud.datastore.Transaction;
import com.google.cloud.datastore.testing.RemoteDatastoreHelper;
import com.google.cloud.opentelemetry.trace.TraceConfiguration;
import com.google.cloud.opentelemetry.trace.TraceExporter;
@@ -67,6 +71,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
@@ -735,4 +740,40 @@ public void runAggregationQueryTraceTest() throws Exception {
fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RUN_AGGREGATION_QUERY);
}
+
+ @Test
+ public void transactionalLookupTest() throws Exception {
+ assertNotNull(customSpanContext);
+
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ Transaction transaction = datastore.newTransaction();
+ Entity entity = datastore.get(KEY1, ReadOption.transactionId(transaction.getTransactionId()));
+ assertNull(entity);
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(
+ customSpanContext.getTraceId(),
+ /*numExpectedSpans=*/ 2,
+ Collections.singletonList(
+ Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION)));
+
+ fetchAndValidateTrace(
+ customSpanContext.getTraceId(),
+ /*numExpectedSpans=*/ 2,
+ Collections.singletonList(
+ Collections.singletonList(SPAN_NAME_TRANSACTION_LOOKUP)));
+ }
+
+ @Test
+ public void runInTransactionQueryTest() throws Exception {}
+
+ @Test
+ public void runInTransactionAggregationQueryTest() throws Exception {}
+
+ @Test
+ public void readWriteTransactionTraceTest() throws Exception {}
}
From 20c1a5457d9b90f287e36b4fb0567e5df27766bb Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Thu, 23 May 2024 11:28:48 -0700
Subject: [PATCH 17/38] Adding transaction span names
---
.../java/com/google/cloud/datastore/telemetry/TraceUtil.java | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index 00e9f2376..4cca0d7ae 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -35,7 +35,10 @@ public interface TraceUtil {
static final String SPAN_NAME_COMMIT = "Commit";
static final String SPAN_NAME_RUN_QUERY = "RunQuery";
static final String SPAN_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
-
+ static final String SPAN_NAME_BEGIN_TRANSACTION = "Transaction.Begin";
+ static final String SPAN_NAME_TRANSACTION_LOOKUP = "Transaction.Lookup";
+ static final String SPAN_NAME_TRANSACTION_COMMIT = "Transaction.Commit";
+ static final String SPAN_NAME_ROLLBACK = "Transaction.Rollback";
/**
* Creates and returns an instance of the TraceUtil class.
*
From 2ed509b541bd6584d9bfa1a26b13ecb3465f6f65 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Thu, 23 May 2024 12:43:32 -0700
Subject: [PATCH 18/38] TransactionLookupTest
---
.../google/cloud/datastore/DatastoreImpl.java | 54 +++++++++----------
.../cloud/datastore/telemetry/TraceUtil.java | 2 +
.../cloud/datastore/it/ITE2ETracingTest.java | 6 +--
3 files changed, 29 insertions(+), 33 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index ebf5aa7e9..66bc6c0ba 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -469,27 +469,27 @@ protected Entity computeNext() {
com.google.datastore.v1.LookupResponse lookup(
final com.google.datastore.v1.LookupRequest requestPb) {
- com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP);
- final ReadOptions readOptions = requestPb.getReadOptions();
- span.setAttribute(
- "isTransactional", (readOptions.hasTransaction() || readOptions.hasNewTransaction()));
+ ReadOptions readOptions = requestPb.getReadOptions();
+ boolean isTransactional = readOptions.hasTransaction() || readOptions.hasNewTransaction();
+ String spanName =
+ (isTransactional
+ ? com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_LOOKUP
+ : com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP);
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(spanName);
+ span.setAttribute("isTransactional", isTransactional);
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
- new Callable() {
- @Override
- public com.google.datastore.v1.LookupResponse call() throws DatastoreException {
- com.google.datastore.v1.LookupResponse response = datastoreRpc.lookup(requestPb);
- span.addEvent(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP + ": Completed",
- new ImmutableMap.Builder()
- .put("Received", response.getFoundCount())
- .put("Missing", response.getMissingCount())
- .put("Deferred", response.getDeferredCount())
- .build());
- return response;
- }
+ () -> {
+ com.google.datastore.v1.LookupResponse response = datastoreRpc.lookup(requestPb);
+ span.addEvent(
+ spanName + ": Completed",
+ new ImmutableMap.Builder()
+ .put("Received", response.getFoundCount())
+ .put("Missing", response.getMissingCount())
+ .put("Deferred", response.getDeferredCount())
+ .build());
+ return response;
},
retrySettings,
requestPb.getReadOptions().getTransaction().isEmpty()
@@ -661,24 +661,20 @@ ByteString requestTransactionId(
com.google.datastore.v1.BeginTransactionResponse beginTransaction(
final com.google.datastore.v1.BeginTransactionRequest requestPb) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_BEGINTRANSACTION);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_BEGIN_TRANSACTION);
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope scope = span.makeCurrent()) {
return RetryHelper.runWithRetries(
- new Callable() {
- @Override
- public com.google.datastore.v1.BeginTransactionResponse call()
- throws DatastoreException {
- return datastoreRpc.beginTransaction(requestPb);
- }
- },
+ () -> datastoreRpc.beginTransaction(requestPb),
retrySettings,
EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index 4cca0d7ae..d43c36a07 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -39,6 +39,8 @@ public interface TraceUtil {
static final String SPAN_NAME_TRANSACTION_LOOKUP = "Transaction.Lookup";
static final String SPAN_NAME_TRANSACTION_COMMIT = "Transaction.Commit";
static final String SPAN_NAME_ROLLBACK = "Transaction.Rollback";
+ static final String SPAN_NAME_TRANSACTION_RUN_AGGREGATION_QUERY =
+ "Transaction.RunAggregationQuery";
/**
* Creates and returns an instance of the TraceUtil class.
*
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index ecb2a84da..67df8c44b 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -758,14 +758,12 @@ public void transactionalLookupTest() throws Exception {
fetchAndValidateTrace(
customSpanContext.getTraceId(),
/*numExpectedSpans=*/ 2,
- Collections.singletonList(
- Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION)));
+ Collections.singletonList(Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION)));
fetchAndValidateTrace(
customSpanContext.getTraceId(),
/*numExpectedSpans=*/ 2,
- Collections.singletonList(
- Collections.singletonList(SPAN_NAME_TRANSACTION_LOOKUP)));
+ Collections.singletonList(Collections.singletonList(SPAN_NAME_TRANSACTION_LOOKUP)));
}
@Test
From 6e1a8cc0f7bb9ebad636d71711b90689316fa07d Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Wed, 29 May 2024 17:24:03 -0700
Subject: [PATCH 19/38] feat: support for transactional operations - tested
using newTransaction() and runInTransaction()
---
.../google/cloud/datastore/DatastoreImpl.java | 49 +++++++++++------
.../cloud/datastore/TransactionImpl.java | 10 +++-
.../cloud/datastore/telemetry/TraceUtil.java | 2 +
.../cloud/datastore/it/ITE2ETracingTest.java | 54 ++++++++++++++++---
4 files changed, 91 insertions(+), 24 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index 66bc6c0ba..753dab596 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -25,6 +25,7 @@
import com.google.cloud.ServiceOptions;
import com.google.cloud.datastore.execution.AggregationQueryExecutor;
import com.google.cloud.datastore.spi.v1.DatastoreRpc;
+import com.google.cloud.datastore.telemetry.TraceUtil.Context;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.collect.AbstractIterator;
@@ -52,6 +53,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
+import javax.annotation.Nonnull;
final class DatastoreImpl extends BaseService implements Datastore {
@@ -103,13 +105,18 @@ static class ReadWriteTransactionCallable implements Callable {
private final TransactionCallable callable;
private volatile TransactionOptions options;
private volatile Transaction transaction;
+ @Nonnull private final Context transactionTraceContext;
ReadWriteTransactionCallable(
- Datastore datastore, TransactionCallable callable, TransactionOptions options) {
+ Datastore datastore,
+ TransactionCallable callable,
+ TransactionOptions options,
+ @Nonnull Context parentTraceContext) {
this.datastore = datastore;
this.callable = callable;
this.options = options;
this.transaction = null;
+ this.transactionTraceContext = parentTraceContext;
}
Datastore getDatastore() {
@@ -132,8 +139,9 @@ void setPrevTransactionId(ByteString transactionId) {
@Override
public T call() throws DatastoreException {
- transaction = datastore.newTransaction(options);
- try {
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored =
+ transactionTraceContext.makeCurrent()) {
+ transaction = datastore.newTransaction(options);
T value = callable.run(transaction);
transaction.commit();
return value;
@@ -154,36 +162,41 @@ public T call() throws DatastoreException {
@Override
public T runInTransaction(final TransactionCallable callable) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_TRANSACTION);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
- new ReadWriteTransactionCallable(this, callable, null),
+ new ReadWriteTransactionCallable(this, callable, null, otelTraceUtil.currentContext()),
retrySettings,
TRANSACTION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
@Override
public T runInTransaction(
final TransactionCallable callable, TransactionOptions transactionOptions) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_TRANSACTION);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
- new ReadWriteTransactionCallable(this, callable, transactionOptions),
+ new ReadWriteTransactionCallable(
+ this, callable, transactionOptions, otelTraceUtil.currentContext()),
retrySettings,
TRANSACTION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
@@ -634,10 +647,14 @@ private com.google.datastore.v1.CommitResponse commitMutation(
com.google.datastore.v1.CommitResponse commit(
final com.google.datastore.v1.CommitRequest requestPb) {
- com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT);
+ final boolean isTransactional =
+ requestPb.hasTransaction() || requestPb.hasSingleUseTransaction();
+ final String spanName =
+ isTransactional
+ ? com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT
+ : com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(spanName);
span.setAttribute("isTransactional", requestPb.hasTransaction());
-
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
() -> datastoreRpc.commit(requestPb),
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java
index f08a908ec..b87d175a0 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java
@@ -20,6 +20,8 @@
import com.google.api.core.BetaApi;
import com.google.cloud.datastore.models.ExplainOptions;
+import com.google.cloud.datastore.telemetry.TraceUtil.Context;
+import com.google.cloud.datastore.telemetry.TraceUtil.Scope;
import com.google.common.collect.ImmutableList;
import com.google.datastore.v1.ReadOptions;
import com.google.datastore.v1.TransactionOptions;
@@ -28,6 +30,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
+import javax.annotation.Nonnull;
final class TransactionImpl extends BaseDatastoreBatchWriter implements Transaction {
@@ -37,6 +40,8 @@ final class TransactionImpl extends BaseDatastoreBatchWriter implements Transact
private final ReadOptionProtoPreparer readOptionProtoPreparer;
+ @Nonnull private final Context transactionTraceContext;
+
static class ResponseImpl implements Transaction.Response {
private final com.google.datastore.v1.CommitResponse response;
@@ -78,6 +83,7 @@ public List getGeneratedKeys() {
transactionId = datastore.requestTransactionId(requestPb);
this.readOptionProtoPreparer = new ReadOptionProtoPreparer();
+ this.transactionTraceContext = datastore.getOptions().getTraceUtil().currentContext();
}
@Override
@@ -96,7 +102,9 @@ public Iterator get(Key... keys) {
@Override
public List fetch(Key... keys) {
validateActive();
- return DatastoreHelper.fetch(this, keys);
+ try (Scope ignored = transactionTraceContext.makeCurrent()) {
+ return DatastoreHelper.fetch(this, keys);
+ }
}
@Override
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index d43c36a07..fe0e92161 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -21,6 +21,7 @@
import com.google.api.core.InternalExtensionOnly;
import com.google.cloud.datastore.DatastoreOptions;
import io.grpc.ManagedChannelBuilder;
+import io.opentelemetry.context.Context;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -35,6 +36,7 @@ public interface TraceUtil {
static final String SPAN_NAME_COMMIT = "Commit";
static final String SPAN_NAME_RUN_QUERY = "RunQuery";
static final String SPAN_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
+ static final String SPAN_NAME_TRANSACTION_RUN = "Transaction.run";
static final String SPAN_NAME_BEGIN_TRANSACTION = "Transaction.Begin";
static final String SPAN_NAME_TRANSACTION_LOOKUP = "Transaction.Lookup";
static final String SPAN_NAME_TRANSACTION_COMMIT = "Transaction.Commit";
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 67df8c44b..d2cffc5db 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -22,7 +22,9 @@
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_LOOKUP;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN;
import static com.google.common.truth.Truth.assertThat;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
@@ -749,6 +751,7 @@ public void transactionalLookupTest() throws Exception {
try (Scope ignored = rootSpan.makeCurrent()) {
Transaction transaction = datastore.newTransaction();
Entity entity = datastore.get(KEY1, ReadOption.transactionId(transaction.getTransactionId()));
+ transaction.commit();
assertNull(entity);
} finally {
rootSpan.end();
@@ -757,18 +760,55 @@ public void transactionalLookupTest() throws Exception {
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- /*numExpectedSpans=*/ 2,
- Collections.singletonList(Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION)));
+ /*numExpectedSpans=*/ 3,
+ Arrays.asList(
+ Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION),
+ Collections.singletonList(SPAN_NAME_TRANSACTION_LOOKUP),
+ Collections.singletonList(SPAN_NAME_TRANSACTION_COMMIT)));
+ }
+
+ @Test
+ public void runInTransactionQueryTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ assertNotNull(customSpanContext);
+
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
+ Query query =
+ Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
+ Datastore.TransactionCallable callable =
+ transaction -> {
+ QueryResults queryResults = datastore.run(query);
+ assertTrue(queryResults.hasNext());
+ assertEquals(entity1, queryResults.next());
+ assertFalse(queryResults.hasNext());
+ return true;
+ };
+ datastore.runInTransaction(callable);
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- /*numExpectedSpans=*/ 2,
- Collections.singletonList(Collections.singletonList(SPAN_NAME_TRANSACTION_LOOKUP)));
+ /*numExpectedSpans=*/ 4,
+ Arrays.asList(
+ Collections.singletonList(SPAN_NAME_TRANSACTION_RUN),
+ Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION),
+ Collections.singletonList(SPAN_NAME_RUN_QUERY),
+ Collections.singletonList(SPAN_NAME_TRANSACTION_COMMIT)));
}
- @Test
- public void runInTransactionQueryTest() throws Exception {}
-
@Test
public void runInTransactionAggregationQueryTest() throws Exception {}
From 5f56b06cc3b566e383e73cf6753b93ba4e66eed3 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Wed, 29 May 2024 17:31:37 -0700
Subject: [PATCH 20/38] Revert "feat: support for transactional operations"
This reverts commit 10341c0b97cbc2025f9f928ce8cb09d5c036a5b3.
---
.../google/cloud/datastore/DatastoreImpl.java | 49 ++++++-----------
.../cloud/datastore/TransactionImpl.java | 10 +---
.../cloud/datastore/telemetry/TraceUtil.java | 2 -
.../cloud/datastore/it/ITE2ETracingTest.java | 54 +++----------------
4 files changed, 24 insertions(+), 91 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index 753dab596..66bc6c0ba 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -25,7 +25,6 @@
import com.google.cloud.ServiceOptions;
import com.google.cloud.datastore.execution.AggregationQueryExecutor;
import com.google.cloud.datastore.spi.v1.DatastoreRpc;
-import com.google.cloud.datastore.telemetry.TraceUtil.Context;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.collect.AbstractIterator;
@@ -53,7 +52,6 @@
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
-import javax.annotation.Nonnull;
final class DatastoreImpl extends BaseService implements Datastore {
@@ -105,18 +103,13 @@ static class ReadWriteTransactionCallable implements Callable {
private final TransactionCallable callable;
private volatile TransactionOptions options;
private volatile Transaction transaction;
- @Nonnull private final Context transactionTraceContext;
ReadWriteTransactionCallable(
- Datastore datastore,
- TransactionCallable callable,
- TransactionOptions options,
- @Nonnull Context parentTraceContext) {
+ Datastore datastore, TransactionCallable callable, TransactionOptions options) {
this.datastore = datastore;
this.callable = callable;
this.options = options;
this.transaction = null;
- this.transactionTraceContext = parentTraceContext;
}
Datastore getDatastore() {
@@ -139,9 +132,8 @@ void setPrevTransactionId(ByteString transactionId) {
@Override
public T call() throws DatastoreException {
- try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored =
- transactionTraceContext.makeCurrent()) {
- transaction = datastore.newTransaction(options);
+ transaction = datastore.newTransaction(options);
+ try {
T value = callable.run(transaction);
transaction.commit();
return value;
@@ -162,41 +154,36 @@ public T call() throws DatastoreException {
@Override
public T runInTransaction(final TransactionCallable callable) {
- com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
- try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
+ Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_TRANSACTION);
+ try (Scope scope = traceUtil.getTracer().withSpan(span)) {
return RetryHelper.runWithRetries(
- new ReadWriteTransactionCallable(this, callable, null, otelTraceUtil.currentContext()),
+ new ReadWriteTransactionCallable(this, callable, null),
retrySettings,
TRANSACTION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.end(e);
+ span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end();
+ span.end(TraceUtil.END_SPAN_OPTIONS);
}
}
@Override
public T runInTransaction(
final TransactionCallable callable, TransactionOptions transactionOptions) {
- com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
- try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
+ Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_TRANSACTION);
+ try (Scope scope = traceUtil.getTracer().withSpan(span)) {
return RetryHelper.runWithRetries(
- new ReadWriteTransactionCallable(
- this, callable, transactionOptions, otelTraceUtil.currentContext()),
+ new ReadWriteTransactionCallable(this, callable, transactionOptions),
retrySettings,
TRANSACTION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.end(e);
+ span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end();
+ span.end(TraceUtil.END_SPAN_OPTIONS);
}
}
@@ -647,14 +634,10 @@ private com.google.datastore.v1.CommitResponse commitMutation(
com.google.datastore.v1.CommitResponse commit(
final com.google.datastore.v1.CommitRequest requestPb) {
- final boolean isTransactional =
- requestPb.hasTransaction() || requestPb.hasSingleUseTransaction();
- final String spanName =
- isTransactional
- ? com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT
- : com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
- com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(spanName);
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT);
span.setAttribute("isTransactional", requestPb.hasTransaction());
+
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
() -> datastoreRpc.commit(requestPb),
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java
index b87d175a0..f08a908ec 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java
@@ -20,8 +20,6 @@
import com.google.api.core.BetaApi;
import com.google.cloud.datastore.models.ExplainOptions;
-import com.google.cloud.datastore.telemetry.TraceUtil.Context;
-import com.google.cloud.datastore.telemetry.TraceUtil.Scope;
import com.google.common.collect.ImmutableList;
import com.google.datastore.v1.ReadOptions;
import com.google.datastore.v1.TransactionOptions;
@@ -30,7 +28,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
-import javax.annotation.Nonnull;
final class TransactionImpl extends BaseDatastoreBatchWriter implements Transaction {
@@ -40,8 +37,6 @@ final class TransactionImpl extends BaseDatastoreBatchWriter implements Transact
private final ReadOptionProtoPreparer readOptionProtoPreparer;
- @Nonnull private final Context transactionTraceContext;
-
static class ResponseImpl implements Transaction.Response {
private final com.google.datastore.v1.CommitResponse response;
@@ -83,7 +78,6 @@ public List getGeneratedKeys() {
transactionId = datastore.requestTransactionId(requestPb);
this.readOptionProtoPreparer = new ReadOptionProtoPreparer();
- this.transactionTraceContext = datastore.getOptions().getTraceUtil().currentContext();
}
@Override
@@ -102,9 +96,7 @@ public Iterator get(Key... keys) {
@Override
public List fetch(Key... keys) {
validateActive();
- try (Scope ignored = transactionTraceContext.makeCurrent()) {
- return DatastoreHelper.fetch(this, keys);
- }
+ return DatastoreHelper.fetch(this, keys);
}
@Override
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index fe0e92161..d43c36a07 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -21,7 +21,6 @@
import com.google.api.core.InternalExtensionOnly;
import com.google.cloud.datastore.DatastoreOptions;
import io.grpc.ManagedChannelBuilder;
-import io.opentelemetry.context.Context;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -36,7 +35,6 @@ public interface TraceUtil {
static final String SPAN_NAME_COMMIT = "Commit";
static final String SPAN_NAME_RUN_QUERY = "RunQuery";
static final String SPAN_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
- static final String SPAN_NAME_TRANSACTION_RUN = "Transaction.run";
static final String SPAN_NAME_BEGIN_TRANSACTION = "Transaction.Begin";
static final String SPAN_NAME_TRANSACTION_LOOKUP = "Transaction.Lookup";
static final String SPAN_NAME_TRANSACTION_COMMIT = "Transaction.Commit";
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index d2cffc5db..67df8c44b 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -22,9 +22,7 @@
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
-import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_LOOKUP;
-import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN;
import static com.google.common.truth.Truth.assertThat;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
@@ -751,7 +749,6 @@ public void transactionalLookupTest() throws Exception {
try (Scope ignored = rootSpan.makeCurrent()) {
Transaction transaction = datastore.newTransaction();
Entity entity = datastore.get(KEY1, ReadOption.transactionId(transaction.getTransactionId()));
- transaction.commit();
assertNull(entity);
} finally {
rootSpan.end();
@@ -760,55 +757,18 @@ public void transactionalLookupTest() throws Exception {
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- /*numExpectedSpans=*/ 3,
- Arrays.asList(
- Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION),
- Collections.singletonList(SPAN_NAME_TRANSACTION_LOOKUP),
- Collections.singletonList(SPAN_NAME_TRANSACTION_COMMIT)));
- }
-
- @Test
- public void runInTransactionQueryTest() throws Exception {
- Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
- Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
- List entityList = new ArrayList<>();
- entityList.add(entity1);
- entityList.add(entity2);
-
- List response = datastore.add(entity1, entity2);
- assertEquals(entityList, response);
-
- assertNotNull(customSpanContext);
-
- Span rootSpan = getNewRootSpanWithContext();
- try (Scope ignored = rootSpan.makeCurrent()) {
- PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
- Query query =
- Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
- Datastore.TransactionCallable callable =
- transaction -> {
- QueryResults queryResults = datastore.run(query);
- assertTrue(queryResults.hasNext());
- assertEquals(entity1, queryResults.next());
- assertFalse(queryResults.hasNext());
- return true;
- };
- datastore.runInTransaction(callable);
- } finally {
- rootSpan.end();
- }
- waitForTracesToComplete();
+ /*numExpectedSpans=*/ 2,
+ Collections.singletonList(Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION)));
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- /*numExpectedSpans=*/ 4,
- Arrays.asList(
- Collections.singletonList(SPAN_NAME_TRANSACTION_RUN),
- Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION),
- Collections.singletonList(SPAN_NAME_RUN_QUERY),
- Collections.singletonList(SPAN_NAME_TRANSACTION_COMMIT)));
+ /*numExpectedSpans=*/ 2,
+ Collections.singletonList(Collections.singletonList(SPAN_NAME_TRANSACTION_LOOKUP)));
}
+ @Test
+ public void runInTransactionQueryTest() throws Exception {}
+
@Test
public void runInTransactionAggregationQueryTest() throws Exception {}
From 5249bd9ffb38870c3d49503e27bd534f0c5a6ef4 Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Thu, 6 Jun 2024 21:33:28 -0700
Subject: [PATCH 21/38] feat: support for transactional operations (#1468)
* feat: support for transactional operations
- tested using newTransaction() and runInTransaction()
---
.../google/cloud/datastore/DatastoreImpl.java | 58 +++++++++++++------
.../cloud/datastore/TransactionImpl.java | 5 ++
.../telemetry/DisabledTraceUtil.java | 4 +-
.../datastore/telemetry/EnabledTraceUtil.java | 4 +-
.../cloud/datastore/telemetry/TraceUtil.java | 5 +-
.../cloud/datastore/it/ITE2ETracingTest.java | 54 ++++++++++++++---
.../telemetry/DisabledTraceUtilTest.java | 11 ++--
.../telemetry/EnabledTraceUtilTest.java | 13 +++--
8 files changed, 113 insertions(+), 41 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index 66bc6c0ba..eea94cc60 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -25,6 +25,7 @@
import com.google.cloud.ServiceOptions;
import com.google.cloud.datastore.execution.AggregationQueryExecutor;
import com.google.cloud.datastore.spi.v1.DatastoreRpc;
+import com.google.cloud.datastore.telemetry.TraceUtil.Context;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.collect.AbstractIterator;
@@ -52,6 +53,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
+import javax.annotation.Nonnull;
final class DatastoreImpl extends BaseService implements Datastore {
@@ -105,7 +107,10 @@ static class ReadWriteTransactionCallable implements Callable {
private volatile Transaction transaction;
ReadWriteTransactionCallable(
- Datastore datastore, TransactionCallable callable, TransactionOptions options) {
+ Datastore datastore,
+ TransactionCallable callable,
+ TransactionOptions options,
+ @Nonnull Context parentTraceContext) {
this.datastore = datastore;
this.callable = callable;
this.options = options;
@@ -132,8 +137,14 @@ void setPrevTransactionId(ByteString transactionId) {
@Override
public T call() throws DatastoreException {
- transaction = datastore.newTransaction(options);
- try {
+ com.google.cloud.datastore.telemetry.TraceUtil traceUtil =
+ datastore.getOptions().getTraceUtil();
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ traceUtil.startSpan(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN,
+ datastore.getOptions().getTraceUtil().getCurrentContext());
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
+ transaction = datastore.newTransaction(options);
T value = callable.run(transaction);
transaction.commit();
return value;
@@ -154,36 +165,42 @@ public T call() throws DatastoreException {
@Override
public T runInTransaction(final TransactionCallable callable) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_TRANSACTION);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
- new ReadWriteTransactionCallable(this, callable, null),
+ new ReadWriteTransactionCallable(
+ this, callable, null, otelTraceUtil.getCurrentContext()),
retrySettings,
TRANSACTION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
@Override
public T runInTransaction(
final TransactionCallable callable, TransactionOptions transactionOptions) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_TRANSACTION);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
- new ReadWriteTransactionCallable(this, callable, transactionOptions),
+ new ReadWriteTransactionCallable(
+ this, callable, transactionOptions, otelTraceUtil.getCurrentContext()),
retrySettings,
TRANSACTION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
@@ -634,10 +651,14 @@ private com.google.datastore.v1.CommitResponse commitMutation(
com.google.datastore.v1.CommitResponse commit(
final com.google.datastore.v1.CommitRequest requestPb) {
- com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT);
- span.setAttribute("isTransactional", requestPb.hasTransaction());
-
+ final boolean isTransactional =
+ requestPb.hasTransaction() || requestPb.hasSingleUseTransaction();
+ final String spanName =
+ isTransactional
+ ? com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT
+ : com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(spanName);
+ span.setAttribute("isTransactional", isTransactional);
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
() -> datastoreRpc.commit(requestPb),
@@ -663,7 +684,8 @@ com.google.datastore.v1.BeginTransactionResponse beginTransaction(
final com.google.datastore.v1.BeginTransactionRequest requestPb) {
com.google.cloud.datastore.telemetry.TraceUtil.Span span =
otelTraceUtil.startSpan(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_BEGIN_TRANSACTION);
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_BEGIN_TRANSACTION,
+ otelTraceUtil.getCurrentContext());
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope scope = span.makeCurrent()) {
return RetryHelper.runWithRetries(
() -> datastoreRpc.beginTransaction(requestPb),
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java
index f08a908ec..e730db81f 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TransactionImpl.java
@@ -20,6 +20,7 @@
import com.google.api.core.BetaApi;
import com.google.cloud.datastore.models.ExplainOptions;
+import com.google.cloud.datastore.telemetry.TraceUtil;
import com.google.common.collect.ImmutableList;
import com.google.datastore.v1.ReadOptions;
import com.google.datastore.v1.TransactionOptions;
@@ -28,6 +29,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
+import javax.annotation.Nonnull;
final class TransactionImpl extends BaseDatastoreBatchWriter implements Transaction {
@@ -37,6 +39,8 @@ final class TransactionImpl extends BaseDatastoreBatchWriter implements Transact
private final ReadOptionProtoPreparer readOptionProtoPreparer;
+ @Nonnull private final TraceUtil traceUtil;
+
static class ResponseImpl implements Transaction.Response {
private final com.google.datastore.v1.CommitResponse response;
@@ -78,6 +82,7 @@ public List getGeneratedKeys() {
transactionId = datastore.requestTransactionId(requestPb);
this.readOptionProtoPreparer = new ReadOptionProtoPreparer();
+ this.traceUtil = datastore.getOptions().getTraceUtil();
}
@Override
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
index a4f25813a..2a42081a1 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
@@ -102,13 +102,13 @@ public TraceUtil.Span startSpan(String spanName, TraceUtil.Context parent) {
@Nonnull
@Override
- public TraceUtil.Span currentSpan() {
+ public TraceUtil.Span getCurrentSpan() {
return new Span();
}
@Nonnull
@Override
- public TraceUtil.Context currentContext() {
+ public TraceUtil.Context getCurrentContext() {
return new Context();
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
index 3bf6a7466..50f89369a 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
@@ -300,13 +300,13 @@ public TraceUtil.Span startSpan(String spanName, TraceUtil.Context parent) {
@Nonnull
@Override
- public TraceUtil.Span currentSpan() {
+ public TraceUtil.Span getCurrentSpan() {
return new Span(io.opentelemetry.api.trace.Span.current(), "");
}
@Nonnull
@Override
- public TraceUtil.Context currentContext() {
+ public TraceUtil.Context getCurrentContext() {
return new Context(io.opentelemetry.context.Context.current());
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index d43c36a07..8f45e2b62 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -35,6 +35,7 @@ public interface TraceUtil {
static final String SPAN_NAME_COMMIT = "Commit";
static final String SPAN_NAME_RUN_QUERY = "RunQuery";
static final String SPAN_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
+ static final String SPAN_NAME_TRANSACTION_RUN = "Transaction.run";
static final String SPAN_NAME_BEGIN_TRANSACTION = "Transaction.Begin";
static final String SPAN_NAME_TRANSACTION_LOOKUP = "Transaction.Lookup";
static final String SPAN_NAME_TRANSACTION_COMMIT = "Transaction.Commit";
@@ -133,9 +134,9 @@ interface Scope extends AutoCloseable {
/** Returns the current span. */
@Nonnull
- Span currentSpan();
+ Span getCurrentSpan();
/** Returns the current Context. */
@Nonnull
- Context currentContext();
+ Context getCurrentContext();
}
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 67df8c44b..d2cffc5db 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -22,7 +22,9 @@
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_LOOKUP;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN;
import static com.google.common.truth.Truth.assertThat;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
@@ -749,6 +751,7 @@ public void transactionalLookupTest() throws Exception {
try (Scope ignored = rootSpan.makeCurrent()) {
Transaction transaction = datastore.newTransaction();
Entity entity = datastore.get(KEY1, ReadOption.transactionId(transaction.getTransactionId()));
+ transaction.commit();
assertNull(entity);
} finally {
rootSpan.end();
@@ -757,18 +760,55 @@ public void transactionalLookupTest() throws Exception {
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- /*numExpectedSpans=*/ 2,
- Collections.singletonList(Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION)));
+ /*numExpectedSpans=*/ 3,
+ Arrays.asList(
+ Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION),
+ Collections.singletonList(SPAN_NAME_TRANSACTION_LOOKUP),
+ Collections.singletonList(SPAN_NAME_TRANSACTION_COMMIT)));
+ }
+
+ @Test
+ public void runInTransactionQueryTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ assertNotNull(customSpanContext);
+
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
+ Query query =
+ Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
+ Datastore.TransactionCallable callable =
+ transaction -> {
+ QueryResults queryResults = datastore.run(query);
+ assertTrue(queryResults.hasNext());
+ assertEquals(entity1, queryResults.next());
+ assertFalse(queryResults.hasNext());
+ return true;
+ };
+ datastore.runInTransaction(callable);
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- /*numExpectedSpans=*/ 2,
- Collections.singletonList(Collections.singletonList(SPAN_NAME_TRANSACTION_LOOKUP)));
+ /*numExpectedSpans=*/ 4,
+ Arrays.asList(
+ Collections.singletonList(SPAN_NAME_TRANSACTION_RUN),
+ Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION),
+ Collections.singletonList(SPAN_NAME_RUN_QUERY),
+ Collections.singletonList(SPAN_NAME_TRANSACTION_COMMIT)));
}
- @Test
- public void runInTransactionQueryTest() throws Exception {}
-
@Test
public void runInTransactionAggregationQueryTest() throws Exception {}
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java
index 0f3f183cd..a24f55597 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java
@@ -29,16 +29,16 @@ public void disabledTraceUtilDoesNotProvideChannelConfigurator() {
@Test
public void usesDisabledContext() {
DisabledTraceUtil traceUtil = new DisabledTraceUtil();
- assertThat(traceUtil.currentContext() instanceof DisabledTraceUtil.Context).isTrue();
+ assertThat(traceUtil.getCurrentContext() instanceof DisabledTraceUtil.Context).isTrue();
}
@Test
public void usesDisabledSpan() {
DisabledTraceUtil traceUtil = new DisabledTraceUtil();
- assertThat(traceUtil.currentSpan() instanceof DisabledTraceUtil.Span).isTrue();
+ assertThat(traceUtil.getCurrentSpan() instanceof DisabledTraceUtil.Span).isTrue();
assertThat(traceUtil.startSpan("foo") instanceof DisabledTraceUtil.Span).isTrue();
assertThat(
- traceUtil.startSpan("foo", traceUtil.currentContext())
+ traceUtil.startSpan("foo", traceUtil.getCurrentContext())
instanceof DisabledTraceUtil.Span)
.isTrue();
}
@@ -46,8 +46,9 @@ public void usesDisabledSpan() {
@Test
public void usesDisabledScope() {
DisabledTraceUtil traceUtil = new DisabledTraceUtil();
- assertThat(traceUtil.currentContext().makeCurrent() instanceof DisabledTraceUtil.Scope)
+ assertThat(traceUtil.getCurrentContext().makeCurrent() instanceof DisabledTraceUtil.Scope)
+ .isTrue();
+ assertThat(traceUtil.getCurrentSpan().makeCurrent() instanceof DisabledTraceUtil.Scope)
.isTrue();
- assertThat(traceUtil.currentSpan().makeCurrent() instanceof DisabledTraceUtil.Scope).isTrue();
}
}
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java
index e88e1a849..2497672d9 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java
@@ -82,23 +82,26 @@ public void enabledTraceUtilProvidesChannelConfigurator() {
@Test
public void usesEnabledContext() {
- assertThat(newEnabledTraceUtil().currentContext() instanceof EnabledTraceUtil.Context).isTrue();
+ assertThat(newEnabledTraceUtil().getCurrentContext() instanceof EnabledTraceUtil.Context)
+ .isTrue();
}
@Test
public void usesEnabledSpan() {
EnabledTraceUtil traceUtil = newEnabledTraceUtil();
- assertThat(traceUtil.currentSpan() instanceof EnabledTraceUtil.Span).isTrue();
+ assertThat(traceUtil.getCurrentSpan() instanceof EnabledTraceUtil.Span).isTrue();
assertThat(traceUtil.startSpan("foo") != null).isTrue();
assertThat(
- traceUtil.startSpan("foo", traceUtil.currentContext()) instanceof EnabledTraceUtil.Span)
+ traceUtil.startSpan("foo", traceUtil.getCurrentContext())
+ instanceof EnabledTraceUtil.Span)
.isTrue();
}
@Test
public void usesEnabledScope() {
EnabledTraceUtil traceUtil = newEnabledTraceUtil();
- assertThat(traceUtil.currentContext().makeCurrent() instanceof EnabledTraceUtil.Scope).isTrue();
- assertThat(traceUtil.currentSpan().makeCurrent() instanceof EnabledTraceUtil.Scope).isTrue();
+ assertThat(traceUtil.getCurrentContext().makeCurrent() instanceof EnabledTraceUtil.Scope)
+ .isTrue();
+ assertThat(traceUtil.getCurrentSpan().makeCurrent() instanceof EnabledTraceUtil.Scope).isTrue();
}
}
From 0abf2988500ae687634a9d3f64f30a997896c66e Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Tue, 18 Jun 2024 23:06:38 -0700
Subject: [PATCH 22/38] feat: Allocateid tracing (#1488)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat: Adding tracing for AllocateIds RPC
* formatting
* 🦉 Updates from OwlBot post-processor
See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md
---------
Co-authored-by: Owl Bot
---
README.md | 25 +++++++++--------
google-cloud-datastore/pom.xml | 2 +-
.../google/cloud/datastore/DatastoreImpl.java | 10 ++++---
.../com/google/cloud/datastore/TraceUtil.java | 1 -
.../cloud/datastore/telemetry/TraceUtil.java | 1 +
.../cloud/datastore/it/ITE2ETracingTest.java | 28 +++++++++++++++++++
6 files changed, 49 insertions(+), 18 deletions(-)
diff --git a/README.md b/README.md
index e6d69755b..9089655ec 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file:
com.google.cloud
libraries-bom
- 26.45.0
+ 26.41.0
pom
import
@@ -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.45.0')
+implementation platform('com.google.cloud:libraries-bom:26.42.0')
implementation 'com.google.cloud:google-cloud-datastore'
```
If you are using Gradle without BOM, add this to your dependencies:
```Groovy
-implementation 'com.google.cloud:google-cloud-datastore:2.21.2'
+implementation 'com.google.cloud:google-cloud-datastore:2.20.2'
```
If you are using SBT, add this to your dependencies:
```Scala
-libraryDependencies += "com.google.cloud" % "google-cloud-datastore" % "2.21.2"
+libraryDependencies += "com.google.cloud" % "google-cloud-datastore" % "2.20.2"
```
@@ -80,7 +80,7 @@ The client application making API calls must be granted [authorization scopes][a
### Prerequisites
You will need a [Google Cloud Platform Console][developer-console] project with the Cloud Datastore [API enabled][enable-api].
-You will need to [enable billing][enable-billing] to use Google Cloud Datastore.
+
[Follow these instructions][create-project] to get your project set up. You will also need to set up the local development environment by
[installing the Google Cloud Command Line Interface][cloud-cli] and running the following commands in command line:
`gcloud auth login` and `gcloud config set project [YOUR PROJECT ID]`.
@@ -93,7 +93,11 @@ to add `google-cloud-datastore` as a dependency in your code.
## About Cloud Datastore
-[Cloud Datastore][product-docs] is a fully managed, schemaless database for\nstoring non-relational data. Cloud Datastore automatically scales with\nyour users and supports ACID transactions, high availability of reads and\nwrites, strong consistency for reads and ancestor queries, and eventual\nconsistency for all other queries.
+[Cloud Datastore][product-docs] is a fully managed, schemaless database for
+storing non-relational data. Cloud Datastore automatically scales with
+your users and supports ACID transactions, high availability of reads and
+writes, strong consistency for reads and ancestor queries, and eventual
+consistency for all other queries.
See the [Cloud Datastore client library docs][javadocs] to learn how to
use this Cloud Datastore Client Library.
@@ -352,6 +356,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-datastore/tre
| Sample | Source Code | Try it |
| --------------------------- | --------------------------------- | ------ |
+| Native Image Datastore Sample | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/native-image-sample/src/main/java/com/example/datastore/NativeImageDatastoreSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/native-image-sample/src/main/java/com/example/datastore/NativeImageDatastoreSample.java) |
| Quickstart Sample | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/QuickstartSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/QuickstartSample.java) |
| Avg Aggregation On Kind | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/aggregation/AvgAggregationOnKind.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/aggregation/AvgAggregationOnKind.java) |
| Avg Aggregation With Limit | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/aggregation/AvgAggregationWithLimit.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/aggregation/AvgAggregationWithLimit.java) |
@@ -383,10 +388,6 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-datastore/tre
To get help, follow the instructions in the [shared Troubleshooting document][troubleshooting].
-## Transport
-
-Cloud Datastore uses both gRPC and HTTP/JSON for the transport layer.
-
## Supported Java Versions
Java 8 or above is required for using this client.
@@ -479,7 +480,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-datastore/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-datastore.svg
-[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-datastore/2.21.2
+[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-datastore/2.20.2
[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
@@ -491,7 +492,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
[contributing]: https://github.com/googleapis/java-datastore/blob/main/CONTRIBUTING.md
[code-of-conduct]: https://github.com/googleapis/java-datastore/blob/main/CODE_OF_CONDUCT.md#contributor-code-of-conduct
[license]: https://github.com/googleapis/java-datastore/blob/main/LICENSE
-[enable-billing]: https://cloud.google.com/apis/docs/getting-started#enabling_billing
+
[enable-api]: https://console.cloud.google.com/flows/enableapi?apiid=datastore.googleapis.com
[libraries-bom]: https://github.com/GoogleCloudPlatform/cloud-opensource-java/wiki/The-Google-Cloud-Platform-Libraries-BOM
[shell_img]: https://gstatic.com/cloudssh/images/open-btn.png
diff --git a/google-cloud-datastore/pom.xml b/google-cloud-datastore/pom.xml
index c8d229e48..da248be2c 100644
--- a/google-cloud-datastore/pom.xml
+++ b/google-cloud-datastore/pom.xml
@@ -16,7 +16,7 @@
google-cloud-datastore
- 1.37.0
+ 1.38.0
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index eea94cc60..f726f0bb2 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -327,8 +327,10 @@ public List allocateId(IncompleteKey... keys) {
private com.google.datastore.v1.AllocateIdsResponse allocateIds(
final com.google.datastore.v1.AllocateIdsRequest requestPb) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_ALLOCATEIDS);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_ALLOCATE_IDS);
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
new Callable() {
@Override
@@ -340,10 +342,10 @@ public com.google.datastore.v1.AllocateIdsResponse call() throws DatastoreExcept
EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TraceUtil.java
index 57525d15d..6b51d6a87 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TraceUtil.java
@@ -31,7 +31,6 @@
public class TraceUtil {
private final Tracer tracer = Tracing.getTracer();
private static final TraceUtil traceUtil = new TraceUtil();
- static final String SPAN_NAME_ALLOCATEIDS = "CloudDatastoreOperation.allocateIds";
static final String SPAN_NAME_TRANSACTION = "CloudDatastoreOperation.readWriteTransaction";
static final String SPAN_NAME_BEGINTRANSACTION = "CloudDatastoreOperation.beginTransaction";
static final String SPAN_NAME_COMMIT = "CloudDatastoreOperation.commit";
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index 8f45e2b62..1198460a4 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -32,6 +32,7 @@ public interface TraceUtil {
static final String ENABLE_TRACING_ENV_VAR = "DATASTORE_ENABLE_TRACING";
static final String LIBRARY_NAME = "com.google.cloud.datastore";
static final String SPAN_NAME_LOOKUP = "Lookup";
+ static final String SPAN_NAME_ALLOCATE_IDS = "AllocateIds";
static final String SPAN_NAME_COMMIT = "Commit";
static final String SPAN_NAME_RUN_QUERY = "RunQuery";
static final String SPAN_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index d2cffc5db..a032762c8 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -17,6 +17,7 @@
package com.google.cloud.datastore.it;
import static com.google.cloud.datastore.aggregation.Aggregation.count;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_ALLOCATE_IDS;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_BEGIN_TRANSACTION;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
@@ -40,7 +41,9 @@
import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
+import com.google.cloud.datastore.IncompleteKey;
import com.google.cloud.datastore.Key;
+import com.google.cloud.datastore.KeyFactory;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.QueryResults;
import com.google.cloud.datastore.ReadOption;
@@ -574,6 +577,31 @@ public void lookupTraceTest() throws Exception {
fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_LOOKUP);
}
+ @Test
+ public void allocateIdsTraceTest() throws Exception {
+ assertNotNull(customSpanContext);
+
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ String kind1 = "kind1";
+ KeyFactory keyFactory = datastore.newKeyFactory().setKind(kind1);
+ IncompleteKey pk1 = keyFactory.newKey();
+ Key key1 = datastore.allocateId(pk1);
+ assertEquals(key1.getProjectId(), pk1.getProjectId());
+ assertEquals(key1.getNamespace(), pk1.getNamespace());
+ assertEquals(key1.getAncestors(), pk1.getAncestors());
+ assertEquals(key1.getKind(), pk1.getKind());
+ assertTrue(key1.hasId());
+ assertFalse(key1.hasName());
+ assertEquals(Key.newBuilder(pk1, key1.getId()).build(), key1);
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_ALLOCATE_IDS);
+ }
+
@Test
public void commitTraceTest() throws Exception {
assertNotNull(customSpanContext);
From 6af5223bfb45a646f2baecb73fa487748bb5d5bb Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Tue, 25 Jun 2024 13:42:55 -0700
Subject: [PATCH 23/38] feat: Add tracing for ReserveIds operation (#1490)
- added end-to-end test
---
.../google/cloud/datastore/DatastoreImpl.java | 10 ++++++----
.../cloud/datastore/telemetry/TraceUtil.java | 1 +
.../cloud/datastore/it/ITE2ETracingTest.java | 20 +++++++++++++++++++
3 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index f726f0bb2..52acb77d8 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -543,8 +543,10 @@ public List reserveIds(Key... keys) {
com.google.datastore.v1.ReserveIdsResponse reserveIds(
final com.google.datastore.v1.ReserveIdsRequest requestPb) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_RESERVEIDS);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RESERVE_IDS);
+ try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
new Callable() {
@Override
@@ -556,10 +558,10 @@ public com.google.datastore.v1.ReserveIdsResponse call() throws DatastoreExcepti
EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index 1198460a4..1e5226126 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -33,6 +33,7 @@ public interface TraceUtil {
static final String LIBRARY_NAME = "com.google.cloud.datastore";
static final String SPAN_NAME_LOOKUP = "Lookup";
static final String SPAN_NAME_ALLOCATE_IDS = "AllocateIds";
+ static final String SPAN_NAME_RESERVE_IDS = "ReserveIds";
static final String SPAN_NAME_COMMIT = "Commit";
static final String SPAN_NAME_RUN_QUERY = "RunQuery";
static final String SPAN_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index a032762c8..bf7635266 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -21,6 +21,7 @@
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_BEGIN_TRANSACTION;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RESERVE_IDS;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT;
@@ -602,6 +603,25 @@ public void allocateIdsTraceTest() throws Exception {
fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_ALLOCATE_IDS);
}
+ @Test
+ public void reserveIdsTraceTest() throws Exception {
+ assertNotNull(customSpanContext);
+
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ KeyFactory keyFactory = datastore.newKeyFactory().setKind("MyKind");
+ Key key1 = keyFactory.newKey(10);
+ Key key2 = keyFactory.newKey("name");
+ List keyList = datastore.reserveIds(key1, key2);
+ assertEquals(2, keyList.size());
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(customSpanContext.getTraceId(), SPAN_NAME_RESERVE_IDS);
+ }
+
@Test
public void commitTraceTest() throws Exception {
assertNotNull(customSpanContext);
From d02d9590bdcdc064689acb8cc30ef48d87729d62 Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Thu, 27 Jun 2024 11:51:17 -0700
Subject: [PATCH 24/38] fix: Fixed Span nesting for
`ReadWriteTransactionCallable` by using parent SpanContext instead of just
parent Context (#1495)
* fix: Fixed the TraceUtil.startSpan method to use `SpanContext` for linking with the parent instead of `Context`.
- This fixes the hierarchy of Spans appearing in a transaction under a Run method.
- Tested using existing transaction test
* Fixed commit reordering and typos
* fix: lint errors
* fix: Refactored the ReadWriteTransactioncallable.call method to use startSpan idiomatically
- TraceUtil.startSpan needs more debugging
- return DefaultTracerProvider instance (no-op) when initializing DisabledTraceUtil - this fixes the unit tests in DatastoreTest.testRunInTransactionWithReadWriteOption
* feat: Added tracing for Transaction.RunQuery (#1499)
* feat: Added span for Transactional RunQuery
- tested
* fix: lint
* fix: patch apply issues
* fix: refactor using boolean flag
* fix: s/startSpan/startSpanWithParentContext
---
.../google/cloud/datastore/DatastoreImpl.java | 92 ++++++++++++-------
.../telemetry/DisabledTraceUtil.java | 28 +++++-
.../datastore/telemetry/EnabledTraceUtil.java | 39 +++++++-
.../cloud/datastore/telemetry/TraceUtil.java | 25 ++++-
.../cloud/datastore/it/ITE2ETracingTest.java | 51 +++++++++-
.../telemetry/DisabledTraceUtilTest.java | 2 +-
.../telemetry/EnabledTraceUtilTest.java | 2 +-
7 files changed, 193 insertions(+), 46 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index 52acb77d8..0fefc3168 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -25,9 +25,9 @@
import com.google.cloud.ServiceOptions;
import com.google.cloud.datastore.execution.AggregationQueryExecutor;
import com.google.cloud.datastore.spi.v1.DatastoreRpc;
-import com.google.cloud.datastore.telemetry.TraceUtil.Context;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -42,6 +42,11 @@
import io.opencensus.common.Scope;
import io.opencensus.trace.Span;
import io.opencensus.trace.Status;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.SpanBuilder;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.api.trace.StatusCode;
+import io.opentelemetry.context.Context;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -53,7 +58,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
-import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
final class DatastoreImpl extends BaseService implements Datastore {
@@ -106,15 +111,18 @@ static class ReadWriteTransactionCallable implements Callable {
private volatile TransactionOptions options;
private volatile Transaction transaction;
+ private final com.google.cloud.datastore.telemetry.TraceUtil.SpanContext parentSpanContext;
+
ReadWriteTransactionCallable(
Datastore datastore,
TransactionCallable callable,
TransactionOptions options,
- @Nonnull Context parentTraceContext) {
+ @Nullable com.google.cloud.datastore.telemetry.TraceUtil.SpanContext parentSpanContext) {
this.datastore = datastore;
this.callable = callable;
this.options = options;
this.transaction = null;
+ this.parentSpanContext = parentSpanContext;
}
Datastore getDatastore() {
@@ -135,26 +143,57 @@ void setPrevTransactionId(ByteString transactionId) {
options = options.toBuilder().setReadWrite(readWrite).build();
}
+ private io.opentelemetry.api.trace.Span startSpanWithParentContext(
+ String spanName,
+ com.google.cloud.datastore.telemetry.TraceUtil.SpanContext parentSpanContext) {
+ com.google.cloud.datastore.telemetry.TraceUtil otelTraceUtil =
+ datastore.getOptions().getTraceUtil();
+ SpanBuilder spanBuilder =
+ otelTraceUtil
+ .getTracer()
+ .spanBuilder(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN)
+ .setSpanKind(SpanKind.PRODUCER)
+ .setParent(
+ Context.current()
+ .with(
+ io.opentelemetry.api.trace.Span.wrap(
+ parentSpanContext.getSpanContext())));
+ return spanBuilder.startSpan();
+ }
+
@Override
public T call() throws DatastoreException {
- com.google.cloud.datastore.telemetry.TraceUtil traceUtil =
- datastore.getOptions().getTraceUtil();
- com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- traceUtil.startSpan(
+ // TODO Instead of using OTel Spans directly, TraceUtil.Span should be used here. However,
+ // the same code in startSpanInternal doesn't work when EnabledTraceUtil.StartSpan is called
+ // probably because of some thread-local caching that is getting lost. This needs more
+ // debugging. The code below works and is idiomatic but could be prettier and more consistent
+ // with the use of TraceUtil-provided framework.
+ io.opentelemetry.api.trace.Span span =
+ startSpanWithParentContext(
com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN,
- datastore.getOptions().getTraceUtil().getCurrentContext());
- try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
+ parentSpanContext);
+ try (io.opentelemetry.context.Scope ignored = span.makeCurrent()) {
transaction = datastore.newTransaction(options);
T value = callable.run(transaction);
transaction.commit();
return value;
} catch (Exception ex) {
transaction.rollback();
+ span.setStatus(StatusCode.ERROR, ex.getMessage());
+ span.recordException(
+ ex,
+ Attributes.builder()
+ .put("exception.message", ex.getMessage())
+ .put("exception.type", ex.getClass().getName())
+ .put("exception.stacktrace", Throwables.getStackTraceAsString(ex))
+ .build());
+ span.end();
throw DatastoreException.propagateUserException(ex);
} finally {
if (transaction.isActive()) {
transaction.rollback();
}
+ span.end();
if (options != null
&& options.getModeCase().equals(TransactionOptions.ModeCase.READ_WRITE)) {
setPrevTransactionId(transaction.getTransactionId());
@@ -165,42 +204,30 @@ public T call() throws DatastoreException {
@Override
public T runInTransaction(final TransactionCallable callable) {
- com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
- try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
+ try {
return RetryHelper.runWithRetries(
new ReadWriteTransactionCallable(
- this, callable, null, otelTraceUtil.getCurrentContext()),
+ this, callable, null, otelTraceUtil.getCurrentSpanContext()),
retrySettings,
TRANSACTION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.end(e);
throw DatastoreException.translateAndThrow(e);
- } finally {
- span.end();
}
}
@Override
public T runInTransaction(
final TransactionCallable callable, TransactionOptions transactionOptions) {
- com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
- try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
+ try {
return RetryHelper.runWithRetries(
new ReadWriteTransactionCallable(
- this, callable, transactionOptions, otelTraceUtil.getCurrentContext()),
+ this, callable, transactionOptions, otelTraceUtil.getCurrentSpanContext()),
retrySettings,
TRANSACTION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.end(e);
throw DatastoreException.translateAndThrow(e);
- } finally {
- span.end();
}
}
@@ -258,11 +285,14 @@ public AggregationResults runAggregation(
com.google.datastore.v1.RunQueryResponse runQuery(
final com.google.datastore.v1.RunQueryRequest requestPb) {
- com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY);
ReadOptions readOptions = requestPb.getReadOptions();
- span.setAttribute(
- "isTransactional", readOptions.hasTransaction() || readOptions.hasNewTransaction());
+ boolean isTransactional = readOptions.hasTransaction() || readOptions.hasNewTransaction();
+ String spanName =
+ (isTransactional
+ ? com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN_QUERY
+ : com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY);
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(spanName);
+ span.setAttribute("isTransactional", isTransactional);
span.setAttribute("readConsistency", readOptions.getReadConsistency().toString());
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
@@ -275,7 +305,7 @@ com.google.datastore.v1.RunQueryResponse runQuery(
: TRANSACTION_OPERATION_EXCEPTION_HANDLER,
getOptions().getClock());
span.addEvent(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY + ": Completed",
+ spanName + ": Completed",
new ImmutableMap.Builder()
.put("Received", response.getBatch().getEntityResultsCount())
.put("More results", response.getBatch().getMoreResults().toString())
@@ -689,7 +719,7 @@ com.google.datastore.v1.BeginTransactionResponse beginTransaction(
com.google.cloud.datastore.telemetry.TraceUtil.Span span =
otelTraceUtil.startSpan(
com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_BEGIN_TRANSACTION,
- otelTraceUtil.getCurrentContext());
+ otelTraceUtil.getCurrentSpanContext());
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope scope = span.makeCurrent()) {
return RetryHelper.runWithRetries(
() -> datastoreRpc.beginTransaction(requestPb),
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
index 2a42081a1..6ba0fd81c 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
@@ -19,7 +19,11 @@
import com.google.api.core.ApiFunction;
import com.google.api.core.ApiFuture;
import com.google.api.core.InternalApi;
+import com.google.cloud.datastore.telemetry.TraceUtil.SpanContext;
import io.grpc.ManagedChannelBuilder;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.api.trace.TracerProvider;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -31,6 +35,13 @@
@InternalApi
public class DisabledTraceUtil implements TraceUtil {
+ static class SpanContext implements TraceUtil.SpanContext {
+ @Override
+ public io.opentelemetry.api.trace.SpanContext getSpanContext() {
+ return null;
+ }
+ }
+
static class Span implements TraceUtil.Span {
@Override
public void end() {}
@@ -66,6 +77,10 @@ public TraceUtil.Span setAttribute(String key, boolean value) {
return this;
}
+ public io.opentelemetry.api.trace.Span getSpan() {
+ return null;
+ }
+
@Override
public Scope makeCurrent() {
return new Scope();
@@ -96,7 +111,7 @@ public Span startSpan(String spanName) {
}
@Override
- public TraceUtil.Span startSpan(String spanName, TraceUtil.Context parent) {
+ public TraceUtil.Span startSpan(String spanName, TraceUtil.SpanContext parentSpanContext) {
return new Span();
}
@@ -111,4 +126,15 @@ public TraceUtil.Span getCurrentSpan() {
public TraceUtil.Context getCurrentContext() {
return new Context();
}
+
+ @Nonnull
+ @Override
+ public TraceUtil.SpanContext getCurrentSpanContext() {
+ return new SpanContext();
+ }
+
+ @Override
+ public Tracer getTracer() {
+ return TracerProvider.noop().get(LIBRARY_NAME);
+ }
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
index 50f89369a..438395cb1 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
@@ -22,16 +22,19 @@
import com.google.api.core.ApiFutures;
import com.google.api.core.InternalApi;
import com.google.cloud.datastore.DatastoreOptions;
+import com.google.cloud.datastore.telemetry.TraceUtil.SpanContext;
import com.google.common.base.Throwables;
import io.grpc.ManagedChannelBuilder;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
+import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.context.Context;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -70,6 +73,19 @@ public ApiFunction getChannelConfi
return null;
}
+ static class SpanContext implements TraceUtil.SpanContext {
+ private final io.opentelemetry.api.trace.SpanContext spanContext;
+
+ public SpanContext(io.opentelemetry.api.trace.SpanContext spanContext) {
+ this.spanContext = spanContext;
+ }
+
+ @Override
+ public io.opentelemetry.api.trace.SpanContext getSpanContext() {
+ return this.spanContext;
+ }
+ }
+
static class Span implements TraceUtil.Span {
private final io.opentelemetry.api.trace.Span span;
private final String spanName;
@@ -181,6 +197,10 @@ public TraceUtil.Span setAttribute(String key, boolean value) {
return this;
}
+ public io.opentelemetry.api.trace.Span getSpan() {
+ return this.span;
+ }
+
@Override
public Scope makeCurrent() {
try (io.opentelemetry.context.Scope scope = span.makeCurrent()) {
@@ -286,13 +306,15 @@ public Span startSpan(String spanName) {
}
@Override
- public TraceUtil.Span startSpan(String spanName, TraceUtil.Context parent) {
- assert (parent instanceof Context);
+ public TraceUtil.Span startSpan(String spanName, TraceUtil.SpanContext parentSpanContext) {
SpanBuilder spanBuilder =
tracer
.spanBuilder(spanName)
.setSpanKind(SpanKind.PRODUCER)
- .setParent(((Context) parent).context);
+ .setParent(
+ io.opentelemetry.context.Context.current()
+ .with(
+ io.opentelemetry.api.trace.Span.wrap(parentSpanContext.getSpanContext())));
io.opentelemetry.api.trace.Span span =
addSettingsAttributesToCurrentSpan(spanBuilder).startSpan();
return new Span(span, spanName);
@@ -309,4 +331,15 @@ public TraceUtil.Span getCurrentSpan() {
public TraceUtil.Context getCurrentContext() {
return new Context(io.opentelemetry.context.Context.current());
}
+
+ @Nonnull
+ @Override
+ public TraceUtil.SpanContext getCurrentSpanContext() {
+ return new SpanContext(io.opentelemetry.api.trace.Span.current().getSpanContext());
+ }
+
+ @Override
+ public Tracer getTracer() {
+ return this.tracer;
+ }
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index 1e5226126..dd1dcf29e 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -21,6 +21,8 @@
import com.google.api.core.InternalExtensionOnly;
import com.google.cloud.datastore.DatastoreOptions;
import io.grpc.ManagedChannelBuilder;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.Tracer;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -37,10 +39,11 @@ public interface TraceUtil {
static final String SPAN_NAME_COMMIT = "Commit";
static final String SPAN_NAME_RUN_QUERY = "RunQuery";
static final String SPAN_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
- static final String SPAN_NAME_TRANSACTION_RUN = "Transaction.run";
+ static final String SPAN_NAME_TRANSACTION_RUN = "Transaction.Run";
static final String SPAN_NAME_BEGIN_TRANSACTION = "Transaction.Begin";
static final String SPAN_NAME_TRANSACTION_LOOKUP = "Transaction.Lookup";
static final String SPAN_NAME_TRANSACTION_COMMIT = "Transaction.Commit";
+ static final String SPAN_NAME_TRANSACTION_RUN_QUERY = "Transaction.RunQuery";
static final String SPAN_NAME_ROLLBACK = "Transaction.Rollback";
static final String SPAN_NAME_TRANSACTION_RUN_AGGREGATION_QUERY =
"Transaction.RunAggregationQuery";
@@ -78,6 +81,11 @@ static TraceUtil getInstance(@Nonnull DatastoreOptions datastoreOptions) {
@Nullable
ApiFunction getChannelConfigurator();
+ /** Represents a trace span's context */
+ interface SpanContext {
+ io.opentelemetry.api.trace.SpanContext getSpanContext();
+ }
+
/** Represents a trace span. */
interface Span {
/** Adds the given event to this span. */
@@ -95,6 +103,8 @@ interface Span {
/** Adds the given attribute to this span. */
Span setAttribute(String key, boolean value);
+ io.opentelemetry.api.trace.Span getSpan();
+
/** Marks this span as the current span. */
Scope makeCurrent();
@@ -129,10 +139,10 @@ interface Scope extends AutoCloseable {
Span startSpan(String spanName);
/**
- * Starts a new span with the given name and the given context as its parent, sets it as the
- * current span, and returns it.
+ * Starts a new span with the given name and the span represented by the parentSpanContext as its
+ * parents, sets it as the current span and returns it.
*/
- Span startSpan(String spanName, Context parent);
+ Span startSpan(String spanName, SpanContext parentSpanContext);
/** Returns the current span. */
@Nonnull
@@ -141,4 +151,11 @@ interface Scope extends AutoCloseable {
/** Returns the current Context. */
@Nonnull
Context getCurrentContext();
+
+ /** Returns the current SpanContext */
+ @Nonnull
+ SpanContext getCurrentSpanContext();
+
+ /** Returns the current OpenTelemetry Tracer when OpenTelemetry SDK is provided. */
+ Tracer getTracer();
}
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index bf7635266..34c7ea858 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -27,6 +27,7 @@
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_LOOKUP;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN_QUERY;
import static com.google.common.truth.Truth.assertThat;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
@@ -815,8 +816,49 @@ public void transactionalLookupTest() throws Exception {
Collections.singletonList(SPAN_NAME_TRANSACTION_COMMIT)));
}
+ @Test
+ public void transactionQueryTest() throws Exception {
+ // Set up
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ assertNotNull(customSpanContext);
+
+ // Test
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ Transaction transaction = datastore.newTransaction();
+ PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
+ Query query =
+ Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
+ QueryResults queryResults = transaction.run(query);
+ transaction.commit();
+ assertTrue(queryResults.hasNext());
+ assertEquals(entity1, queryResults.next());
+ assertFalse(queryResults.hasNext());
+ } finally {
+ rootSpan.end();
+ }
+ waitForTracesToComplete();
+
+ fetchAndValidateTrace(
+ customSpanContext.getTraceId(),
+ /*numExpectedSpans=*/ 3,
+ Arrays.asList(
+ Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION),
+ Collections.singletonList(SPAN_NAME_TRANSACTION_RUN_QUERY),
+ Collections.singletonList(SPAN_NAME_TRANSACTION_COMMIT)));
+ }
+
@Test
public void runInTransactionQueryTest() throws Exception {
+ // Set up
Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
List entityList = new ArrayList<>();
@@ -851,14 +893,13 @@ public void runInTransactionQueryTest() throws Exception {
customSpanContext.getTraceId(),
/*numExpectedSpans=*/ 4,
Arrays.asList(
- Collections.singletonList(SPAN_NAME_TRANSACTION_RUN),
- Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION),
- Collections.singletonList(SPAN_NAME_RUN_QUERY),
- Collections.singletonList(SPAN_NAME_TRANSACTION_COMMIT)));
+ Arrays.asList(SPAN_NAME_TRANSACTION_RUN, SPAN_NAME_BEGIN_TRANSACTION),
+ Arrays.asList(SPAN_NAME_TRANSACTION_RUN, SPAN_NAME_RUN_QUERY),
+ Arrays.asList(SPAN_NAME_TRANSACTION_RUN, SPAN_NAME_TRANSACTION_COMMIT)));
}
@Test
- public void runInTransactionAggregationQueryTest() throws Exception {}
+ public void transactionRunQueryTest() throws Exception {}
@Test
public void readWriteTransactionTraceTest() throws Exception {}
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java
index a24f55597..89c91b3a7 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java
@@ -38,7 +38,7 @@ public void usesDisabledSpan() {
assertThat(traceUtil.getCurrentSpan() instanceof DisabledTraceUtil.Span).isTrue();
assertThat(traceUtil.startSpan("foo") instanceof DisabledTraceUtil.Span).isTrue();
assertThat(
- traceUtil.startSpan("foo", traceUtil.getCurrentContext())
+ traceUtil.startSpan("foo", traceUtil.getCurrentSpanContext())
instanceof DisabledTraceUtil.Span)
.isTrue();
}
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java
index 2497672d9..a3620bbc2 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java
@@ -92,7 +92,7 @@ public void usesEnabledSpan() {
assertThat(traceUtil.getCurrentSpan() instanceof EnabledTraceUtil.Span).isTrue();
assertThat(traceUtil.startSpan("foo") != null).isTrue();
assertThat(
- traceUtil.startSpan("foo", traceUtil.getCurrentContext())
+ traceUtil.startSpan("foo", traceUtil.getCurrentSpanContext())
instanceof EnabledTraceUtil.Span)
.isTrue();
}
From 45da20b4a502c2bbe5b03d52f843ce5e39174c76 Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Tue, 2 Jul 2024 12:56:52 -0700
Subject: [PATCH 25/38] test: Additional Transaction Testing and cleanup
OpenCensus usage (#1505)
* test: newTransactionReadWriteTraceTest
* fix: test literal
* feat: Added tests for transaction cases
* fix: Cleanup OpenCensus dead code
* fix: updating version from 2.20.1 -> 2.21.0
* fix: reverting version from 2.21.0 -> 2.20.1
* fix: Adding an exception to the clirr-maven-plugin for an internal API parameter change from com.google.cloud.datastore.TraceUtil -> com.google.cloud.datastore.telemetry.TraceUtil
* fix: Fixing the differenceType in clirr exception
* fix: add an exception for removal of an internal class (com.google.cloud.datastore.TraceUtil)
* fix: fixing incomplete difference details for type 7005
* fix: Fixing `to` of the difference to be the entire signature
* fix: typo
---
.../clirr-ignored-differences.xml | 12 ++
.../google/cloud/datastore/DatastoreImpl.java | 17 ++-
.../RetryAndTraceDatastoreRpcDecorator.java | 5 +-
.../com/google/cloud/datastore/TraceUtil.java | 75 -----------
.../datastore/spi/v1/HttpDatastoreRpc.java | 5 +-
.../cloud/datastore/it/ITE2ETracingTest.java | 122 ++++++++++++++++--
6 files changed, 139 insertions(+), 97 deletions(-)
delete mode 100644 google-cloud-datastore/src/main/java/com/google/cloud/datastore/TraceUtil.java
diff --git a/google-cloud-datastore/clirr-ignored-differences.xml b/google-cloud-datastore/clirr-ignored-differences.xml
index 1620fd752..847ba4f4c 100644
--- a/google-cloud-datastore/clirr-ignored-differences.xml
+++ b/google-cloud-datastore/clirr-ignored-differences.xml
@@ -55,4 +55,16 @@
java.lang.Object execute(com.google.cloud.datastore.Query, com.google.cloud.datastore.ReadOption[])
7004
+
+ com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator
+ RetryAndTraceDatastoreRpcDecorator(com.google.cloud.datastore.spi.v1.DatastoreRpc, com.google.cloud.datastore.TraceUtil, com.google.api.gax.retrying.RetrySettings, com.google.cloud.datastore.DatastoreOptions)
+ RetryAndTraceDatastoreRpcDecorator(com.google.cloud.datastore.spi.v1.DatastoreRpc, com.google.cloud.datastore.telemetry.TraceUtil, com.google.api.gax.retrying.RetrySettings, com.google.cloud.datastore.DatastoreOptions)
+ 7005
+
+
+
+
+ com/google/cloud/datastore/TraceUtil
+ 8001
+
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index 0fefc3168..ea85170fe 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -25,6 +25,7 @@
import com.google.cloud.ServiceOptions;
import com.google.cloud.datastore.execution.AggregationQueryExecutor;
import com.google.cloud.datastore.spi.v1.DatastoreRpc;
+import com.google.cloud.datastore.telemetry.TraceUtil.Scope;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
@@ -39,9 +40,6 @@
import com.google.datastore.v1.RunQueryResponse;
import com.google.datastore.v1.TransactionOptions;
import com.google.protobuf.ByteString;
-import io.opencensus.common.Scope;
-import io.opencensus.trace.Span;
-import io.opencensus.trace.Status;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.SpanKind;
@@ -68,7 +66,6 @@ final class DatastoreImpl extends BaseService implements Datas
TransactionExceptionHandler.build();
private static final ExceptionHandler TRANSACTION_OPERATION_EXCEPTION_HANDLER =
TransactionOperationExceptionHandler.build();
- private final TraceUtil traceUtil = TraceUtil.getInstance();
private final com.google.cloud.datastore.telemetry.TraceUtil otelTraceUtil =
getOptions().getTraceUtil();
@@ -85,7 +82,8 @@ final class DatastoreImpl extends BaseService implements Datas
readOptionProtoPreparer = new ReadOptionProtoPreparer();
aggregationQueryExecutor =
new AggregationQueryExecutor(
- new RetryAndTraceDatastoreRpcDecorator(datastoreRpc, traceUtil, retrySettings, options),
+ new RetryAndTraceDatastoreRpcDecorator(
+ datastoreRpc, otelTraceUtil, retrySettings, options),
options);
}
@@ -744,8 +742,9 @@ void rollbackTransaction(ByteString transaction) {
}
void rollback(final com.google.datastore.v1.RollbackRequest requestPb) {
- Span span = traceUtil.startSpan(TraceUtil.SPAN_NAME_ROLLBACK);
- try (Scope scope = traceUtil.getTracer().withSpan(span)) {
+ com.google.cloud.datastore.telemetry.TraceUtil.Span span =
+ otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_ROLLBACK);
+ try (Scope scope = span.makeCurrent()) {
RetryHelper.runWithRetries(
new Callable() {
@Override
@@ -758,10 +757,10 @@ public Void call() throws DatastoreException {
EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
- span.setStatus(Status.UNKNOWN.withDescription(e.getMessage()));
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
} finally {
- span.end(TraceUtil.END_SPAN_OPTIONS);
+ span.end();
}
}
}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java
index 7abf1d360..e1ea6e8dd 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/RetryAndTraceDatastoreRpcDecorator.java
@@ -22,6 +22,7 @@
import com.google.cloud.RetryHelper;
import com.google.cloud.RetryHelper.RetryHelperException;
import com.google.cloud.datastore.spi.v1.DatastoreRpc;
+import com.google.cloud.datastore.telemetry.TraceUtil;
import com.google.datastore.v1.AllocateIdsRequest;
import com.google.datastore.v1.AllocateIdsResponse;
import com.google.datastore.v1.BeginTransactionRequest;
@@ -55,13 +56,13 @@ public class RetryAndTraceDatastoreRpcDecorator implements DatastoreRpc {
public RetryAndTraceDatastoreRpcDecorator(
DatastoreRpc datastoreRpc,
- TraceUtil traceUtil,
+ TraceUtil otelTraceUtil,
RetrySettings retrySettings,
DatastoreOptions datastoreOptions) {
this.datastoreRpc = datastoreRpc;
this.retrySettings = retrySettings;
this.datastoreOptions = datastoreOptions;
- this.otelTraceUtil = datastoreOptions.getTraceUtil();
+ this.otelTraceUtil = otelTraceUtil;
}
@Override
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TraceUtil.java
deleted file mode 100644
index 6b51d6a87..000000000
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/TraceUtil.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2020 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.cloud.datastore;
-
-import com.google.cloud.datastore.spi.v1.HttpDatastoreRpc;
-import io.opencensus.trace.EndSpanOptions;
-import io.opencensus.trace.Span;
-import io.opencensus.trace.Tracer;
-import io.opencensus.trace.Tracing;
-
-/**
- * Helper class for tracing utility. It is used for instrumenting {@link HttpDatastoreRpc} with
- * OpenCensus APIs.
- *
- * TraceUtil instances are created by the {@link TraceUtil#getInstance()} method.
- */
-public class TraceUtil {
- private final Tracer tracer = Tracing.getTracer();
- private static final TraceUtil traceUtil = new TraceUtil();
- static final String SPAN_NAME_TRANSACTION = "CloudDatastoreOperation.readWriteTransaction";
- static final String SPAN_NAME_BEGINTRANSACTION = "CloudDatastoreOperation.beginTransaction";
- static final String SPAN_NAME_COMMIT = "CloudDatastoreOperation.commit";
- static final String SPAN_NAME_LOOKUP = "CloudDatastoreOperation.lookup";
- static final String SPAN_NAME_RESERVEIDS = "CloudDatastoreOperation.reserveIds";
- static final String SPAN_NAME_ROLLBACK = "CloudDatastoreOperation.rollback";
- static final String SPAN_NAME_RUNQUERY = "CloudDatastoreOperation.runQuery";
- static final String SPAN_NAME_RUN_AGGREGATION_QUERY =
- "CloudDatastoreOperation.runAggregationQuery";
- static final EndSpanOptions END_SPAN_OPTIONS =
- EndSpanOptions.builder().setSampleToLocalSpanStore(true).build();
-
- /**
- * Starts a new span.
- *
- * @param spanName The name of the returned Span.
- * @return The newly created {@link Span}.
- */
- protected Span startSpan(String spanName) {
- return tracer.spanBuilder(spanName).startSpan();
- }
-
- /**
- * Return the global {@link Tracer}.
- *
- * @return The global {@link Tracer}.
- */
- public Tracer getTracer() {
- return tracer;
- }
-
- /**
- * Return TraceUtil Object.
- *
- * @return An instance of {@link TraceUtil}
- */
- public static TraceUtil getInstance() {
- return traceUtil;
- }
-
- private TraceUtil() {}
-}
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/spi/v1/HttpDatastoreRpc.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/spi/v1/HttpDatastoreRpc.java
index fd3cdc658..d927a2d7f 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/spi/v1/HttpDatastoreRpc.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/spi/v1/HttpDatastoreRpc.java
@@ -21,7 +21,6 @@
import com.google.api.client.http.HttpTransport;
import com.google.cloud.datastore.DatastoreException;
import com.google.cloud.datastore.DatastoreOptions;
-import com.google.cloud.datastore.TraceUtil;
import com.google.cloud.http.CensusHttpModule;
import com.google.cloud.http.HttpTransportOptions;
import com.google.datastore.v1.AllocateIdsRequest;
@@ -40,6 +39,7 @@
import com.google.datastore.v1.RunAggregationQueryResponse;
import com.google.datastore.v1.RunQueryRequest;
import com.google.datastore.v1.RunQueryResponse;
+import io.opencensus.trace.Tracing;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URL;
@@ -80,8 +80,7 @@ public HttpDatastoreRpc(DatastoreOptions options) {
private HttpRequestInitializer getHttpRequestInitializer(
final DatastoreOptions options, HttpTransportOptions httpTransportOptions) {
// Open Census initialization
- CensusHttpModule censusHttpModule =
- new CensusHttpModule(TraceUtil.getInstance().getTracer(), true);
+ CensusHttpModule censusHttpModule = new CensusHttpModule(Tracing.getTracer(), true);
final HttpRequestInitializer censusHttpModuleHttpRequestInitializer =
censusHttpModule.getHttpRequestInitializer(
httpTransportOptions.getHttpRequestInitializer(options));
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 34c7ea858..b8174184e 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -22,6 +22,7 @@
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RESERVE_IDS;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_ROLLBACK;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT;
@@ -374,6 +375,7 @@ public void after() throws Exception {
tracer = null;
retrievedTrace = null;
customSpanContext = null;
+ openTelemetrySdk = null;
}
@AfterClass
@@ -793,7 +795,7 @@ public void runAggregationQueryTraceTest() throws Exception {
}
@Test
- public void transactionalLookupTest() throws Exception {
+ public void newTransactionReadTest() throws Exception {
assertNotNull(customSpanContext);
Span rootSpan = getNewRootSpanWithContext();
@@ -817,7 +819,7 @@ public void transactionalLookupTest() throws Exception {
}
@Test
- public void transactionQueryTest() throws Exception {
+ public void newTransactionQueryTest() throws Exception {
// Set up
Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
@@ -856,6 +858,116 @@ public void transactionQueryTest() throws Exception {
Collections.singletonList(SPAN_NAME_TRANSACTION_COMMIT)));
}
+ @Test
+ public void newTransactionReadWriteTraceTest() throws Exception {
+ // Set up
+ Entity entity1 = Entity.newBuilder(KEY1).set("pepper_type", "jalapeno").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("pepper_type", "habanero").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ String simplified_spice_level = "not_spicy";
+ Entity entity1update =
+ Entity.newBuilder(entity1).set("spice_level", simplified_spice_level).build();
+
+ assertNotNull(customSpanContext);
+
+ // Test
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ Transaction transaction = datastore.newTransaction();
+ entity1 = transaction.get(KEY1);
+ switch (entity1.getString("pepper_type")) {
+ case "jalapeno":
+ simplified_spice_level = "mild";
+ break;
+
+ case "habanero":
+ simplified_spice_level = "hot";
+ break;
+ }
+ transaction.update(entity1update);
+ transaction.delete(KEY2);
+ transaction.commit();
+ assertFalse(transaction.isActive());
+ } finally {
+ rootSpan.end();
+ }
+
+ waitForTracesToComplete();
+
+ List list = datastore.fetch(KEY1, KEY2);
+ assertEquals(list.get(0), entity1update);
+ assertNull(list.get(1));
+
+ fetchAndValidateTrace(
+ customSpanContext.getTraceId(),
+ /*numExpectedSpans=*/ 3,
+ Arrays.asList(
+ Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION),
+ Collections.singletonList(SPAN_NAME_TRANSACTION_LOOKUP),
+ Collections.singletonList(SPAN_NAME_TRANSACTION_COMMIT)));
+ }
+
+ @Test
+ public void newTransactionRollbackTest() throws Exception {
+ // Set up
+ Entity entity1 = Entity.newBuilder(KEY1).set("pepper_type", "jalapeno").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("pepper_type", "habanero").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ String simplified_spice_level = "not_spicy";
+ Entity entity1update =
+ Entity.newBuilder(entity1).set("spice_level", simplified_spice_level).build();
+
+ assertNotNull(customSpanContext);
+
+ // Test
+ Span rootSpan = getNewRootSpanWithContext();
+ try (Scope ignored = rootSpan.makeCurrent()) {
+ Transaction transaction = datastore.newTransaction();
+ entity1 = transaction.get(KEY1);
+ switch (entity1.getString("pepper_type")) {
+ case "jalapeno":
+ simplified_spice_level = "mild";
+ break;
+
+ case "habanero":
+ simplified_spice_level = "hot";
+ break;
+ }
+ transaction.update(entity1update);
+ transaction.delete(KEY2);
+ transaction.rollback();
+ assertFalse(transaction.isActive());
+ } finally {
+ rootSpan.end();
+ }
+
+ waitForTracesToComplete();
+
+ List list = datastore.fetch(KEY1, KEY2);
+ assertEquals(list.get(0), entity1);
+ assertEquals(list.get(1), entity2);
+
+ fetchAndValidateTrace(
+ customSpanContext.getTraceId(),
+ /*numExpectedSpans=*/ 3,
+ Arrays.asList(
+ Collections.singletonList(SPAN_NAME_BEGIN_TRANSACTION),
+ Collections.singletonList(SPAN_NAME_TRANSACTION_LOOKUP),
+ Collections.singletonList(SPAN_NAME_ROLLBACK)));
+ }
+
@Test
public void runInTransactionQueryTest() throws Exception {
// Set up
@@ -897,10 +1009,4 @@ public void runInTransactionQueryTest() throws Exception {
Arrays.asList(SPAN_NAME_TRANSACTION_RUN, SPAN_NAME_RUN_QUERY),
Arrays.asList(SPAN_NAME_TRANSACTION_RUN, SPAN_NAME_TRANSACTION_COMMIT)));
}
-
- @Test
- public void transactionRunQueryTest() throws Exception {}
-
- @Test
- public void readWriteTransactionTraceTest() throws Exception {}
}
From db416560a5593b1b1fbb5ddacf3ef913592bd9d9 Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Wed, 10 Jul 2024 13:32:13 -0700
Subject: [PATCH 26/38] =?UTF-8?q?test:=20Adding=20ITTracingTest=20to=20ver?=
=?UTF-8?q?ify=20events=20and=20span=20attributes=20(whic=E2=80=A6=20(#151?=
=?UTF-8?q?4)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* test: Adding ITTracingTest to verify events and span attributes (which are not verified in ITE2ETracingTest) due to TraceClient API limitations.
- This test uses InMemorySpanExporter to read the generated Otel span data by the test process to verify generated span data as it were before exporting to a backend. None of the span data is exported to a durable backend.
- This test is still an E2E test as it requires a project to send RPCs to.
* fix: fixing compilation error due to missing pom dependency.
* test: Test for AllocateId and ReserveId rpcs
* test: Commit/Put/Update/Delete tests
* test: Added fixes and test for RunQuery event
---
google-cloud-datastore/pom.xml | 6 +
.../google/cloud/datastore/DatastoreImpl.java | 46 +-
.../cloud/datastore/it/ITE2ETracingTest.java | 4 +-
.../cloud/datastore/it/ITTracingTest.java | 582 ++++++++++++++++++
4 files changed, 621 insertions(+), 17 deletions(-)
create mode 100644 google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
diff --git a/google-cloud-datastore/pom.xml b/google-cloud-datastore/pom.xml
index da248be2c..c76831376 100644
--- a/google-cloud-datastore/pom.xml
+++ b/google-cloud-datastore/pom.xml
@@ -207,6 +207,12 @@
${opentelemetry.version}
test
+
+ io.opentelemetry
+ opentelemetry-sdk-testing
+ ${opentelemetry.version}
+ test
+
io.opentelemetry
opentelemetry-sdk-trace
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index ea85170fe..d491f9a93 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -34,6 +34,7 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
+import com.google.datastore.v1.CommitResponse;
import com.google.datastore.v1.ExplainOptions;
import com.google.datastore.v1.ReadOptions;
import com.google.datastore.v1.ReserveIdsRequest;
@@ -290,8 +291,6 @@ com.google.datastore.v1.RunQueryResponse runQuery(
? com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN_QUERY
: com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY);
com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(spanName);
- span.setAttribute("isTransactional", isTransactional);
- span.setAttribute("readConsistency", readOptions.getReadConsistency().toString());
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
RunQueryResponse response =
@@ -303,10 +302,17 @@ com.google.datastore.v1.RunQueryResponse runQuery(
: TRANSACTION_OPERATION_EXCEPTION_HANDLER,
getOptions().getClock());
span.addEvent(
- spanName + ": Completed",
+ spanName,
new ImmutableMap.Builder()
- .put("Received", response.getBatch().getEntityResultsCount())
- .put("More results", response.getBatch().getMoreResults().toString())
+ .put("response_count", response.getBatch().getEntityResultsCount())
+ .put("transactional", isTransactional)
+ .put("read_consistency", readOptions.getReadConsistency().toString())
+ .put(
+ "transaction_id",
+ (isTransactional
+ ? requestPb.getReadOptions().getTransaction().toStringUtf8()
+ : ""))
+ .put("more_results", response.getBatch().getMoreResults().toString())
.build());
return response;
} catch (RetryHelperException e) {
@@ -523,18 +529,18 @@ com.google.datastore.v1.LookupResponse lookup(
? com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_LOOKUP
: com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP);
com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(spanName);
- span.setAttribute("isTransactional", isTransactional);
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
() -> {
com.google.datastore.v1.LookupResponse response = datastoreRpc.lookup(requestPb);
span.addEvent(
- spanName + ": Completed",
+ spanName,
new ImmutableMap.Builder()
.put("Received", response.getFoundCount())
.put("Missing", response.getMissingCount())
.put("Deferred", response.getDeferredCount())
+ .put("isTransactional", isTransactional)
.build());
return response;
},
@@ -690,15 +696,25 @@ com.google.datastore.v1.CommitResponse commit(
? com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT
: com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(spanName);
- span.setAttribute("isTransactional", isTransactional);
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
- return RetryHelper.runWithRetries(
- () -> datastoreRpc.commit(requestPb),
- retrySettings,
- requestPb.getTransaction().isEmpty()
- ? EXCEPTION_HANDLER
- : TRANSACTION_OPERATION_EXCEPTION_HANDLER,
- getOptions().getClock());
+ CommitResponse response =
+ RetryHelper.runWithRetries(
+ () -> datastoreRpc.commit(requestPb),
+ retrySettings,
+ requestPb.getTransaction().isEmpty()
+ ? EXCEPTION_HANDLER
+ : TRANSACTION_OPERATION_EXCEPTION_HANDLER,
+ getOptions().getClock());
+ span.addEvent(
+ spanName,
+ new ImmutableMap.Builder()
+ .put("doc_count", response.getMutationResultsCount())
+ .put("transactional", isTransactional)
+ .put(
+ "transaction_id",
+ isTransactional ? requestPb.getTransaction().toStringUtf8() : "")
+ .build());
+ return response;
} catch (RetryHelperException e) {
span.end(e);
throw DatastoreException.translateAndThrow(e);
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index b8174184e..1de627158 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -334,7 +334,7 @@ public void before() throws Exception {
.setNamespace(options.getNamespace())
.build();
KEY2 =
- Key.newBuilder(projectId, kind1, "key3", options.getDatabaseId())
+ Key.newBuilder(projectId, kind1, "key2", options.getDatabaseId())
.setNamespace(options.getNamespace())
.build();
KEY3 =
@@ -342,7 +342,7 @@ public void before() throws Exception {
.setNamespace(options.getNamespace())
.build();
KEY4 =
- Key.newBuilder(projectId, kind1, "key2", options.getDatabaseId())
+ Key.newBuilder(projectId, kind1, "key4", options.getDatabaseId())
.setNamespace(options.getNamespace())
.build();
// Set up the tracer for custom TraceID injection
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
new file mode 100644
index 000000000..6432cbc9e
--- /dev/null
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
@@ -0,0 +1,582 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.datastore.it;
+
+import static com.google.cloud.datastore.telemetry.TraceUtil.*;
+import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.cloud.datastore.Datastore;
+import com.google.cloud.datastore.DatastoreOpenTelemetryOptions;
+import com.google.cloud.datastore.DatastoreOptions;
+import com.google.cloud.datastore.Entity;
+import com.google.cloud.datastore.IncompleteKey;
+import com.google.cloud.datastore.Key;
+import com.google.cloud.datastore.KeyFactory;
+import com.google.cloud.datastore.Query;
+import com.google.cloud.datastore.QueryResults;
+import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
+import com.google.cloud.datastore.testing.RemoteDatastoreHelper;
+import com.google.common.base.Preconditions;
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
+import io.opentelemetry.sdk.OpenTelemetrySdkBuilder;
+import io.opentelemetry.sdk.common.CompletableResultCode;
+import io.opentelemetry.sdk.resources.Resource;
+import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter;
+import io.opentelemetry.sdk.trace.SdkTracerProvider;
+import io.opentelemetry.sdk.trace.SpanProcessor;
+import io.opentelemetry.sdk.trace.data.EventData;
+import io.opentelemetry.sdk.trace.data.SpanData;
+import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
+import io.opentelemetry.sdk.trace.samplers.Sampler;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.Nullable;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+@RunWith(TestParameterInjector.class)
+public class ITTracingTest {
+ protected boolean isUsingGlobalOpenTelemetrySDK() {
+ return useGlobalOpenTelemetrySDK;
+ }
+
+ protected String datastoreNamedDatabase() {
+ return datastoreNamedDatabase;
+ }
+
+ private static final Logger logger =
+ Logger.getLogger(com.google.cloud.datastore.it.ITTracingTest.class.getName());
+
+ private static final int TRACE_FORCE_FLUSH_MILLIS = 1000;
+ private static final int TRACE_PROVIDER_SHUTDOWN_MILLIS = 1000;
+ private static final int IN_MEMORY_SPAN_EXPORTER_DELAY_MILLIS = 50;
+ private static final String SERVICE = "google.datastore.v1.Datastore/";
+
+ private static Key KEY1;
+
+ private static Key KEY2;
+
+ private static OpenTelemetrySdk openTelemetrySdk;
+
+ // We use an InMemorySpanExporter for testing which keeps all generated trace spans
+ // in memory so that we can check their correctness.
+ protected InMemorySpanExporter inMemorySpanExporter;
+ private static DatastoreOptions options;
+
+ protected Datastore datastore;
+ private static RemoteDatastoreHelper remoteDatastoreHelper;
+
+ @TestParameter boolean useGlobalOpenTelemetrySDK;
+
+ @TestParameter({
+ /*(default)*/
+ "",
+ "test-db"
+ })
+ String datastoreNamedDatabase;
+
+ Map spanNameToSpanId = new HashMap<>();
+ Map spanIdToParentSpanId = new HashMap<>();
+ Map spanNameToSpanData = new HashMap<>();
+
+ @Rule public TestName testName = new TestName();
+
+ @Before
+ public void before() {
+ inMemorySpanExporter = InMemorySpanExporter.create();
+
+ Resource resource =
+ Resource.getDefault().merge(Resource.builder().put(SERVICE_NAME, "Sparky").build());
+ SpanProcessor inMemorySpanProcessor = SimpleSpanProcessor.create(inMemorySpanExporter);
+ DatastoreOptions.Builder optionsBuilder = DatastoreOptions.newBuilder();
+ DatastoreOpenTelemetryOptions.Builder otelOptionsBuilder =
+ DatastoreOpenTelemetryOptions.newBuilder();
+ OpenTelemetrySdkBuilder openTelemetrySdkBuilder =
+ OpenTelemetrySdk.builder()
+ .setTracerProvider(
+ SdkTracerProvider.builder()
+ .setResource(resource)
+ .addSpanProcessor(inMemorySpanProcessor)
+ .setSampler(Sampler.alwaysOn())
+ .build());
+
+ if (isUsingGlobalOpenTelemetrySDK()) {
+ GlobalOpenTelemetry.resetForTest();
+ openTelemetrySdk = openTelemetrySdkBuilder.buildAndRegisterGlobal();
+ optionsBuilder.setOpenTelemetryOptions(otelOptionsBuilder.setTracingEnabled(true).build());
+ } else {
+ openTelemetrySdk = openTelemetrySdkBuilder.build();
+ optionsBuilder.setOpenTelemetryOptions(
+ otelOptionsBuilder.setTracingEnabled(true).setOpenTelemetry(openTelemetrySdk).build());
+ }
+
+ String namedDb = datastoreNamedDatabase();
+ logger.log(Level.INFO, "Integration test using named database " + namedDb);
+ remoteDatastoreHelper = RemoteDatastoreHelper.create(namedDb, openTelemetrySdk);
+ options = remoteDatastoreHelper.getOptions();
+ datastore = options.getService();
+
+ Preconditions.checkNotNull(
+ datastore,
+ "Error instantiating Datastore. Check that the service account credentials "
+ + "were properly set.");
+
+ String projectId = options.getProjectId();
+ String kind1 = "kind1";
+ KEY1 =
+ Key.newBuilder(projectId, kind1, "key1", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
+ KEY2 =
+ Key.newBuilder(projectId, kind1, "key2", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
+
+ cleanupTestSpanContext();
+ }
+
+ @After
+ public void after() throws Exception {
+ if (isUsingGlobalOpenTelemetrySDK()) {
+ GlobalOpenTelemetry.resetForTest();
+ }
+ remoteDatastoreHelper.deleteNamespace();
+ inMemorySpanExporter.reset();
+ CompletableResultCode completableResultCode =
+ openTelemetrySdk.getSdkTracerProvider().shutdown();
+ completableResultCode.join(TRACE_PROVIDER_SHUTDOWN_MILLIS, TimeUnit.MILLISECONDS);
+ openTelemetrySdk = null;
+ }
+
+ @AfterClass
+ public static void teardown() {}
+
+ void waitForTracesToComplete() throws Exception {
+ // The same way that querying the Cloud Trace backend may not give us the
+ // full trace on the first try, querying the in-memory traces may not result
+ // in the full trace immediately. Note that performing the `flush` is not
+ // enough. This doesn't pose an issue in practice, but can make tests flaky.
+ // Therefore, we're adding a delay to make sure we avoid any flakiness.
+ inMemorySpanExporter.flush().join(IN_MEMORY_SPAN_EXPORTER_DELAY_MILLIS, TimeUnit.MILLISECONDS);
+ TimeUnit.MILLISECONDS.sleep(IN_MEMORY_SPAN_EXPORTER_DELAY_MILLIS);
+
+ CompletableResultCode completableResultCode =
+ openTelemetrySdk.getSdkTracerProvider().forceFlush();
+ completableResultCode.join(TRACE_FORCE_FLUSH_MILLIS, TimeUnit.MILLISECONDS);
+ }
+
+ // Prepares all the spans in memory for inspection.
+ List prepareSpans() throws Exception {
+ waitForTracesToComplete();
+ List spans = inMemorySpanExporter.getFinishedSpanItems();
+ buildSpanMaps(spans);
+ printSpans();
+ return spans;
+ }
+
+ void buildSpanMaps(List spans) {
+ for (SpanData spanData : spans) {
+ spanNameToSpanData.put(spanData.getName(), spanData);
+ spanNameToSpanId.put(spanData.getName(), spanData.getSpanId());
+ spanIdToParentSpanId.put(spanData.getSpanId(), spanData.getParentSpanId());
+ }
+ }
+
+ // Returns the SpanData object for the span with the given name.
+ // Returns null if no span with the given name exists.
+ @Nullable
+ SpanData getSpanByName(String spanName) {
+ return spanNameToSpanData.get(spanName);
+ }
+
+ // Returns the SpanData object for the gRPC span with the given RPC name.
+ // Returns null if no such span exists.
+ @Nullable
+ SpanData getGrpcSpanByName(String rpcName) {
+ return getSpanByName(SERVICE + rpcName);
+ }
+
+ String grpcSpanName(String rpcName) {
+ return SERVICE + rpcName;
+ }
+
+ void assertSameTrace(SpanData... spans) {
+ if (spans.length > 1) {
+ String traceId = spans[0].getTraceId();
+ for (SpanData spanData : spans) {
+ assertEquals(traceId, spanData.getTraceId());
+ }
+ }
+ }
+
+ // Helper to see the spans in standard output while developing tests
+ void printSpans() {
+ for (SpanData spanData : spanNameToSpanData.values()) {
+ logger.log(
+ Level.FINE,
+ String.format(
+ "SPAN ID:%s, ParentID:%s, KIND:%s, TRACE ID:%s, NAME:%s, ATTRIBUTES:%s, EVENTS:%s\n",
+ spanData.getSpanId(),
+ spanData.getParentSpanId(),
+ spanData.getKind(),
+ spanData.getTraceId(),
+ spanData.getName(),
+ spanData.getAttributes().toString(),
+ spanData.getEvents().toString()));
+ }
+ }
+
+ // Asserts that the span hierarchy exists for the given span names. The hierarchy starts with the
+ // root span, followed
+ // by the child span, grandchild span, and so on. It also asserts that all the given spans belong
+ // to the same trace,
+ // and that datastore-generated spans contain the expected datastore attributes.
+ void assertSpanHierarchy(String... spanNamesHierarchy) {
+ List spanNames = Arrays.asList(spanNamesHierarchy);
+
+ for (int i = 0; i + 1 < spanNames.size(); ++i) {
+ String parentSpanName = spanNames.get(i);
+ String childSpanName = spanNames.get(i + 1);
+ SpanData parentSpan = getSpanByName(parentSpanName);
+ SpanData childSpan = getSpanByName(childSpanName);
+ assertNotNull(parentSpan);
+ assertNotNull(childSpan);
+ assertEquals(childSpan.getParentSpanId(), parentSpan.getSpanId());
+ assertSameTrace(childSpan, parentSpan);
+ // gRPC spans do not have datastore attributes.
+ if (!parentSpanName.startsWith(SERVICE)) {
+ assertHasExpectedAttributes(parentSpan);
+ }
+ if (!childSpanName.startsWith(SERVICE)) {
+ assertHasExpectedAttributes(childSpan);
+ }
+ }
+ }
+
+ void assertHasExpectedAttributes(SpanData spanData, String... additionalExpectedAttributes) {
+ // All datastore-generated spans have the settings attributes.
+ List expectedAttributes =
+ Arrays.asList(
+ "gcp.datastore.memoryUtilization",
+ "gcp.datastore.settings.host",
+ "gcp.datastore.settings.databaseId",
+ "gcp.datastore.settings.channel.needsCredentials",
+ "gcp.datastore.settings.channel.needsEndpoint",
+ "gcp.datastore.settings.channel.needsHeaders",
+ "gcp.datastore.settings.channel.shouldAutoClose",
+ "gcp.datastore.settings.channel.transportName",
+ "gcp.datastore.settings.retrySettings.maxRpcTimeout",
+ "gcp.datastore.settings.retrySettings.retryDelayMultiplier",
+ "gcp.datastore.settings.retrySettings.initialRetryDelay",
+ "gcp.datastore.settings.credentials.authenticationType",
+ "gcp.datastore.settings.retrySettings.maxAttempts",
+ "gcp.datastore.settings.retrySettings.maxRetryDelay",
+ "gcp.datastore.settings.retrySettings.rpcTimeoutMultiplier",
+ "gcp.datastore.settings.retrySettings.totalTimeout",
+ "gcp.datastore.settings.retrySettings.initialRpcTimeout");
+
+ expectedAttributes.addAll(Arrays.asList(additionalExpectedAttributes));
+
+ Attributes spanAttributes = spanData.getAttributes();
+ for (String expectedAttribute : expectedAttributes) {
+ assertNotNull(spanAttributes.get(AttributeKey.stringKey(expectedAttribute)));
+ }
+ }
+
+ // Returns true if and only if the given span data contains an event with the given name and the
+ // given expected
+ // attributes.
+ boolean hasEvent(SpanData spanData, String eventName, @Nullable Attributes expectedAttributes) {
+ if (spanData == null) {
+ return false;
+ }
+
+ logger.log(
+ Level.INFO,
+ String.format(
+ "Checking if span named '%s' (ID='%s') contains an event named '%s'",
+ spanData.getName(), spanData.getSpanId(), eventName));
+
+ List events = spanData.getEvents();
+ for (EventData event : events) {
+ if (event.getName().equals(eventName)) {
+ if (expectedAttributes == null) {
+ return true;
+ }
+
+ // Make sure attributes also match.
+ Attributes eventAttributes = event.getAttributes();
+ return expectedAttributes.equals(eventAttributes);
+ }
+ }
+ return false;
+ }
+
+ void cleanupTestSpanContext() {
+ inMemorySpanExporter.reset();
+ spanNameToSpanId.clear();
+ spanIdToParentSpanId.clear();
+ spanNameToSpanData.clear();
+ }
+
+ // This is a POJO used for testing APIs that take a POJO.
+ public static class Pojo {
+ public int bar;
+
+ public Pojo() {
+ bar = 0;
+ }
+
+ public Pojo(int bar) {
+ this.bar = bar;
+ }
+
+ public int getBar() {
+ return bar;
+ }
+
+ public void setBar(int bar) {
+ this.bar = bar;
+ }
+ }
+
+ @Test
+ public void lookupTraceTest() throws Exception {
+ Entity entity = datastore.get(KEY1);
+ assertNull(entity);
+
+ List spans = prepareSpans();
+ assertEquals(1, spans.size());
+ assertSpanHierarchy(SPAN_NAME_LOOKUP);
+ SpanData span = getSpanByName(SPAN_NAME_LOOKUP);
+ assertTrue(
+ hasEvent(
+ span,
+ SPAN_NAME_LOOKUP,
+ Attributes.builder()
+ .put("Received", 0)
+ .put("Missing", 1)
+ .put("Deferred", 0)
+ .put("transactional", false)
+ .build()));
+ }
+
+ @Test
+ public void allocateIdsTraceTest() throws Exception {
+ String kind1 = "kind1";
+ KeyFactory keyFactory = datastore.newKeyFactory().setKind(kind1);
+ IncompleteKey pk1 = keyFactory.newKey();
+ Key key1 = datastore.allocateId(pk1);
+
+ List spans = prepareSpans();
+ assertEquals(1, spans.size());
+ assertSpanHierarchy(SPAN_NAME_ALLOCATE_IDS);
+ }
+
+ @Test
+ public void reserveIdsTraceTest() throws Exception {
+ KeyFactory keyFactory = datastore.newKeyFactory().setKind("MyKind");
+ Key key1 = keyFactory.newKey(10);
+ Key key2 = keyFactory.newKey("name");
+ List keyList = datastore.reserveIds(key1, key2);
+ assertEquals(2, keyList.size());
+
+ List spans = prepareSpans();
+ assertEquals(1, spans.size());
+ assertSpanHierarchy(SPAN_NAME_RESERVE_IDS);
+ }
+
+ @Test
+ public void commitTraceTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
+ Entity response = datastore.add(entity1);
+ assertEquals(entity1, response);
+
+ List spans = prepareSpans();
+ assertEquals(1, spans.size());
+ assertSpanHierarchy(SPAN_NAME_COMMIT);
+ }
+
+ @Test
+ public void putTraceTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
+ Entity response = datastore.put(entity1);
+ assertEquals(entity1, response);
+
+ List spans = prepareSpans();
+ assertEquals(1, spans.size());
+ assertSpanHierarchy(SPAN_NAME_COMMIT);
+ }
+
+ @Test
+ public void updateTraceTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ List spans = prepareSpans();
+ assertEquals(1, spans.size());
+ assertSpanHierarchy(SPAN_NAME_COMMIT);
+
+ SpanData spanData = getSpanByName(SPAN_NAME_COMMIT);
+ assertTrue(
+ hasEvent(
+ spanData,
+ SPAN_NAME_COMMIT,
+ Attributes.builder()
+ .put("doc_count", response.size())
+ .put("transactional", false)
+ .put("transaction_id", "")
+ .build()));
+
+ // Clean Up test span context to verify update spans
+ cleanupTestSpanContext();
+
+ Entity entity1_update = Entity.newBuilder(entity1).set("test_field", "new_test_value1").build();
+ Entity entity2_update = Entity.newBuilder(entity2).set("test_field", "new_test_value1").build();
+ datastore.update(entity1_update, entity2_update);
+
+ spans = prepareSpans();
+ assertEquals(1, spans.size());
+ assertSpanHierarchy(SPAN_NAME_COMMIT);
+ }
+
+ @Test
+ public void deleteTraceTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_key", "test_value").build();
+ Entity response = datastore.put(entity1);
+ assertEquals(entity1, response);
+
+ List spans = prepareSpans();
+ assertEquals(1, spans.size());
+ assertSpanHierarchy(SPAN_NAME_COMMIT);
+
+ SpanData spanData = getSpanByName(SPAN_NAME_COMMIT);
+ assertTrue(
+ hasEvent(
+ spanData,
+ SPAN_NAME_COMMIT,
+ Attributes.builder()
+ .put("doc_count", 1)
+ .put("transactional", false)
+ .put("transaction_id", "")
+ .build()));
+
+ // Clean Up test span context to verify update spans
+ cleanupTestSpanContext();
+
+ datastore.delete(entity1.getKey());
+ spans = prepareSpans();
+ assertEquals(1, spans.size());
+ assertSpanHierarchy(SPAN_NAME_COMMIT);
+
+ spanData = getSpanByName(SPAN_NAME_COMMIT);
+ assertTrue(
+ hasEvent(
+ spanData,
+ SPAN_NAME_COMMIT,
+ Attributes.builder()
+ .put("doc_count", 1)
+ .put("transactional", false)
+ .put("transaction_id", "")
+ .build()));
+ }
+
+ @Test
+ public void runQueryTraceTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ // Clean Up test span context to verify RunQuery spans
+ cleanupTestSpanContext();
+
+ PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
+ Query query =
+ Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
+ QueryResults queryResults = datastore.run(query);
+ assertTrue(queryResults.hasNext());
+ assertEquals(entity1, queryResults.next());
+ assertFalse(queryResults.hasNext());
+
+ List spans = prepareSpans();
+ assertEquals(1, spans.size());
+ assertSpanHierarchy(SPAN_NAME_RUN_QUERY);
+
+ SpanData span = getSpanByName(SPAN_NAME_RUN_QUERY);
+ assertTrue(
+ hasEvent(
+ span,
+ SPAN_NAME_RUN_QUERY,
+ Attributes.builder()
+ .put("response_count", 1)
+ .put("transactional", false)
+ .put("read_consistency", "READ_CONSISTENCY_UNSPECIFIED")
+ .put("more_results", "NO_MORE_RESULTS")
+ .put("transaction_id", "")
+ .build()));
+ }
+
+ @Test
+ public void runAggregationQueryTraceTest() throws Exception {}
+
+ @Test
+ public void newTransactionReadTraceTest() throws Exception {}
+
+ @Test
+ public void newTransactionQueryTest() throws Exception {}
+
+ @Test
+ public void newTransactionReadWriteTraceTest() throws Exception {}
+
+ @Test
+ public void newTransactionRollbackTest() throws Exception {}
+
+ @Test
+ public void runInTransactionQueryTest() throws Exception {}
+}
From 9672e7ba20837d1241197f8ad4eddeaa2b9e9f13 Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Fri, 19 Jul 2024 11:11:27 -0700
Subject: [PATCH 27/38] test: Additional Transaction tests and AggregationQuery
test (#1518)
* test: ReadWrite Transaction test
* test: Added test for Transactional RunQuery and Transaction Rollback
* test: runInTransaction API tracing test
- Fixed setting of common span attributes to spans in runInTransaction
- Removed some gRPC related channel attributes that are not present in this Datastore version, yet.
---
.../google/cloud/datastore/DatastoreImpl.java | 12 +-
.../telemetry/DisabledTraceUtil.java | 5 +
.../datastore/telemetry/EnabledTraceUtil.java | 3 +-
.../cloud/datastore/telemetry/TraceUtil.java | 7 +
.../cloud/datastore/it/ITTracingTest.java | 292 +++++++++++++++++-
5 files changed, 303 insertions(+), 16 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index d491f9a93..3e9081d66 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -157,7 +157,7 @@ private io.opentelemetry.api.trace.Span startSpanWithParentContext(
.with(
io.opentelemetry.api.trace.Span.wrap(
parentSpanContext.getSpanContext())));
- return spanBuilder.startSpan();
+ return otelTraceUtil.addSettingsAttributesToCurrentSpan(spanBuilder).startSpan();
}
@Override
@@ -540,7 +540,10 @@ com.google.datastore.v1.LookupResponse lookup(
.put("Received", response.getFoundCount())
.put("Missing", response.getMissingCount())
.put("Deferred", response.getDeferredCount())
- .put("isTransactional", isTransactional)
+ .put("transactional", isTransactional)
+ .put(
+ "transaction_id",
+ isTransactional ? readOptions.getTransaction().toStringUtf8() : "")
.build());
return response;
},
@@ -772,6 +775,11 @@ public Void call() throws DatastoreException {
retrySettings,
EXCEPTION_HANDLER,
getOptions().getClock());
+ span.addEvent(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_ROLLBACK,
+ new ImmutableMap.Builder()
+ .put("transaction_id", requestPb.getTransaction().toStringUtf8())
+ .build());
} catch (RetryHelperException e) {
span.end(e);
throw DatastoreException.translateAndThrow(e);
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
index 6ba0fd81c..06941c721 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
@@ -22,6 +22,7 @@
import com.google.cloud.datastore.telemetry.TraceUtil.SpanContext;
import io.grpc.ManagedChannelBuilder;
import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.TracerProvider;
import java.util.Map;
@@ -115,6 +116,10 @@ public TraceUtil.Span startSpan(String spanName, TraceUtil.SpanContext parentSpa
return new Span();
}
+ public SpanBuilder addSettingsAttributesToCurrentSpan(SpanBuilder spanBuilder) {
+ return getTracer().spanBuilder("TRACING_DISABLED_NO_OP");
+ }
+
@Nonnull
@Override
public TraceUtil.Span getCurrentSpan() {
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
index 438395cb1..3b962754d 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
@@ -238,7 +238,8 @@ public Scope makeCurrent() {
}
/** Applies the current Datastore instance settings as attributes to the current Span */
- private SpanBuilder addSettingsAttributesToCurrentSpan(SpanBuilder spanBuilder) {
+ @Override
+ public SpanBuilder addSettingsAttributesToCurrentSpan(SpanBuilder spanBuilder) {
spanBuilder =
spanBuilder.setAllAttributes(
Attributes.builder()
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index dd1dcf29e..dce53e952 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -22,6 +22,7 @@
import com.google.cloud.datastore.DatastoreOptions;
import io.grpc.ManagedChannelBuilder;
import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.Tracer;
import java.util.Map;
import javax.annotation.Nonnull;
@@ -144,6 +145,12 @@ interface Scope extends AutoCloseable {
*/
Span startSpan(String spanName, SpanContext parentSpanContext);
+ /**
+ * Adds common SpanAttributes to the current span, useful when hand-creating a new Span without
+ * using the TraceUtil.Span interface.
+ */
+ SpanBuilder addSettingsAttributesToCurrentSpan(SpanBuilder spanBuilder);
+
/** Returns the current span. */
@Nonnull
Span getCurrentSpan();
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
index 6432cbc9e..485f3272e 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
@@ -16,7 +16,9 @@
package com.google.cloud.datastore.it;
+import static com.google.cloud.datastore.aggregation.Aggregation.count;
import static com.google.cloud.datastore.telemetry.TraceUtil.*;
+import static com.google.common.truth.Truth.assertThat;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -24,6 +26,9 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import com.google.cloud.datastore.AggregationQuery;
+import com.google.cloud.datastore.AggregationResult;
+import com.google.cloud.datastore.AggregationResults;
import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOpenTelemetryOptions;
import com.google.cloud.datastore.DatastoreOptions;
@@ -33,7 +38,10 @@
import com.google.cloud.datastore.KeyFactory;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.QueryResults;
+import com.google.cloud.datastore.ReadOption;
+import com.google.cloud.datastore.StructuredQuery;
import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
+import com.google.cloud.datastore.Transaction;
import com.google.cloud.datastore.testing.RemoteDatastoreHelper;
import com.google.common.base.Preconditions;
import com.google.testing.junit.testparameterinjector.TestParameter;
@@ -91,6 +99,10 @@ protected String datastoreNamedDatabase() {
private static Key KEY2;
+ private static Key KEY3;
+
+ private static Key KEY4;
+
private static OpenTelemetrySdk openTelemetrySdk;
// We use an InMemorySpanExporter for testing which keeps all generated trace spans
@@ -166,7 +178,14 @@ public void before() {
Key.newBuilder(projectId, kind1, "key2", options.getDatabaseId())
.setNamespace(options.getNamespace())
.build();
-
+ KEY3 =
+ Key.newBuilder(projectId, kind1, "key3", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
+ KEY4 =
+ Key.newBuilder(projectId, kind1, "key4", options.getDatabaseId())
+ .setNamespace(options.getNamespace())
+ .build();
cleanupTestSpanContext();
}
@@ -295,11 +314,6 @@ void assertHasExpectedAttributes(SpanData spanData, String... additionalExpected
"gcp.datastore.memoryUtilization",
"gcp.datastore.settings.host",
"gcp.datastore.settings.databaseId",
- "gcp.datastore.settings.channel.needsCredentials",
- "gcp.datastore.settings.channel.needsEndpoint",
- "gcp.datastore.settings.channel.needsHeaders",
- "gcp.datastore.settings.channel.shouldAutoClose",
- "gcp.datastore.settings.channel.transportName",
"gcp.datastore.settings.retrySettings.maxRpcTimeout",
"gcp.datastore.settings.retrySettings.retryDelayMultiplier",
"gcp.datastore.settings.retrySettings.initialRetryDelay",
@@ -380,6 +394,8 @@ public void lookupTraceTest() throws Exception {
Entity entity = datastore.get(KEY1);
assertNull(entity);
+ waitForTracesToComplete();
+
List spans = prepareSpans();
assertEquals(1, spans.size());
assertSpanHierarchy(SPAN_NAME_LOOKUP);
@@ -403,6 +419,8 @@ public void allocateIdsTraceTest() throws Exception {
IncompleteKey pk1 = keyFactory.newKey();
Key key1 = datastore.allocateId(pk1);
+ waitForTracesToComplete();
+
List spans = prepareSpans();
assertEquals(1, spans.size());
assertSpanHierarchy(SPAN_NAME_ALLOCATE_IDS);
@@ -416,6 +434,8 @@ public void reserveIdsTraceTest() throws Exception {
List keyList = datastore.reserveIds(key1, key2);
assertEquals(2, keyList.size());
+ waitForTracesToComplete();
+
List spans = prepareSpans();
assertEquals(1, spans.size());
assertSpanHierarchy(SPAN_NAME_RESERVE_IDS);
@@ -427,6 +447,8 @@ public void commitTraceTest() throws Exception {
Entity response = datastore.add(entity1);
assertEquals(entity1, response);
+ waitForTracesToComplete();
+
List spans = prepareSpans();
assertEquals(1, spans.size());
assertSpanHierarchy(SPAN_NAME_COMMIT);
@@ -438,6 +460,8 @@ public void putTraceTest() throws Exception {
Entity response = datastore.put(entity1);
assertEquals(entity1, response);
+ waitForTracesToComplete();
+
List spans = prepareSpans();
assertEquals(1, spans.size());
assertSpanHierarchy(SPAN_NAME_COMMIT);
@@ -476,6 +500,8 @@ public void updateTraceTest() throws Exception {
Entity entity2_update = Entity.newBuilder(entity2).set("test_field", "new_test_value1").build();
datastore.update(entity1_update, entity2_update);
+ waitForTracesToComplete();
+
spans = prepareSpans();
assertEquals(1, spans.size());
assertSpanHierarchy(SPAN_NAME_COMMIT);
@@ -506,6 +532,9 @@ public void deleteTraceTest() throws Exception {
cleanupTestSpanContext();
datastore.delete(entity1.getKey());
+
+ waitForTracesToComplete();
+
spans = prepareSpans();
assertEquals(1, spans.size());
assertSpanHierarchy(SPAN_NAME_COMMIT);
@@ -544,6 +573,8 @@ public void runQueryTraceTest() throws Exception {
assertEquals(entity1, queryResults.next());
assertFalse(queryResults.hasNext());
+ waitForTracesToComplete();
+
List spans = prepareSpans();
assertEquals(1, spans.size());
assertSpanHierarchy(SPAN_NAME_RUN_QUERY);
@@ -563,20 +594,255 @@ public void runQueryTraceTest() throws Exception {
}
@Test
- public void runAggregationQueryTraceTest() throws Exception {}
+ public void runAggregationQueryTraceTest() throws Exception {
+ Entity entity1 =
+ Entity.newBuilder(KEY1)
+ .set("pepper_name", "jalapeno")
+ .set("max_scoville_level", 10000)
+ .build();
+ Entity entity2 =
+ Entity.newBuilder(KEY2)
+ .set("pepper_name", "serrano")
+ .set("max_scoville_level", 25000)
+ .build();
+ Entity entity3 =
+ Entity.newBuilder(KEY3)
+ .set("pepper_name", "habanero")
+ .set("max_scoville_level", 350000)
+ .build();
+ Entity entity4 =
+ Entity.newBuilder(KEY4)
+ .set("pepper_name", "ghost")
+ .set("max_scoville_level", 1500000)
+ .build();
- @Test
- public void newTransactionReadTraceTest() throws Exception {}
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+ entityList.add(entity3);
+ entityList.add(entity4);
+
+ List response = datastore.add(entity1, entity2, entity3, entity4);
+ assertEquals(entityList, response);
+
+ // Clean Up test span context to verify RunAggregationQuery spans
+ cleanupTestSpanContext();
+
+ PropertyFilter mediumSpicyFilters = PropertyFilter.lt("max_scoville_level", 100000);
+ StructuredQuery mediumSpicyQuery =
+ Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(mediumSpicyFilters).build();
+ AggregationQuery countSpicyPeppers =
+ Query.newAggregationQueryBuilder()
+ .addAggregation(count().as("count"))
+ .over(mediumSpicyQuery)
+ .build();
+ AggregationResults results = datastore.runAggregation(countSpicyPeppers);
+ assertThat(results.size()).isEqualTo(1);
+ AggregationResult result = results.get(0);
+ assertThat(result.getLong("count")).isEqualTo(2L);
+
+ waitForTracesToComplete();
+
+ List spans = prepareSpans();
+ assertEquals(1, spans.size());
+ assertSpanHierarchy(SPAN_NAME_RUN_AGGREGATION_QUERY);
+ }
@Test
- public void newTransactionQueryTest() throws Exception {}
+ public void newTransactionReadWriteTraceTest() throws Exception {
+ // Transaction.Begin
+ Transaction transaction = datastore.newTransaction();
+
+ // Transaction.Lookup
+ Entity entity = datastore.get(KEY1, ReadOption.transactionId(transaction.getTransactionId()));
+ assertNull(entity);
+
+ Entity updatedEntity = Entity.newBuilder(KEY1).set("test_field", "new_test_value1").build();
+ transaction.put(updatedEntity);
+
+ // Transaction.Commit
+ transaction.commit();
+
+ waitForTracesToComplete();
+
+ List spans = prepareSpans();
+ assertEquals(3, spans.size());
+
+ assertSpanHierarchy(SPAN_NAME_BEGIN_TRANSACTION);
+ assertSpanHierarchy(SPAN_NAME_TRANSACTION_LOOKUP);
+ SpanData span = getSpanByName(SPAN_NAME_TRANSACTION_LOOKUP);
+ assertTrue(
+ hasEvent(
+ span,
+ SPAN_NAME_TRANSACTION_LOOKUP,
+ Attributes.builder()
+ .put("Deferred", 0)
+ .put("Missing", 1)
+ .put("Received", 0)
+ .put("transactional", true)
+ .put("transaction_id", transaction.getTransactionId().toStringUtf8())
+ .build()));
+
+ assertSpanHierarchy(SPAN_NAME_TRANSACTION_COMMIT);
+ span = getSpanByName(SPAN_NAME_TRANSACTION_COMMIT);
+ assertTrue(
+ hasEvent(
+ span,
+ SPAN_NAME_TRANSACTION_COMMIT,
+ Attributes.builder()
+ .put("doc_count", 1)
+ .put("transactional", true)
+ .put("transaction_id", transaction.getTransactionId().toStringUtf8())
+ .build()));
+ }
@Test
- public void newTransactionReadWriteTraceTest() throws Exception {}
+ public void newTransactionQueryTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ // Clean Up test span context to verify Transaction RunQuery spans
+ cleanupTestSpanContext();
+
+ Transaction transaction = datastore.newTransaction();
+ PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
+ Query query =
+ Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
+ QueryResults queryResults = transaction.run(query);
+ transaction.commit();
+ assertTrue(queryResults.hasNext());
+ assertEquals(entity1, queryResults.next());
+ assertFalse(queryResults.hasNext());
+
+ waitForTracesToComplete();
+
+ List spans = prepareSpans();
+ assertEquals(3, spans.size());
+
+ assertSpanHierarchy(SPAN_NAME_BEGIN_TRANSACTION);
+ assertSpanHierarchy(SPAN_NAME_TRANSACTION_RUN_QUERY);
+ assertSpanHierarchy(SPAN_NAME_TRANSACTION_COMMIT);
+ SpanData span = getSpanByName(SPAN_NAME_TRANSACTION_RUN_QUERY);
+ assertTrue(
+ hasEvent(
+ span,
+ SPAN_NAME_TRANSACTION_RUN_QUERY,
+ Attributes.builder()
+ .put("response_count", 1)
+ .put("transactional", true)
+ .put("read_consistency", "READ_CONSISTENCY_UNSPECIFIED")
+ .put("more_results", "NO_MORE_RESULTS")
+ .put("transaction_id", transaction.getTransactionId().toStringUtf8())
+ .build()));
+ }
@Test
- public void newTransactionRollbackTest() throws Exception {}
+ public void newTransactionRollbackTest() throws Exception {
+ Entity entity1 = Entity.newBuilder(KEY1).set("pepper_type", "jalapeno").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("pepper_type", "habanero").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ // Clean Up test span context to verify Transaction Rollback spans
+ cleanupTestSpanContext();
+
+ String simplified_spice_level = "not_spicy";
+ Entity entity1update =
+ Entity.newBuilder(entity1).set("spice_level", simplified_spice_level).build();
+ Transaction transaction = datastore.newTransaction();
+ entity1 = transaction.get(KEY1);
+ switch (entity1.getString("pepper_type")) {
+ case "jalapeno":
+ simplified_spice_level = "mild";
+ break;
+
+ case "habanero":
+ simplified_spice_level = "hot";
+ break;
+ }
+ transaction.update(entity1update);
+ transaction.delete(KEY2);
+ transaction.rollback();
+ assertFalse(transaction.isActive());
+
+ waitForTracesToComplete();
+
+ List spans = prepareSpans();
+ assertEquals(3, spans.size());
+
+ assertSpanHierarchy(SPAN_NAME_BEGIN_TRANSACTION);
+ assertSpanHierarchy(SPAN_NAME_TRANSACTION_LOOKUP);
+ SpanData span = getSpanByName(SPAN_NAME_TRANSACTION_LOOKUP);
+ assertTrue(
+ hasEvent(
+ span,
+ SPAN_NAME_TRANSACTION_LOOKUP,
+ Attributes.builder()
+ .put("Deferred", 0)
+ .put("Missing", 0)
+ .put("Received", 1)
+ .put("transactional", true)
+ .put("transaction_id", transaction.getTransactionId().toStringUtf8())
+ .build()));
+
+ assertSpanHierarchy(SPAN_NAME_ROLLBACK);
+ span = getSpanByName(SPAN_NAME_ROLLBACK);
+ assertTrue(
+ hasEvent(
+ span,
+ SPAN_NAME_ROLLBACK,
+ Attributes.builder()
+ .put("transaction_id", transaction.getTransactionId().toStringUtf8())
+ .build()));
+ }
@Test
- public void runInTransactionQueryTest() throws Exception {}
+ public void runInTransactionQueryTest() throws Exception {
+ // Set up
+ Entity entity1 = Entity.newBuilder(KEY1).set("test_field", "test_value1").build();
+ Entity entity2 = Entity.newBuilder(KEY2).set("test_field", "test_value2").build();
+ List entityList = new ArrayList<>();
+ entityList.add(entity1);
+ entityList.add(entity2);
+
+ List response = datastore.add(entity1, entity2);
+ assertEquals(entityList, response);
+
+ // Clean Up test span context to verify Transaction Rollback spans
+ cleanupTestSpanContext();
+
+ PropertyFilter filter = PropertyFilter.eq("test_field", entity1.getValue("test_field"));
+ Query query =
+ Query.newEntityQueryBuilder().setKind(KEY1.getKind()).setFilter(filter).build();
+ Datastore.TransactionCallable callable =
+ transaction -> {
+ QueryResults queryResults = datastore.run(query);
+ assertTrue(queryResults.hasNext());
+ assertEquals(entity1, queryResults.next());
+ assertFalse(queryResults.hasNext());
+ return true;
+ };
+ datastore.runInTransaction(callable);
+
+ waitForTracesToComplete();
+
+ List spans = prepareSpans();
+ assertEquals(4, spans.size());
+
+ // Since the runInTransaction method runs the TransactionCallable opaquely in a transaction
+ // there is no way for the API user to know the transaction ID, so we will not validate it here.
+ assertSpanHierarchy(SPAN_NAME_TRANSACTION_RUN, SPAN_NAME_BEGIN_TRANSACTION);
+ assertSpanHierarchy(SPAN_NAME_TRANSACTION_RUN, SPAN_NAME_RUN_QUERY);
+ assertSpanHierarchy(SPAN_NAME_TRANSACTION_RUN, SPAN_NAME_TRANSACTION_COMMIT);
+ }
}
From f13184efd5528a959bc41dd84e294317506025bb Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Mon, 5 Aug 2024 11:19:43 -0700
Subject: [PATCH 28/38] fix: Undelete gRPC upgrade docs
---
README.md | 106 +++---------------------------------------------------
1 file changed, 5 insertions(+), 101 deletions(-)
diff --git a/README.md b/README.md
index 9089655ec..4520f2779 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file:
com.google.cloud
libraries-bom
- 26.41.0
+ 26.40.0
pom
import
@@ -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.42.0')
+implementation platform('com.google.cloud:libraries-bom:26.40.0')
implementation 'com.google.cloud:google-cloud-datastore'
```
If you are using Gradle without BOM, add this to your dependencies:
```Groovy
-implementation 'com.google.cloud:google-cloud-datastore:2.20.2'
+implementation 'com.google.cloud:google-cloud-datastore:2.20.0'
```
If you are using SBT, add this to your dependencies:
```Scala
-libraryDependencies += "com.google.cloud" % "google-cloud-datastore" % "2.20.2"
+libraryDependencies += "com.google.cloud" % "google-cloud-datastore" % "2.20.0"
```
@@ -210,102 +210,6 @@ running on Compute Engine or from your own desktop. To run the example on App En
the code from the main method to your application's servlet class and change the print statements to
display on your webpage.
-gRPC Java Datastore Client User Guide
--------
-In this feature launch, the [Java Datastore client](https://github.com/googleapis/java-datastore) now offers gRPC as a transport layer option with experimental support. Using [gRPC connection pooling](https://grpc.io/docs/guides/performance/) enables distributing RPCs over multiple connections which may improve performance.
-
-#### Download Instructions
-Instructions:
-1. Clone the grpc-experimental branch from GitHub:
-```python
-git clone -b grpc-experimental https://github.com/googleapis/java-datastore.git
-```
-2. Run the following commands to build the library:
-```python
-# Go to the directory the code was downloaded to
-cd java-datastore/
-
-# Build the library
-mvn clean install -DskipTests=true
-```
-3. Add the following dependency to your project:
-```xml
-
- com.google.cloud
- google-cloud-datastore
- 2.20.0-grpc-experimental-1-SNAPSHOT
-
-```
-
-#### How to Use
-To opt-in to the gRPC transport behavior, simply add the below line of code (`setTransportOptions`) to your Datastore client instantiation.
-
-Example:
-```java
-DatastoreOptions datastoreOptions =
- DatastoreOptions.newBuilder()
- .setProjectId("my-project")
- .setDatabaseId("my-database")
- .setTransportOptions(GrpcTransportOptions.newBuilder().build())
- .build();
-```
-Setting the transport options explicitly to `GrpcTransportOptions` will signal the client to use gRPC instead of HTTP when making calls to the server.
-
-To revert back to the existing stable behavior and transport, simply remove the transport options line or replace it with `HttpTransportOptions`. Please note this will require an application rebuild and restart.
-Example:
-```java
-// will default to existing HTTP transport behavior
-DatastoreOptions datastoreOptions = DatastoreOptions.newBuilder()
- .setProjectId("my-project")
- .setDatabaseId("my-database")
- .build();
-
-// will also default to existing HTTP transport behavior
-DatastoreOptions datastoreOptions =
- DatastoreOptions.newBuilder()
- .setProjectId("my-project")
- .setDatabaseId("my-database")
- .setTransportOptions(HttpTransportOptions.newBuilder()
- .setConnectTimeout(1000)
- .build()).build();
-```
-
-Note: client instantiations that already use `setTransportOptions` with `HttpTransportOptions` will continue to have the same behavior. Only transports that are explicitly set to gRPC will change.
-
-#### Verify Datastore Transport Options Type
-To verify which type of TransportOptions you have successfully configured, you can use the below lines of code to compare transport options type:
-```java
-// checks if using gRPC transport options
-boolean isGRPC = datastore.getOptions().getTransportOptions() instanceof GrpcTransportOptions;
-
-// checks if using HTTP transport options
-boolean isHTTP = datastore.getOptions().getTransportOptions() instanceof HTTPTransportOptions;
-```
-
-#### New Features
-There are new gRPC specific features available to use in this update.
-
-##### Channel Pooling
-To customize the number of channels your client uses, you can update the channel provider in the DatastoreOptions.
-See [ChannelPoolSettings](https://cloud.google.com/java/docs/reference/gax/latest/com.google.api.gax.grpc.ChannelPoolSettings) and [Performance Best Practices](https://grpc.io/docs/guides/performance/) for more information on channel pools and best practices for performance.
-
-Example:
-```java
-InstantiatingGrpcChannelProvider channelProvider =
- DatastoreSettings.defaultGrpcTransportProviderBuilder()
- .setChannelPoolSettings(
- ChannelPoolSettings.builder()
- .setInitialChannelCount(MIN_VAL)
- .setMaxChannelCount(MAX_VAL)
- .build())
- .build();
-
-DatastoreOptions options = DatastoreOptions.newBuilder()
- .setProjectId("my-project")
- .setChannelProvider(channelProvider)
- .setTransportOptions(GrpcTransportOptions.newBuilder().build())
- .build();
-```
Testing
-------
@@ -480,7 +384,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-datastore/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-datastore.svg
-[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-datastore/2.20.2
+[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-datastore/2.20.0
[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
From 520e35108c1a8f6b2b0203916b1d2ee2a176b36a Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Mon, 5 Aug 2024 11:23:34 -0700
Subject: [PATCH 29/38] fix: Undo merge mistakes
---
README.md | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
diff --git a/README.md b/README.md
index 4520f2779..308b4669b 100644
--- a/README.md
+++ b/README.md
@@ -210,6 +210,102 @@ running on Compute Engine or from your own desktop. To run the example on App En
the code from the main method to your application's servlet class and change the print statements to
display on your webpage.
+gRPC Java Datastore Client User Guide
+-------
+In this feature launch, the [Java Datastore client](https://github.com/googleapis/java-datastore) now offers gRPC as a transport layer option with experimental support. Using [gRPC connection pooling](https://grpc.io/docs/guides/performance/) enables distributing RPCs over multiple connections which may improve performance.
+
+#### Download Instructions
+Instructions:
+1. Clone the grpc-experimental branch from GitHub:
+```python
+git clone -b grpc-experimental https://github.com/googleapis/java-datastore.git
+```
+2. Run the following commands to build the library:
+```python
+# Go to the directory the code was downloaded to
+cd java-datastore/
+
+# Build the library
+mvn clean install -DskipTests=true
+```
+3. Add the following dependency to your project:
+```xml
+
+ com.google.cloud
+ google-cloud-datastore
+ 2.20.0-grpc-experimental-1-SNAPSHOT
+
+```
+
+#### How to Use
+To opt-in to the gRPC transport behavior, simply add the below line of code (`setTransportOptions`) to your Datastore client instantiation.
+
+Example:
+```java
+DatastoreOptions datastoreOptions =
+ DatastoreOptions.newBuilder()
+ .setProjectId("my-project")
+ .setDatabaseId("my-database")
+ .setTransportOptions(GrpcTransportOptions.newBuilder().build())
+ .build();
+```
+Setting the transport options explicitly to `GrpcTransportOptions` will signal the client to use gRPC instead of HTTP when making calls to the server.
+
+To revert back to the existing stable behavior and transport, simply remove the transport options line or replace it with `HttpTransportOptions`. Please note this will require an application rebuild and restart.
+Example:
+```java
+// will default to existing HTTP transport behavior
+DatastoreOptions datastoreOptions = DatastoreOptions.newBuilder()
+ .setProjectId("my-project")
+ .setDatabaseId("my-database")
+ .build();
+
+// will also default to existing HTTP transport behavior
+DatastoreOptions datastoreOptions =
+ DatastoreOptions.newBuilder()
+ .setProjectId("my-project")
+ .setDatabaseId("my-database")
+ .setTransportOptions(HttpTransportOptions.newBuilder()
+ .setConnectTimeout(1000)
+ .build()).build();
+```
+
+Note: client instantiations that already use `setTransportOptions` with `HttpTransportOptions` will continue to have the same behavior. Only transports that are explicitly set to gRPC will change.
+
+#### Verify Datastore Transport Options Type
+To verify which type of TransportOptions you have successfully configured, you can use the below lines of code to compare transport options type:
+```java
+// checks if using gRPC transport options
+boolean isGRPC = datastore.getOptions().getTransportOptions() instanceof GrpcTransportOptions;
+
+// checks if using HTTP transport options
+boolean isHTTP = datastore.getOptions().getTransportOptions() instanceof HTTPTransportOptions;
+```
+
+#### New Features
+There are new gRPC specific features available to use in this update.
+
+##### Channel Pooling
+To customize the number of channels your client uses, you can update the channel provider in the DatastoreOptions.
+See [ChannelPoolSettings](https://cloud.google.com/java/docs/reference/gax/latest/com.google.api.gax.grpc.ChannelPoolSettings) and [Performance Best Practices](https://grpc.io/docs/guides/performance/) for more information on channel pools and best practices for performance.
+
+Example:
+```java
+InstantiatingGrpcChannelProvider channelProvider =
+ DatastoreSettings.defaultGrpcTransportProviderBuilder()
+ .setChannelPoolSettings(
+ ChannelPoolSettings.builder()
+ .setInitialChannelCount(MIN_VAL)
+ .setMaxChannelCount(MAX_VAL)
+ .build())
+ .build();
+
+DatastoreOptions options = DatastoreOptions.newBuilder()
+ .setProjectId("my-project")
+ .setChannelProvider(channelProvider)
+ .setTransportOptions(GrpcTransportOptions.newBuilder().build())
+ .build();
+```
Testing
-------
From acf19d41e4f4716098633ffd2e4dc45a497bb041 Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Mon, 5 Aug 2024 23:29:37 -0700
Subject: [PATCH 30/38] fix: Updating span event strings (#1539)
* fix: Fixing user-facing span names in line with go/firestore-client-trace-catalog
* fix: updating bom dependency version to fix https://github.com/googleapis/java-datastore/actions/runs/10256441634/job/28375496112?pr=1539
---
google-cloud-datastore/pom.xml | 2 +-
.../google/cloud/datastore/DatastoreImpl.java | 8 +++----
.../cloud/datastore/it/ITTracingTest.java | 23 ++++++++++---------
3 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/google-cloud-datastore/pom.xml b/google-cloud-datastore/pom.xml
index c76831376..ea07bc979 100644
--- a/google-cloud-datastore/pom.xml
+++ b/google-cloud-datastore/pom.xml
@@ -16,7 +16,7 @@
google-cloud-datastore
- 1.38.0
+ 1.39.0
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index 3e9081d66..e4db9620b 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -302,9 +302,9 @@ com.google.datastore.v1.RunQueryResponse runQuery(
: TRANSACTION_OPERATION_EXCEPTION_HANDLER,
getOptions().getClock());
span.addEvent(
- spanName,
+ spanName + " complete.",
new ImmutableMap.Builder()
- .put("response_count", response.getBatch().getEntityResultsCount())
+ .put("doc_count", response.getBatch().getEntityResultsCount())
.put("transactional", isTransactional)
.put("read_consistency", readOptions.getReadConsistency().toString())
.put(
@@ -535,7 +535,7 @@ com.google.datastore.v1.LookupResponse lookup(
() -> {
com.google.datastore.v1.LookupResponse response = datastoreRpc.lookup(requestPb);
span.addEvent(
- spanName,
+ spanName + " complete.",
new ImmutableMap.Builder()
.put("Received", response.getFoundCount())
.put("Missing", response.getMissingCount())
@@ -709,7 +709,7 @@ com.google.datastore.v1.CommitResponse commit(
: TRANSACTION_OPERATION_EXCEPTION_HANDLER,
getOptions().getClock());
span.addEvent(
- spanName,
+ spanName + " complete.",
new ImmutableMap.Builder()
.put("doc_count", response.getMutationResultsCount())
.put("transactional", isTransactional)
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
index 485f3272e..85ff4758b 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
@@ -403,12 +403,13 @@ public void lookupTraceTest() throws Exception {
assertTrue(
hasEvent(
span,
- SPAN_NAME_LOOKUP,
+ SPAN_NAME_LOOKUP + " complete.",
Attributes.builder()
.put("Received", 0)
.put("Missing", 1)
.put("Deferred", 0)
.put("transactional", false)
+ .put("transaction_id", "")
.build()));
}
@@ -486,7 +487,7 @@ public void updateTraceTest() throws Exception {
assertTrue(
hasEvent(
spanData,
- SPAN_NAME_COMMIT,
+ SPAN_NAME_COMMIT + " complete.",
Attributes.builder()
.put("doc_count", response.size())
.put("transactional", false)
@@ -521,7 +522,7 @@ public void deleteTraceTest() throws Exception {
assertTrue(
hasEvent(
spanData,
- SPAN_NAME_COMMIT,
+ SPAN_NAME_COMMIT + " complete.",
Attributes.builder()
.put("doc_count", 1)
.put("transactional", false)
@@ -543,7 +544,7 @@ public void deleteTraceTest() throws Exception {
assertTrue(
hasEvent(
spanData,
- SPAN_NAME_COMMIT,
+ SPAN_NAME_COMMIT + " complete.",
Attributes.builder()
.put("doc_count", 1)
.put("transactional", false)
@@ -583,9 +584,9 @@ public void runQueryTraceTest() throws Exception {
assertTrue(
hasEvent(
span,
- SPAN_NAME_RUN_QUERY,
+ SPAN_NAME_RUN_QUERY + " complete.",
Attributes.builder()
- .put("response_count", 1)
+ .put("doc_count", 1)
.put("transactional", false)
.put("read_consistency", "READ_CONSISTENCY_UNSPECIFIED")
.put("more_results", "NO_MORE_RESULTS")
@@ -674,7 +675,7 @@ public void newTransactionReadWriteTraceTest() throws Exception {
assertTrue(
hasEvent(
span,
- SPAN_NAME_TRANSACTION_LOOKUP,
+ SPAN_NAME_TRANSACTION_LOOKUP + " complete.",
Attributes.builder()
.put("Deferred", 0)
.put("Missing", 1)
@@ -688,7 +689,7 @@ public void newTransactionReadWriteTraceTest() throws Exception {
assertTrue(
hasEvent(
span,
- SPAN_NAME_TRANSACTION_COMMIT,
+ SPAN_NAME_TRANSACTION_COMMIT + " complete.",
Attributes.builder()
.put("doc_count", 1)
.put("transactional", true)
@@ -732,9 +733,9 @@ public void newTransactionQueryTest() throws Exception {
assertTrue(
hasEvent(
span,
- SPAN_NAME_TRANSACTION_RUN_QUERY,
+ SPAN_NAME_TRANSACTION_RUN_QUERY + " complete.",
Attributes.builder()
- .put("response_count", 1)
+ .put("doc_count", 1)
.put("transactional", true)
.put("read_consistency", "READ_CONSISTENCY_UNSPECIFIED")
.put("more_results", "NO_MORE_RESULTS")
@@ -786,7 +787,7 @@ public void newTransactionRollbackTest() throws Exception {
assertTrue(
hasEvent(
span,
- SPAN_NAME_TRANSACTION_LOOKUP,
+ SPAN_NAME_TRANSACTION_LOOKUP + " complete.",
Attributes.builder()
.put("Deferred", 0)
.put("Missing", 0)
From d903850a02a86117334d8e9845f3c892895cdb9e Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Wed, 4 Sep 2024 10:07:09 -0700
Subject: [PATCH 31/38] Fix: typo in test causing integration test failure
(#1556)
https://btx.cloud.google.com/invocations/c11a2e8b-4494-4ddc-a77e-cf2bcbcf5254/targets/cloud-devrel%2Fclient-libraries%2Fjava%2Fjava-datastore%2Fpresubmit%2Fintegration;config=default/log
---
.../java/com/google/cloud/datastore/it/ITE2ETracingTest.java | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
index 1de627158..bee54a1f0 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITE2ETracingTest.java
@@ -338,7 +338,7 @@ public void before() throws Exception {
.setNamespace(options.getNamespace())
.build();
KEY3 =
- Key.newBuilder(projectId, kind1, "key4", options.getDatabaseId())
+ Key.newBuilder(projectId, kind1, "key3", options.getDatabaseId())
.setNamespace(options.getNamespace())
.build();
KEY4 =
@@ -381,9 +381,6 @@ public void after() throws Exception {
@AfterClass
public static void teardown() throws Exception {
traceClient_v1.close();
- CompletableResultCode completableResultCode =
- openTelemetrySdk.getSdkTracerProvider().shutdown();
- completableResultCode.join(TRACE_PROVIDER_SHUTDOWN_MILLIS, TimeUnit.MILLISECONDS);
}
// Generates a random hex string of length `numBytes`
From 83ce822aeb3f15d574e8a1bb60512240f36d68b1 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Mon, 16 Sep 2024 13:40:37 -0700
Subject: [PATCH 32/38] fix: opentelemetry-sdk should only be used as a Test
Dependency
---
google-cloud-datastore/pom.xml | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/google-cloud-datastore/pom.xml b/google-cloud-datastore/pom.xml
index ea07bc979..b263c0395 100644
--- a/google-cloud-datastore/pom.xml
+++ b/google-cloud-datastore/pom.xml
@@ -129,11 +129,6 @@
-
- io.opentelemetry
- opentelemetry-sdk
- ${opentelemetry.version}
-
io.opentelemetry
opentelemetry-api
@@ -201,6 +196,11 @@
test
+
+ io.opentelemetry
+ opentelemetry-sdk
+ ${opentelemetry.version}
+
io.opentelemetry
opentelemetry-sdk-common
From 45541d317ba8175b85f5dd095c9b8c1675a1b91c Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Mon, 16 Sep 2024 14:09:42 -0700
Subject: [PATCH 33/38] fix: Update opentelemetry.version - this also fixes the
tests failing in
https://github.com/googleapis/java-datastore/actions/runs/10891578591/job/30222786908
---
google-cloud-datastore/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/google-cloud-datastore/pom.xml b/google-cloud-datastore/pom.xml
index b263c0395..a462d394c 100644
--- a/google-cloud-datastore/pom.xml
+++ b/google-cloud-datastore/pom.xml
@@ -16,7 +16,7 @@
google-cloud-datastore
- 1.39.0
+ 1.42.1
From da943a1e5d31070ac324479e0d86b512e516a498 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Mon, 16 Sep 2024 14:26:51 -0700
Subject: [PATCH 34/38] fix: Replacing attribute key values w/ constants
---
.../google/cloud/datastore/DatastoreImpl.java | 46 ++++++-----
.../cloud/datastore/telemetry/TraceUtil.java | 13 ++++
.../cloud/datastore/it/ITTracingTest.java | 76 +++++++++----------
3 files changed, 80 insertions(+), 55 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index e4db9620b..11ff58bc9 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -16,6 +16,18 @@
package com.google.cloud.datastore;
+import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_DEFERRED;
+import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_DOCUMENT_COUNT;
+import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_EXCEPTION_MESSAGE;
+import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_EXCEPTION_STACKTRACE;
+import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_EXCEPTION_TYPE;
+import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_MISSING;
+import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_MORE_RESULTS;
+import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_READ_CONSISTENCY;
+import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_RECEIVED;
+import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_TRANSACTIONAL;
+import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_TRANSACTION_ID;
+
import com.google.api.core.BetaApi;
import com.google.api.gax.retrying.RetrySettings;
import com.google.cloud.BaseService;
@@ -182,9 +194,9 @@ public T call() throws DatastoreException {
span.recordException(
ex,
Attributes.builder()
- .put("exception.message", ex.getMessage())
- .put("exception.type", ex.getClass().getName())
- .put("exception.stacktrace", Throwables.getStackTraceAsString(ex))
+ .put(ATTRIBUTES_KEY_EXCEPTION_MESSAGE, ex.getMessage())
+ .put(ATTRIBUTES_KEY_EXCEPTION_TYPE, ex.getClass().getName())
+ .put(ATTRIBUTES_KEY_EXCEPTION_STACKTRACE, Throwables.getStackTraceAsString(ex))
.build());
span.end();
throw DatastoreException.propagateUserException(ex);
@@ -304,15 +316,15 @@ com.google.datastore.v1.RunQueryResponse runQuery(
span.addEvent(
spanName + " complete.",
new ImmutableMap.Builder()
- .put("doc_count", response.getBatch().getEntityResultsCount())
- .put("transactional", isTransactional)
- .put("read_consistency", readOptions.getReadConsistency().toString())
+ .put(ATTRIBUTES_KEY_DOCUMENT_COUNT, response.getBatch().getEntityResultsCount())
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, isTransactional)
+ .put(ATTRIBUTES_KEY_READ_CONSISTENCY, readOptions.getReadConsistency().toString())
.put(
- "transaction_id",
+ ATTRIBUTES_KEY_TRANSACTION_ID,
(isTransactional
? requestPb.getReadOptions().getTransaction().toStringUtf8()
: ""))
- .put("more_results", response.getBatch().getMoreResults().toString())
+ .put(ATTRIBUTES_KEY_MORE_RESULTS, response.getBatch().getMoreResults().toString())
.build());
return response;
} catch (RetryHelperException e) {
@@ -537,12 +549,12 @@ com.google.datastore.v1.LookupResponse lookup(
span.addEvent(
spanName + " complete.",
new ImmutableMap.Builder()
- .put("Received", response.getFoundCount())
- .put("Missing", response.getMissingCount())
- .put("Deferred", response.getDeferredCount())
- .put("transactional", isTransactional)
+ .put(ATTRIBUTES_KEY_RECEIVED, response.getFoundCount())
+ .put(ATTRIBUTES_KEY_MISSING, response.getMissingCount())
+ .put(ATTRIBUTES_KEY_DEFERRED, response.getDeferredCount())
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, isTransactional)
.put(
- "transaction_id",
+ ATTRIBUTES_KEY_TRANSACTION_ID,
isTransactional ? readOptions.getTransaction().toStringUtf8() : "")
.build());
return response;
@@ -711,10 +723,10 @@ com.google.datastore.v1.CommitResponse commit(
span.addEvent(
spanName + " complete.",
new ImmutableMap.Builder()
- .put("doc_count", response.getMutationResultsCount())
- .put("transactional", isTransactional)
+ .put(ATTRIBUTES_KEY_DOCUMENT_COUNT, response.getMutationResultsCount())
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, isTransactional)
.put(
- "transaction_id",
+ ATTRIBUTES_KEY_TRANSACTION_ID,
isTransactional ? requestPb.getTransaction().toStringUtf8() : "")
.build());
return response;
@@ -778,7 +790,7 @@ public Void call() throws DatastoreException {
span.addEvent(
com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_ROLLBACK,
new ImmutableMap.Builder()
- .put("transaction_id", requestPb.getTransaction().toStringUtf8())
+ .put(ATTRIBUTES_KEY_TRANSACTION_ID, requestPb.getTransaction().toStringUtf8())
.build());
} catch (RetryHelperException e) {
span.end(e);
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index dce53e952..245b825e1 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -48,6 +48,19 @@ public interface TraceUtil {
static final String SPAN_NAME_ROLLBACK = "Transaction.Rollback";
static final String SPAN_NAME_TRANSACTION_RUN_AGGREGATION_QUERY =
"Transaction.RunAggregationQuery";
+
+ static final String ATTRIBUTES_KEY_EXCEPTION_MESSAGE = "exception.message";
+ static final String ATTRIBUTES_KEY_EXCEPTION_TYPE = "exception.type";
+ static final String ATTRIBUTES_KEY_EXCEPTION_STACKTRACE = "exception.stacktrace";
+ static final String ATTRIBUTES_KEY_DOCUMENT_COUNT = "doc_count";
+ static final String ATTRIBUTES_KEY_TRANSACTIONAL = "transactional";
+ static final String ATTRIBUTES_KEY_TRANSACTION_ID = "transaction_id";
+ static final String ATTRIBUTES_KEY_READ_CONSISTENCY = "read_consistency";
+ static final String ATTRIBUTES_KEY_RECEIVED = "Received";
+ static final String ATTRIBUTES_KEY_MISSING = "Missing";
+ static final String ATTRIBUTES_KEY_DEFERRED = "Deferred";
+ static final String ATTRIBUTES_KEY_MORE_RESULTS = "mor_results";
+
/**
* Creates and returns an instance of the TraceUtil class.
*
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
index 85ff4758b..aefb51352 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITTracingTest.java
@@ -405,11 +405,11 @@ public void lookupTraceTest() throws Exception {
span,
SPAN_NAME_LOOKUP + " complete.",
Attributes.builder()
- .put("Received", 0)
- .put("Missing", 1)
- .put("Deferred", 0)
- .put("transactional", false)
- .put("transaction_id", "")
+ .put(ATTRIBUTES_KEY_RECEIVED, 0)
+ .put(ATTRIBUTES_KEY_MISSING, 1)
+ .put(ATTRIBUTES_KEY_DEFERRED, 0)
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, false)
+ .put(ATTRIBUTES_KEY_TRANSACTION_ID, "")
.build()));
}
@@ -489,9 +489,9 @@ public void updateTraceTest() throws Exception {
spanData,
SPAN_NAME_COMMIT + " complete.",
Attributes.builder()
- .put("doc_count", response.size())
- .put("transactional", false)
- .put("transaction_id", "")
+ .put(ATTRIBUTES_KEY_DOCUMENT_COUNT, response.size())
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, false)
+ .put(ATTRIBUTES_KEY_TRANSACTION_ID, "")
.build()));
// Clean Up test span context to verify update spans
@@ -524,9 +524,9 @@ public void deleteTraceTest() throws Exception {
spanData,
SPAN_NAME_COMMIT + " complete.",
Attributes.builder()
- .put("doc_count", 1)
- .put("transactional", false)
- .put("transaction_id", "")
+ .put(ATTRIBUTES_KEY_DOCUMENT_COUNT, 1)
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, false)
+ .put(ATTRIBUTES_KEY_TRANSACTION_ID, "")
.build()));
// Clean Up test span context to verify update spans
@@ -546,9 +546,9 @@ public void deleteTraceTest() throws Exception {
spanData,
SPAN_NAME_COMMIT + " complete.",
Attributes.builder()
- .put("doc_count", 1)
- .put("transactional", false)
- .put("transaction_id", "")
+ .put(ATTRIBUTES_KEY_DOCUMENT_COUNT, 1)
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, false)
+ .put(ATTRIBUTES_KEY_TRANSACTION_ID, "")
.build()));
}
@@ -586,11 +586,11 @@ public void runQueryTraceTest() throws Exception {
span,
SPAN_NAME_RUN_QUERY + " complete.",
Attributes.builder()
- .put("doc_count", 1)
- .put("transactional", false)
- .put("read_consistency", "READ_CONSISTENCY_UNSPECIFIED")
- .put("more_results", "NO_MORE_RESULTS")
- .put("transaction_id", "")
+ .put(ATTRIBUTES_KEY_DOCUMENT_COUNT, 1)
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, false)
+ .put(ATTRIBUTES_KEY_READ_CONSISTENCY, "READ_CONSISTENCY_UNSPECIFIED")
+ .put(ATTRIBUTES_KEY_MORE_RESULTS, "NO_MORE_RESULTS")
+ .put(ATTRIBUTES_KEY_TRANSACTION_ID, "")
.build()));
}
@@ -677,11 +677,11 @@ public void newTransactionReadWriteTraceTest() throws Exception {
span,
SPAN_NAME_TRANSACTION_LOOKUP + " complete.",
Attributes.builder()
- .put("Deferred", 0)
- .put("Missing", 1)
- .put("Received", 0)
- .put("transactional", true)
- .put("transaction_id", transaction.getTransactionId().toStringUtf8())
+ .put(ATTRIBUTES_KEY_DEFERRED, 0)
+ .put(ATTRIBUTES_KEY_MISSING, 1)
+ .put(ATTRIBUTES_KEY_RECEIVED, 0)
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, true)
+ .put(ATTRIBUTES_KEY_TRANSACTION_ID, transaction.getTransactionId().toStringUtf8())
.build()));
assertSpanHierarchy(SPAN_NAME_TRANSACTION_COMMIT);
@@ -691,9 +691,9 @@ public void newTransactionReadWriteTraceTest() throws Exception {
span,
SPAN_NAME_TRANSACTION_COMMIT + " complete.",
Attributes.builder()
- .put("doc_count", 1)
- .put("transactional", true)
- .put("transaction_id", transaction.getTransactionId().toStringUtf8())
+ .put(ATTRIBUTES_KEY_DOCUMENT_COUNT, 1)
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, true)
+ .put(ATTRIBUTES_KEY_TRANSACTION_ID, transaction.getTransactionId().toStringUtf8())
.build()));
}
@@ -735,11 +735,11 @@ public void newTransactionQueryTest() throws Exception {
span,
SPAN_NAME_TRANSACTION_RUN_QUERY + " complete.",
Attributes.builder()
- .put("doc_count", 1)
- .put("transactional", true)
- .put("read_consistency", "READ_CONSISTENCY_UNSPECIFIED")
- .put("more_results", "NO_MORE_RESULTS")
- .put("transaction_id", transaction.getTransactionId().toStringUtf8())
+ .put(ATTRIBUTES_KEY_DOCUMENT_COUNT, 1)
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, true)
+ .put(ATTRIBUTES_KEY_READ_CONSISTENCY, "READ_CONSISTENCY_UNSPECIFIED")
+ .put(ATTRIBUTES_KEY_MORE_RESULTS, "NO_MORE_RESULTS")
+ .put(ATTRIBUTES_KEY_TRANSACTION_ID, transaction.getTransactionId().toStringUtf8())
.build()));
}
@@ -789,11 +789,11 @@ public void newTransactionRollbackTest() throws Exception {
span,
SPAN_NAME_TRANSACTION_LOOKUP + " complete.",
Attributes.builder()
- .put("Deferred", 0)
- .put("Missing", 0)
- .put("Received", 1)
- .put("transactional", true)
- .put("transaction_id", transaction.getTransactionId().toStringUtf8())
+ .put(ATTRIBUTES_KEY_DEFERRED, 0)
+ .put(ATTRIBUTES_KEY_MISSING, 0)
+ .put(ATTRIBUTES_KEY_RECEIVED, 1)
+ .put(ATTRIBUTES_KEY_TRANSACTIONAL, true)
+ .put(ATTRIBUTES_KEY_TRANSACTION_ID, transaction.getTransactionId().toStringUtf8())
.build()));
assertSpanHierarchy(SPAN_NAME_ROLLBACK);
@@ -803,7 +803,7 @@ public void newTransactionRollbackTest() throws Exception {
span,
SPAN_NAME_ROLLBACK,
Attributes.builder()
- .put("transaction_id", transaction.getTransactionId().toStringUtf8())
+ .put(ATTRIBUTES_KEY_TRANSACTION_ID, transaction.getTransactionId().toStringUtf8())
.build()));
}
From 7b0b45c70d13fadc2bf1f0831dd54a7f4af7212c Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Mon, 16 Sep 2024 15:34:47 -0700
Subject: [PATCH 35/38] fix: opentelemetry.version to fix RequireUpperBoundDeps
check
https://github.com/googleapis/java-datastore/actions/runs/10892403348/job/30225154043?pr=1576
---
google-cloud-datastore/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/google-cloud-datastore/pom.xml b/google-cloud-datastore/pom.xml
index a462d394c..5137728ea 100644
--- a/google-cloud-datastore/pom.xml
+++ b/google-cloud-datastore/pom.xml
@@ -16,7 +16,7 @@
google-cloud-datastore
- 1.42.1
+ 1.42.0
From e4b4af06b14e45159e282461a980ac5f281e63ab Mon Sep 17 00:00:00 2001
From: Jimit Shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Thu, 19 Sep 2024 10:14:02 -0700
Subject: [PATCH 36/38] fix: Create Span hierarchy using parent Span (#1580)
* fix: Replace use of TraceUtil.SpanContext w/ TraceUtil.Context
* fix: Fixing how span hierarchy is created across threads - using Span instead of Context
* fix: cleaning up startSpan(spanName, parentContext) variant
* fix: add TracedReadWriteTransactionCallable to bifurcate tracing enabled/disabled paths for the Transaction callback.
- This change implements the idiomatic way to express nested spans as described in https://opentelemetry.io/docs/languages/java/instrumentation/#create-nested-spans
* fix: cleanup
* fix: cleanup
* fix: cleanup
---
.../google/cloud/datastore/DatastoreImpl.java | 146 +++++++++++-------
.../telemetry/DisabledTraceUtil.java | 18 +--
.../datastore/telemetry/EnabledTraceUtil.java | 45 ++----
.../cloud/datastore/telemetry/TraceUtil.java | 16 +-
.../google/cloud/datastore/DatastoreTest.java | 2 +
.../telemetry/DisabledTraceUtilTest.java | 2 +-
.../telemetry/EnabledTraceUtilTest.java | 5 +-
7 files changed, 109 insertions(+), 125 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index 11ff58bc9..79b647acf 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -18,9 +18,6 @@
import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_DEFERRED;
import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_DOCUMENT_COUNT;
-import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_EXCEPTION_MESSAGE;
-import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_EXCEPTION_STACKTRACE;
-import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_EXCEPTION_TYPE;
import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_MISSING;
import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_MORE_RESULTS;
import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_READ_CONSISTENCY;
@@ -37,10 +34,10 @@
import com.google.cloud.ServiceOptions;
import com.google.cloud.datastore.execution.AggregationQueryExecutor;
import com.google.cloud.datastore.spi.v1.DatastoreRpc;
+import com.google.cloud.datastore.telemetry.TraceUtil;
import com.google.cloud.datastore.telemetry.TraceUtil.Scope;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
-import com.google.common.base.Throwables;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -53,10 +50,6 @@
import com.google.datastore.v1.RunQueryResponse;
import com.google.datastore.v1.TransactionOptions;
import com.google.protobuf.ByteString;
-import io.opentelemetry.api.common.Attributes;
-import io.opentelemetry.api.trace.SpanBuilder;
-import io.opentelemetry.api.trace.SpanKind;
-import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Context;
import java.util.ArrayList;
import java.util.Arrays;
@@ -115,25 +108,24 @@ public Transaction newTransaction() {
return new TransactionImpl(this);
}
- static class ReadWriteTransactionCallable implements Callable {
-
+ static class TracedReadWriteTransactionCallable implements Callable {
private final Datastore datastore;
private final TransactionCallable callable;
private volatile TransactionOptions options;
private volatile Transaction transaction;
- private final com.google.cloud.datastore.telemetry.TraceUtil.SpanContext parentSpanContext;
+ private final TraceUtil.Span parentSpan;
- ReadWriteTransactionCallable(
+ TracedReadWriteTransactionCallable(
Datastore datastore,
TransactionCallable callable,
TransactionOptions options,
- @Nullable com.google.cloud.datastore.telemetry.TraceUtil.SpanContext parentSpanContext) {
+ @Nullable com.google.cloud.datastore.telemetry.TraceUtil.Span parentSpan) {
this.datastore = datastore;
this.callable = callable;
this.options = options;
this.transaction = null;
- this.parentSpanContext = parentSpanContext;
+ this.parentSpan = parentSpan;
}
Datastore getDatastore() {
@@ -154,57 +146,75 @@ void setPrevTransactionId(ByteString transactionId) {
options = options.toBuilder().setReadWrite(readWrite).build();
}
- private io.opentelemetry.api.trace.Span startSpanWithParentContext(
- String spanName,
- com.google.cloud.datastore.telemetry.TraceUtil.SpanContext parentSpanContext) {
- com.google.cloud.datastore.telemetry.TraceUtil otelTraceUtil =
- datastore.getOptions().getTraceUtil();
- SpanBuilder spanBuilder =
- otelTraceUtil
- .getTracer()
- .spanBuilder(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN)
- .setSpanKind(SpanKind.PRODUCER)
- .setParent(
- Context.current()
- .with(
- io.opentelemetry.api.trace.Span.wrap(
- parentSpanContext.getSpanContext())));
- return otelTraceUtil.addSettingsAttributesToCurrentSpan(spanBuilder).startSpan();
+ @Override
+ public T call() throws DatastoreException {
+ try (io.opentelemetry.context.Scope ignored =
+ Context.current().with(parentSpan.getSpan()).makeCurrent()) {
+ transaction = datastore.newTransaction(options);
+ T value = callable.run(transaction);
+ transaction.commit();
+ return value;
+ } catch (Exception ex) {
+ transaction.rollback();
+ throw DatastoreException.propagateUserException(ex);
+ } finally {
+ if (transaction.isActive()) {
+ transaction.rollback();
+ }
+ if (options != null
+ && options.getModeCase().equals(TransactionOptions.ModeCase.READ_WRITE)) {
+ setPrevTransactionId(transaction.getTransactionId());
+ }
+ }
+ }
+ }
+
+ static class ReadWriteTransactionCallable implements Callable {
+ private final Datastore datastore;
+ private final TransactionCallable callable;
+ private volatile TransactionOptions options;
+ private volatile Transaction transaction;
+
+ ReadWriteTransactionCallable(
+ Datastore datastore, TransactionCallable callable, TransactionOptions options) {
+ this.datastore = datastore;
+ this.callable = callable;
+ this.options = options;
+ this.transaction = null;
+ }
+
+ Datastore getDatastore() {
+ return datastore;
+ }
+
+ TransactionOptions getOptions() {
+ return options;
+ }
+
+ Transaction getTransaction() {
+ return transaction;
+ }
+
+ void setPrevTransactionId(ByteString transactionId) {
+ TransactionOptions.ReadWrite readWrite =
+ TransactionOptions.ReadWrite.newBuilder().setPreviousTransaction(transactionId).build();
+ options = options.toBuilder().setReadWrite(readWrite).build();
}
@Override
public T call() throws DatastoreException {
- // TODO Instead of using OTel Spans directly, TraceUtil.Span should be used here. However,
- // the same code in startSpanInternal doesn't work when EnabledTraceUtil.StartSpan is called
- // probably because of some thread-local caching that is getting lost. This needs more
- // debugging. The code below works and is idiomatic but could be prettier and more consistent
- // with the use of TraceUtil-provided framework.
- io.opentelemetry.api.trace.Span span =
- startSpanWithParentContext(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN,
- parentSpanContext);
- try (io.opentelemetry.context.Scope ignored = span.makeCurrent()) {
+ try {
transaction = datastore.newTransaction(options);
T value = callable.run(transaction);
transaction.commit();
return value;
} catch (Exception ex) {
transaction.rollback();
- span.setStatus(StatusCode.ERROR, ex.getMessage());
- span.recordException(
- ex,
- Attributes.builder()
- .put(ATTRIBUTES_KEY_EXCEPTION_MESSAGE, ex.getMessage())
- .put(ATTRIBUTES_KEY_EXCEPTION_TYPE, ex.getClass().getName())
- .put(ATTRIBUTES_KEY_EXCEPTION_STACKTRACE, Throwables.getStackTraceAsString(ex))
- .build());
- span.end();
throw DatastoreException.propagateUserException(ex);
} finally {
if (transaction.isActive()) {
transaction.rollback();
}
- span.end();
if (options != null
&& options.getModeCase().equals(TransactionOptions.ModeCase.READ_WRITE)) {
setPrevTransactionId(transaction.getTransactionId());
@@ -215,30 +225,51 @@ public T call() throws DatastoreException {
@Override
public T runInTransaction(final TransactionCallable callable) {
- try {
+ TraceUtil.Span span =
+ otelTraceUtil.startSpan(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
+ Callable transactionCallable =
+ (getOptions().getOpenTelemetryOptions().isEnabled()
+ ? new TracedReadWriteTransactionCallable(
+ this, callable, /*transactionOptions=*/ null, span)
+ : new ReadWriteTransactionCallable(this, callable, /*transactionOptions=*/ null));
+ try (Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
- new ReadWriteTransactionCallable(
- this, callable, null, otelTraceUtil.getCurrentSpanContext()),
+ transactionCallable,
retrySettings,
TRANSACTION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
+ } finally {
+ span.end();
}
}
@Override
public T runInTransaction(
final TransactionCallable callable, TransactionOptions transactionOptions) {
- try {
+ TraceUtil.Span span =
+ otelTraceUtil.startSpan(
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
+
+ Callable transactionCallable =
+ (getOptions().getOpenTelemetryOptions().isEnabled()
+ ? new TracedReadWriteTransactionCallable(this, callable, transactionOptions, span)
+ : new ReadWriteTransactionCallable(this, callable, transactionOptions));
+
+ try (Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
- new ReadWriteTransactionCallable(
- this, callable, transactionOptions, otelTraceUtil.getCurrentSpanContext()),
+ transactionCallable,
retrySettings,
TRANSACTION_EXCEPTION_HANDLER,
getOptions().getClock());
} catch (RetryHelperException e) {
+ span.end(e);
throw DatastoreException.translateAndThrow(e);
+ } finally {
+ span.end();
}
}
@@ -747,8 +778,7 @@ com.google.datastore.v1.BeginTransactionResponse beginTransaction(
final com.google.datastore.v1.BeginTransactionRequest requestPb) {
com.google.cloud.datastore.telemetry.TraceUtil.Span span =
otelTraceUtil.startSpan(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_BEGIN_TRANSACTION,
- otelTraceUtil.getCurrentSpanContext());
+ com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_BEGIN_TRANSACTION);
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope scope = span.makeCurrent()) {
return RetryHelper.runWithRetries(
() -> datastoreRpc.beginTransaction(requestPb),
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
index 06941c721..ebb630515 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/DisabledTraceUtil.java
@@ -19,7 +19,7 @@
import com.google.api.core.ApiFunction;
import com.google.api.core.ApiFuture;
import com.google.api.core.InternalApi;
-import com.google.cloud.datastore.telemetry.TraceUtil.SpanContext;
+import com.google.cloud.datastore.telemetry.TraceUtil.Context;
import io.grpc.ManagedChannelBuilder;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder;
@@ -35,14 +35,6 @@
*/
@InternalApi
public class DisabledTraceUtil implements TraceUtil {
-
- static class SpanContext implements TraceUtil.SpanContext {
- @Override
- public io.opentelemetry.api.trace.SpanContext getSpanContext() {
- return null;
- }
- }
-
static class Span implements TraceUtil.Span {
@Override
public void end() {}
@@ -112,7 +104,7 @@ public Span startSpan(String spanName) {
}
@Override
- public TraceUtil.Span startSpan(String spanName, TraceUtil.SpanContext parentSpanContext) {
+ public TraceUtil.Span startSpan(String spanName, TraceUtil.Span parentSpan) {
return new Span();
}
@@ -132,12 +124,6 @@ public TraceUtil.Context getCurrentContext() {
return new Context();
}
- @Nonnull
- @Override
- public TraceUtil.SpanContext getCurrentSpanContext() {
- return new SpanContext();
- }
-
@Override
public Tracer getTracer() {
return TracerProvider.noop().get(LIBRARY_NAME);
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
index 3b962754d..40fc7308e 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/EnabledTraceUtil.java
@@ -22,19 +22,19 @@
import com.google.api.core.ApiFutures;
import com.google.api.core.InternalApi;
import com.google.cloud.datastore.DatastoreOptions;
-import com.google.cloud.datastore.telemetry.TraceUtil.SpanContext;
+import com.google.cloud.datastore.telemetry.TraceUtil.Context;
+import com.google.cloud.datastore.telemetry.TraceUtil.Scope;
+import com.google.cloud.datastore.telemetry.TraceUtil.Span;
import com.google.common.base.Throwables;
import io.grpc.ManagedChannelBuilder;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
-import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.api.trace.Tracer;
-import io.opentelemetry.context.Context;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -73,19 +73,6 @@ public ApiFunction getChannelConfi
return null;
}
- static class SpanContext implements TraceUtil.SpanContext {
- private final io.opentelemetry.api.trace.SpanContext spanContext;
-
- public SpanContext(io.opentelemetry.api.trace.SpanContext spanContext) {
- this.spanContext = spanContext;
- }
-
- @Override
- public io.opentelemetry.api.trace.SpanContext getSpanContext() {
- return this.spanContext;
- }
- }
-
static class Span implements TraceUtil.Span {
private final io.opentelemetry.api.trace.Span span;
private final String spanName;
@@ -95,6 +82,11 @@ public Span(io.opentelemetry.api.trace.Span span, String spanName) {
this.spanName = spanName;
}
+ @Override
+ public io.opentelemetry.api.trace.Span getSpan() {
+ return this.span;
+ }
+
/** Ends this span. */
@Override
public void end() {
@@ -197,10 +189,6 @@ public TraceUtil.Span setAttribute(String key, boolean value) {
return this;
}
- public io.opentelemetry.api.trace.Span getSpan() {
- return this.span;
- }
-
@Override
public Scope makeCurrent() {
try (io.opentelemetry.context.Scope scope = span.makeCurrent()) {
@@ -307,18 +295,13 @@ public Span startSpan(String spanName) {
}
@Override
- public TraceUtil.Span startSpan(String spanName, TraceUtil.SpanContext parentSpanContext) {
+ public TraceUtil.Span startSpan(String spanName, TraceUtil.Span parentSpan) {
SpanBuilder spanBuilder =
tracer
.spanBuilder(spanName)
.setSpanKind(SpanKind.PRODUCER)
- .setParent(
- io.opentelemetry.context.Context.current()
- .with(
- io.opentelemetry.api.trace.Span.wrap(parentSpanContext.getSpanContext())));
- io.opentelemetry.api.trace.Span span =
- addSettingsAttributesToCurrentSpan(spanBuilder).startSpan();
- return new Span(span, spanName);
+ .setParent(io.opentelemetry.context.Context.current().with(parentSpan.getSpan()));
+ return new Span(addSettingsAttributesToCurrentSpan(spanBuilder).startSpan(), spanName);
}
@Nonnull
@@ -333,12 +316,6 @@ public TraceUtil.Context getCurrentContext() {
return new Context(io.opentelemetry.context.Context.current());
}
- @Nonnull
- @Override
- public TraceUtil.SpanContext getCurrentSpanContext() {
- return new SpanContext(io.opentelemetry.api.trace.Span.current().getSpanContext());
- }
-
@Override
public Tracer getTracer() {
return this.tracer;
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index 245b825e1..57b3eab9b 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -21,7 +21,6 @@
import com.google.api.core.InternalExtensionOnly;
import com.google.cloud.datastore.DatastoreOptions;
import io.grpc.ManagedChannelBuilder;
-import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.Tracer;
import java.util.Map;
@@ -95,11 +94,6 @@ static TraceUtil getInstance(@Nonnull DatastoreOptions datastoreOptions) {
@Nullable
ApiFunction getChannelConfigurator();
- /** Represents a trace span's context */
- interface SpanContext {
- io.opentelemetry.api.trace.SpanContext getSpanContext();
- }
-
/** Represents a trace span. */
interface Span {
/** Adds the given event to this span. */
@@ -153,10 +147,10 @@ interface Scope extends AutoCloseable {
Span startSpan(String spanName);
/**
- * Starts a new span with the given name and the span represented by the parentSpanContext as its
- * parents, sets it as the current span and returns it.
+ * Starts a new span with the given name and the span represented by the parentSpan as its parent,
+ * sets it as the current span and returns it.
*/
- Span startSpan(String spanName, SpanContext parentSpanContext);
+ Span startSpan(String spanName, Span parentSpan);
/**
* Adds common SpanAttributes to the current span, useful when hand-creating a new Span without
@@ -172,10 +166,6 @@ interface Scope extends AutoCloseable {
@Nonnull
Context getCurrentContext();
- /** Returns the current SpanContext */
- @Nonnull
- SpanContext getCurrentSpanContext();
-
/** Returns the current OpenTelemetry Tracer when OpenTelemetry SDK is provided. */
Tracer getTracer();
}
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/DatastoreTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/DatastoreTest.java
index cd768f986..d88e1d1ec 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/DatastoreTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/DatastoreTest.java
@@ -176,6 +176,8 @@ public static void beforeClass() throws IOException, InterruptedException {
public void setUp() {
rpcFactoryMock = EasyMock.createStrictMock(DatastoreRpcFactory.class);
rpcMock = EasyMock.createStrictMock(DatastoreRpc.class);
+ DatastoreOpenTelemetryOptions.Builder otelOptionsBuilder =
+ DatastoreOpenTelemetryOptions.newBuilder();
rpcMockOptions =
options
.toBuilder()
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java
index 89c91b3a7..c80ef9353 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/DisabledTraceUtilTest.java
@@ -38,7 +38,7 @@ public void usesDisabledSpan() {
assertThat(traceUtil.getCurrentSpan() instanceof DisabledTraceUtil.Span).isTrue();
assertThat(traceUtil.startSpan("foo") instanceof DisabledTraceUtil.Span).isTrue();
assertThat(
- traceUtil.startSpan("foo", traceUtil.getCurrentSpanContext())
+ traceUtil.startSpan("foo", traceUtil.getCurrentSpan())
instanceof DisabledTraceUtil.Span)
.isTrue();
}
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java
index a3620bbc2..50d7b6820 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/telemetry/EnabledTraceUtilTest.java
@@ -65,7 +65,7 @@ public void usesOpenTelemetryFromOptions() {
@Test
public void usesGlobalOpenTelemetryIfOpenTelemetryInstanceNotProvided() {
- OpenTelemetrySdk globalOpenTelemetrySdk = OpenTelemetrySdk.builder().buildAndRegisterGlobal();
+ OpenTelemetrySdk ignored = OpenTelemetrySdk.builder().buildAndRegisterGlobal();
DatastoreOptions firestoreOptions =
getBaseOptions()
.setOpenTelemetryOptions(
@@ -92,8 +92,7 @@ public void usesEnabledSpan() {
assertThat(traceUtil.getCurrentSpan() instanceof EnabledTraceUtil.Span).isTrue();
assertThat(traceUtil.startSpan("foo") != null).isTrue();
assertThat(
- traceUtil.startSpan("foo", traceUtil.getCurrentSpanContext())
- instanceof EnabledTraceUtil.Span)
+ traceUtil.startSpan("foo", traceUtil.getCurrentSpan()) instanceof EnabledTraceUtil.Span)
.isTrue();
}
From d2e2680f5a1845ab102f92340c11014bcb577ae9 Mon Sep 17 00:00:00 2001
From: jimit-j-shah <57637300+jimit-j-shah@users.noreply.github.com>
Date: Thu, 19 Sep 2024 10:43:53 -0700
Subject: [PATCH 37/38] fix: formatting and import refactoring
---
.../google/cloud/datastore/DatastoreImpl.java | 47 +++++++++----------
.../cloud/datastore/telemetry/TraceUtil.java | 4 --
2 files changed, 21 insertions(+), 30 deletions(-)
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
index 79b647acf..2bf8389fd 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java
@@ -24,6 +24,17 @@
import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_RECEIVED;
import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_TRANSACTIONAL;
import static com.google.cloud.datastore.telemetry.TraceUtil.ATTRIBUTES_KEY_TRANSACTION_ID;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_ALLOCATE_IDS;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_BEGIN_TRANSACTION;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RESERVE_IDS;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_ROLLBACK;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_LOOKUP;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN;
+import static com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN_QUERY;
import com.google.api.core.BetaApi;
import com.google.api.gax.retrying.RetrySettings;
@@ -225,9 +236,7 @@ public T call() throws DatastoreException {
@Override
public T runInTransaction(final TransactionCallable callable) {
- TraceUtil.Span span =
- otelTraceUtil.startSpan(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
+ TraceUtil.Span span = otelTraceUtil.startSpan(SPAN_NAME_TRANSACTION_RUN);
Callable transactionCallable =
(getOptions().getOpenTelemetryOptions().isEnabled()
? new TracedReadWriteTransactionCallable(
@@ -250,9 +259,7 @@ public T runInTransaction(final TransactionCallable callable) {
@Override
public T runInTransaction(
final TransactionCallable callable, TransactionOptions transactionOptions) {
- TraceUtil.Span span =
- otelTraceUtil.startSpan(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN);
+ TraceUtil.Span span = otelTraceUtil.startSpan(SPAN_NAME_TRANSACTION_RUN);
Callable transactionCallable =
(getOptions().getOpenTelemetryOptions().isEnabled()
@@ -329,10 +336,7 @@ com.google.datastore.v1.RunQueryResponse runQuery(
final com.google.datastore.v1.RunQueryRequest requestPb) {
ReadOptions readOptions = requestPb.getReadOptions();
boolean isTransactional = readOptions.hasTransaction() || readOptions.hasNewTransaction();
- String spanName =
- (isTransactional
- ? com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN_QUERY
- : com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RUN_QUERY);
+ String spanName = (isTransactional ? SPAN_NAME_TRANSACTION_RUN_QUERY : SPAN_NAME_RUN_QUERY);
com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(spanName);
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
@@ -405,8 +409,7 @@ public List allocateId(IncompleteKey... keys) {
private com.google.datastore.v1.AllocateIdsResponse allocateIds(
final com.google.datastore.v1.AllocateIdsRequest requestPb) {
com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_ALLOCATE_IDS);
+ otelTraceUtil.startSpan(SPAN_NAME_ALLOCATE_IDS);
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
new Callable() {
@@ -567,10 +570,7 @@ com.google.datastore.v1.LookupResponse lookup(
final com.google.datastore.v1.LookupRequest requestPb) {
ReadOptions readOptions = requestPb.getReadOptions();
boolean isTransactional = readOptions.hasTransaction() || readOptions.hasNewTransaction();
- String spanName =
- (isTransactional
- ? com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_LOOKUP
- : com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_LOOKUP);
+ String spanName = (isTransactional ? SPAN_NAME_TRANSACTION_LOOKUP : SPAN_NAME_LOOKUP);
com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(spanName);
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
@@ -624,8 +624,7 @@ public List reserveIds(Key... keys) {
com.google.datastore.v1.ReserveIdsResponse reserveIds(
final com.google.datastore.v1.ReserveIdsRequest requestPb) {
com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_RESERVE_IDS);
+ otelTraceUtil.startSpan(SPAN_NAME_RESERVE_IDS);
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
return RetryHelper.runWithRetries(
new Callable() {
@@ -737,10 +736,7 @@ com.google.datastore.v1.CommitResponse commit(
final com.google.datastore.v1.CommitRequest requestPb) {
final boolean isTransactional =
requestPb.hasTransaction() || requestPb.hasSingleUseTransaction();
- final String spanName =
- isTransactional
- ? com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT
- : com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_COMMIT;
+ final String spanName = isTransactional ? SPAN_NAME_TRANSACTION_COMMIT : SPAN_NAME_COMMIT;
com.google.cloud.datastore.telemetry.TraceUtil.Span span = otelTraceUtil.startSpan(spanName);
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope ignored = span.makeCurrent()) {
CommitResponse response =
@@ -777,8 +773,7 @@ ByteString requestTransactionId(
com.google.datastore.v1.BeginTransactionResponse beginTransaction(
final com.google.datastore.v1.BeginTransactionRequest requestPb) {
com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_BEGIN_TRANSACTION);
+ otelTraceUtil.startSpan(SPAN_NAME_BEGIN_TRANSACTION);
try (com.google.cloud.datastore.telemetry.TraceUtil.Scope scope = span.makeCurrent()) {
return RetryHelper.runWithRetries(
() -> datastoreRpc.beginTransaction(requestPb),
@@ -804,7 +799,7 @@ void rollbackTransaction(ByteString transaction) {
void rollback(final com.google.datastore.v1.RollbackRequest requestPb) {
com.google.cloud.datastore.telemetry.TraceUtil.Span span =
- otelTraceUtil.startSpan(com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_ROLLBACK);
+ otelTraceUtil.startSpan(SPAN_NAME_ROLLBACK);
try (Scope scope = span.makeCurrent()) {
RetryHelper.runWithRetries(
new Callable() {
@@ -818,7 +813,7 @@ public Void call() throws DatastoreException {
EXCEPTION_HANDLER,
getOptions().getClock());
span.addEvent(
- com.google.cloud.datastore.telemetry.TraceUtil.SPAN_NAME_ROLLBACK,
+ SPAN_NAME_ROLLBACK,
new ImmutableMap.Builder()
.put(ATTRIBUTES_KEY_TRANSACTION_ID, requestPb.getTransaction().toStringUtf8())
.build());
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
index 57b3eab9b..fd616a733 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TraceUtil.java
@@ -47,10 +47,6 @@ public interface TraceUtil {
static final String SPAN_NAME_ROLLBACK = "Transaction.Rollback";
static final String SPAN_NAME_TRANSACTION_RUN_AGGREGATION_QUERY =
"Transaction.RunAggregationQuery";
-
- static final String ATTRIBUTES_KEY_EXCEPTION_MESSAGE = "exception.message";
- static final String ATTRIBUTES_KEY_EXCEPTION_TYPE = "exception.type";
- static final String ATTRIBUTES_KEY_EXCEPTION_STACKTRACE = "exception.stacktrace";
static final String ATTRIBUTES_KEY_DOCUMENT_COUNT = "doc_count";
static final String ATTRIBUTES_KEY_TRANSACTIONAL = "transactional";
static final String ATTRIBUTES_KEY_TRANSACTION_ID = "transaction_id";
From e0d3ba9ee4d3346a3f42dce899becd41d66fd03e Mon Sep 17 00:00:00 2001
From: cloud-java-bot
Date: Thu, 19 Sep 2024 18:37:52 +0000
Subject: [PATCH 38/38] chore: generate libraries at Thu Sep 19 18:35:54 UTC
2024
---
README.md | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 084ec175f..d8b43bd0a 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file:
com.google.cloud
libraries-bom
- 26.40.0
+ 26.45.0
pom
import
@@ -42,7 +42,7 @@ If you are using Maven without the BOM, add this to your dependencies:
com.google.cloud
google-cloud-datastore
- 2.21.2
+ 2.21.3
```
@@ -80,7 +80,7 @@ The client application making API calls must be granted [authorization scopes][a
### Prerequisites
You will need a [Google Cloud Platform Console][developer-console] project with the Cloud Datastore [API enabled][enable-api].
-
+You will need to [enable billing][enable-billing] to use Google Cloud Datastore.
[Follow these instructions][create-project] to get your project set up. You will also need to set up the local development environment by
[installing the Google Cloud Command Line Interface][cloud-cli] and running the following commands in command line:
`gcloud auth login` and `gcloud config set project [YOUR PROJECT ID]`.
@@ -93,11 +93,7 @@ to add `google-cloud-datastore` as a dependency in your code.
## About Cloud Datastore
-[Cloud Datastore][product-docs] is a fully managed, schemaless database for
-storing non-relational data. Cloud Datastore automatically scales with
-your users and supports ACID transactions, high availability of reads and
-writes, strong consistency for reads and ancestor queries, and eventual
-consistency for all other queries.
+[Cloud Datastore][product-docs] is a fully managed, schemaless database for\nstoring non-relational data. Cloud Datastore automatically scales with\nyour users and supports ACID transactions, high availability of reads and\nwrites, strong consistency for reads and ancestor queries, and eventual\nconsistency for all other queries.
See the [Cloud Datastore client library docs][javadocs] to learn how to
use this Cloud Datastore Client Library.
@@ -286,7 +282,7 @@ boolean isHTTP = datastore.getOptions().getTransportOptions() instanceof HTTPTra
There are new gRPC specific features available to use in this update.
##### Channel Pooling
-To customize the number of channels your client uses, you can update the channel provider in the DatastoreOptions.
+To customize the number of channels your client uses, you can update the channel provider in the DatastoreOptions.
See [ChannelPoolSettings](https://cloud.google.com/java/docs/reference/gax/latest/com.google.api.gax.grpc.ChannelPoolSettings) and [Performance Best Practices](https://grpc.io/docs/guides/performance/) for more information on channel pools and best practices for performance.
Example:
@@ -356,7 +352,6 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-datastore/tre
| Sample | Source Code | Try it |
| --------------------------- | --------------------------------- | ------ |
-| Native Image Datastore Sample | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/native-image-sample/src/main/java/com/example/datastore/NativeImageDatastoreSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/native-image-sample/src/main/java/com/example/datastore/NativeImageDatastoreSample.java) |
| Quickstart Sample | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/QuickstartSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/QuickstartSample.java) |
| Avg Aggregation On Kind | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/aggregation/AvgAggregationOnKind.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/aggregation/AvgAggregationOnKind.java) |
| Avg Aggregation With Limit | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/aggregation/AvgAggregationWithLimit.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/aggregation/AvgAggregationWithLimit.java) |
@@ -388,6 +383,10 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-datastore/tre
To get help, follow the instructions in the [shared Troubleshooting document][troubleshooting].
+## Transport
+
+Cloud Datastore uses both gRPC and HTTP/JSON for the transport layer.
+
## Supported Java Versions
Java 8 or above is required for using this client.
@@ -492,7 +491,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
[contributing]: https://github.com/googleapis/java-datastore/blob/main/CONTRIBUTING.md
[code-of-conduct]: https://github.com/googleapis/java-datastore/blob/main/CODE_OF_CONDUCT.md#contributor-code-of-conduct
[license]: https://github.com/googleapis/java-datastore/blob/main/LICENSE
-
+[enable-billing]: https://cloud.google.com/apis/docs/getting-started#enabling_billing
[enable-api]: https://console.cloud.google.com/flows/enableapi?apiid=datastore.googleapis.com
[libraries-bom]: https://github.com/GoogleCloudPlatform/cloud-opensource-java/wiki/The-Google-Cloud-Platform-Libraries-BOM
[shell_img]: https://gstatic.com/cloudssh/images/open-btn.png