Skip to content

Commit 45cdcfc

Browse files
feat: add tracing for batchUpdate, executeUpdate, and connections (#3097)
* feat: add OpenTelemetry tracing to Connection API * chore: add more traces + run formatter * test: add tracing tests * chore: make db.statement optional * feat: add tags to traces * fix: declare test dependency * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * chore: create one option for extended tracing Create one combined option for extended tracing, and disable this option by default for both the Connection API and the standard client. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * chore: add ignored diff for clirr * chore: address review comments * chore: add documentation for env var * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * 🦉 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 <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent e4ee19d commit 45cdcfc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1801
-653
lines changed

.readme-partials.yaml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,27 @@ custom_content: |
144144
.build()
145145
146146
SpannerOptions options = SpannerOptions.newBuilder()
147-
// Inject OpenTelemetry object via Spanner Options or register OpenTelmetry object as Global
147+
// Inject OpenTelemetry object via Spanner Options or register OpenTelemetry object as Global
148148
.setOpenTelemetry(openTelemetry)
149149
.build();
150150
151151
Spanner spanner = options.getService();
152152
```
153+
154+
#### OpenTelemetry SQL Statement Tracing
155+
The OpenTelemetry traces that are generated by the Java client include any request and transaction
156+
tags that have been set. The traces can also include the SQL statements that are executed. Enable
157+
this with the `enableExtendedTracing` option:
158+
159+
```
160+
SpannerOptions options = SpannerOptions.newBuilder()
161+
.setOpenTelemetry(openTelemetry)
162+
.setEnableExtendedTracing(true)
163+
.build();
164+
```
165+
166+
This option can also be enabled by setting the environment variable
167+
`SPANNER_ENABLE_EXTENDED_TRACING=true`.
153168
154169
### Instrument with OpenCensus
155170

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ If you are using Maven without the BOM, add this to your dependencies:
5050
If you are using Gradle 5.x or later, add this to your dependencies:
5151

5252
```Groovy
53-
implementation platform('com.google.cloud:libraries-bom:26.38.0')
53+
implementation platform('com.google.cloud:libraries-bom:26.39.0')
5454
5555
implementation 'com.google.cloud:google-cloud-spanner'
5656
```
@@ -250,13 +250,28 @@ OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
250250
.build()
251251

252252
SpannerOptions options = SpannerOptions.newBuilder()
253-
// Inject OpenTelemetry object via Spanner Options or register OpenTelmetry object as Global
253+
// Inject OpenTelemetry object via Spanner Options or register OpenTelemetry object as Global
254254
.setOpenTelemetry(openTelemetry)
255255
.build();
256256

257257
Spanner spanner = options.getService();
258258
```
259259

260+
#### OpenTelemetry SQL Statement Tracing
261+
The OpenTelemetry traces that are generated by the Java client include any request and transaction
262+
tags that have been set. The traces can also include the SQL statements that are executed. Enable
263+
this with the `enableExtendedTracing` option:
264+
265+
```
266+
SpannerOptions options = SpannerOptions.newBuilder()
267+
.setOpenTelemetry(openTelemetry)
268+
.setEnableExtendedTracing(true)
269+
.build();
270+
```
271+
272+
This option can also be enabled by setting the environment variable
273+
`SPANNER_ENABLE_EXTENDED_TRACING=true`.
274+
260275
### Instrument with OpenCensus
261276

262277
> Note: OpenCensus project is deprecated. See [Sunsetting OpenCensus](https://opentelemetry.io/blog/2023/sunsetting-opencensus/).

google-cloud-spanner/clirr-ignored-differences.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,5 +668,12 @@
668668
<className>com/google/cloud/spanner/connection/Connection</className>
669669
<method>com.google.cloud.spanner.connection.DdlInTransactionMode getDdlInTransactionMode()</method>
670670
</difference>
671+
672+
<!-- Added extended tracing option -->
673+
<difference>
674+
<differenceType>7012</differenceType>
675+
<className>com/google/cloud/spanner/SpannerOptions$SpannerEnvironment</className>
676+
<method>boolean isEnableExtendedTracing()</method>
677+
</difference>
671678

672679
</differences>

google-cloud-spanner/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,12 @@
417417
<version>${opentelemetry.version}</version>
418418
<scope>test</scope>
419419
</dependency>
420+
<dependency>
421+
<groupId>io.opentelemetry</groupId>
422+
<artifactId>opentelemetry-sdk-common</artifactId>
423+
<version>${opentelemetry.version}</version>
424+
<scope>test</scope>
425+
</dependency>
420426
<dependency>
421427
<groupId>io.opentelemetry</groupId>
422428
<artifactId>opentelemetry-sdk-metrics</artifactId>

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,7 @@ ResultSet executeQueryInternalWithOptions(
735735
SpannerImpl.QUERY,
736736
span,
737737
tracer,
738+
tracer.createStatementAttributes(statement, options),
738739
rpc.getExecuteQueryRetrySettings(),
739740
rpc.getExecuteQueryRetryableCodes()) {
740741
@Override

google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public Timestamp write(final Iterable<Mutation> mutations) throws SpannerExcepti
9292
public CommitResponse writeWithOptions(
9393
final Iterable<Mutation> mutations, final TransactionOption... options)
9494
throws SpannerException {
95-
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION);
95+
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION, options);
9696
try (IScope s = tracer.withSpan(span)) {
9797
return runWithSessionRetry(session -> session.writeWithOptions(mutations, options));
9898
} catch (RuntimeException e) {
@@ -112,7 +112,7 @@ public Timestamp writeAtLeastOnce(final Iterable<Mutation> mutations) throws Spa
112112
public CommitResponse writeAtLeastOnceWithOptions(
113113
final Iterable<Mutation> mutations, final TransactionOption... options)
114114
throws SpannerException {
115-
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION);
115+
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION, options);
116116
try (IScope s = tracer.withSpan(span)) {
117117
return runWithSessionRetry(
118118
session -> session.writeAtLeastOnceWithOptions(mutations, options));
@@ -128,7 +128,7 @@ public CommitResponse writeAtLeastOnceWithOptions(
128128
public ServerStream<BatchWriteResponse> batchWriteAtLeastOnce(
129129
final Iterable<MutationGroup> mutationGroups, final TransactionOption... options)
130130
throws SpannerException {
131-
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION);
131+
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION, options);
132132
try (IScope s = tracer.withSpan(span)) {
133133
return runWithSessionRetry(session -> session.batchWriteAtLeastOnce(mutationGroups, options));
134134
} catch (RuntimeException e) {
@@ -213,7 +213,7 @@ public ReadOnlyTransaction readOnlyTransaction(TimestampBound bound) {
213213

214214
@Override
215215
public TransactionRunner readWriteTransaction(TransactionOption... options) {
216-
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION);
216+
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION, options);
217217
try (IScope s = tracer.withSpan(span)) {
218218
return getSession().readWriteTransaction(options);
219219
} catch (RuntimeException e) {
@@ -225,7 +225,7 @@ public TransactionRunner readWriteTransaction(TransactionOption... options) {
225225

226226
@Override
227227
public TransactionManager transactionManager(TransactionOption... options) {
228-
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION);
228+
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION, options);
229229
try (IScope s = tracer.withSpan(span)) {
230230
return getSession().transactionManager(options);
231231
} catch (RuntimeException e) {
@@ -237,7 +237,7 @@ public TransactionManager transactionManager(TransactionOption... options) {
237237

238238
@Override
239239
public AsyncRunner runAsync(TransactionOption... options) {
240-
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION);
240+
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION, options);
241241
try (IScope s = tracer.withSpan(span)) {
242242
return getSession().runAsync(options);
243243
} catch (RuntimeException e) {
@@ -249,7 +249,7 @@ public AsyncRunner runAsync(TransactionOption... options) {
249249

250250
@Override
251251
public AsyncTransactionManager transactionManagerAsync(TransactionOption... options) {
252-
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION);
252+
ISpan span = tracer.spanBuilder(READ_WRITE_TRANSACTION, options);
253253
try (IScope s = tracer.withSpan(span)) {
254254
return getSession().transactionManagerAsync(options);
255255
} catch (RuntimeException e) {

google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,10 @@ static final class TagOption extends InternalOption implements ReadQueryUpdateTr
355355
this.tag = tag;
356356
}
357357

358+
String getTag() {
359+
return tag;
360+
}
361+
358362
@Override
359363
void appendToOptions(Options options) {
360364
options.tag = tag;

google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResumableStreamIterator.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.google.protobuf.ByteString;
3535
import com.google.spanner.v1.PartialResultSet;
3636
import io.grpc.Context;
37+
import io.opentelemetry.api.common.Attributes;
3738
import java.io.IOException;
3839
import java.util.LinkedList;
3940
import java.util.Objects;
@@ -81,10 +82,28 @@ protected ResumableStreamIterator(
8182
TraceWrapper tracer,
8283
RetrySettings streamingRetrySettings,
8384
Set<Code> retryableCodes) {
85+
this(
86+
maxBufferSize,
87+
streamName,
88+
parent,
89+
tracer,
90+
Attributes.empty(),
91+
streamingRetrySettings,
92+
retryableCodes);
93+
}
94+
95+
protected ResumableStreamIterator(
96+
int maxBufferSize,
97+
String streamName,
98+
ISpan parent,
99+
TraceWrapper tracer,
100+
Attributes attributes,
101+
RetrySettings streamingRetrySettings,
102+
Set<Code> retryableCodes) {
84103
checkArgument(maxBufferSize >= 0);
85104
this.maxBufferSize = maxBufferSize;
86105
this.tracer = tracer;
87-
this.span = tracer.spanBuilderWithExplicitParent(streamName, parent);
106+
this.span = tracer.spanBuilderWithExplicitParent(streamName, parent, attributes);
88107
this.streamingRetrySettings = Preconditions.checkNotNull(streamingRetrySettings);
89108
this.retryableCodes = Preconditions.checkNotNull(retryableCodes);
90109
this.backOff = newBackOff();

google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,12 @@ class SpannerImpl extends BaseService<SpannerOptions> implements Spanner {
6363
final TraceWrapper tracer =
6464
new TraceWrapper(
6565
Tracing.getTracer(),
66-
this.getOptions()
66+
getOptions()
6767
.getOpenTelemetry()
6868
.getTracer(
6969
MetricRegistryConstants.INSTRUMENTATION_SCOPE,
70-
GaxProperties.getLibraryVersion(this.getOptions().getClass())));
70+
GaxProperties.getLibraryVersion(this.getOptions().getClass())),
71+
getOptions().isEnableExtendedTracing());
7172

7273
static final String CREATE_MULTIPLEXED_SESSION = "CloudSpannerOperation.CreateMultiplexedSession";
7374
static final String CREATE_SESSION = "CloudSpannerOperation.CreateSession";
@@ -80,6 +81,8 @@ class SpannerImpl extends BaseService<SpannerOptions> implements Spanner {
8081
static final String QUERY = "CloudSpannerOperation.ExecuteStreamingQuery";
8182
static final String READ = "CloudSpannerOperation.ExecuteStreamingRead";
8283
static final String BATCH_WRITE = "CloudSpannerOperation.BatchWrite";
84+
static final String UPDATE = "CloudSpannerOperation.ExecuteUpdate";
85+
static final String BATCH_UPDATE = "CloudSpannerOperation.BatchUpdate";
8386

8487
private static final Object CLIENT_ID_LOCK = new Object();
8588

google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ public class SpannerOptions extends ServiceOptions<Spanner, SpannerOptions> {
149149
private final DirectedReadOptions directedReadOptions;
150150
private final boolean useVirtualThreads;
151151
private final OpenTelemetry openTelemetry;
152+
private final boolean enableExtendedTracing;
152153

153154
enum TracingFramework {
154155
OPEN_CENSUS,
@@ -653,6 +654,7 @@ protected SpannerOptions(Builder builder) {
653654
directedReadOptions = builder.directedReadOptions;
654655
useVirtualThreads = builder.useVirtualThreads;
655656
openTelemetry = builder.openTelemetry;
657+
enableExtendedTracing = builder.enableExtendedTracing;
656658
}
657659

658660
/**
@@ -665,15 +667,21 @@ public interface SpannerEnvironment {
665667
* set.
666668
*/
667669
@Nonnull
668-
String getOptimizerVersion();
670+
default String getOptimizerVersion() {
671+
return "";
672+
}
669673

670674
/**
671675
* The optimizer statistics package to use. Must return an empty string to indicate that no
672676
* value has been set.
673677
*/
674678
@Nonnull
675679
default String getOptimizerStatisticsPackage() {
676-
throw new UnsupportedOperationException("Unimplemented");
680+
return "";
681+
}
682+
683+
default boolean isEnableExtendedTracing() {
684+
return false;
677685
}
678686
}
679687

@@ -686,19 +694,27 @@ private static class SpannerEnvironmentImpl implements SpannerEnvironment {
686694
private static final String SPANNER_OPTIMIZER_VERSION_ENV_VAR = "SPANNER_OPTIMIZER_VERSION";
687695
private static final String SPANNER_OPTIMIZER_STATISTICS_PACKAGE_ENV_VAR =
688696
"SPANNER_OPTIMIZER_STATISTICS_PACKAGE";
697+
private static final String SPANNER_ENABLE_EXTENDED_TRACING = "SPANNER_ENABLE_EXTENDED_TRACING";
689698

690699
private SpannerEnvironmentImpl() {}
691700

701+
@Nonnull
692702
@Override
693703
public String getOptimizerVersion() {
694704
return MoreObjects.firstNonNull(System.getenv(SPANNER_OPTIMIZER_VERSION_ENV_VAR), "");
695705
}
696706

707+
@Nonnull
697708
@Override
698709
public String getOptimizerStatisticsPackage() {
699710
return MoreObjects.firstNonNull(
700711
System.getenv(SPANNER_OPTIMIZER_STATISTICS_PACKAGE_ENV_VAR), "");
701712
}
713+
714+
@Override
715+
public boolean isEnableExtendedTracing() {
716+
return Boolean.parseBoolean(System.getenv(SPANNER_ENABLE_EXTENDED_TRACING));
717+
}
702718
}
703719

704720
/** Builder for {@link SpannerOptions} instances. */
@@ -762,6 +778,7 @@ public static class Builder
762778
private DirectedReadOptions directedReadOptions;
763779
private boolean useVirtualThreads = false;
764780
private OpenTelemetry openTelemetry;
781+
private boolean enableExtendedTracing = SpannerOptions.environment.isEnableExtendedTracing();
765782

766783
private static String createCustomClientLibToken(String token) {
767784
return token + " " + ServiceOptions.getGoogApiClientLibName();
@@ -825,6 +842,7 @@ protected Builder() {
825842
this.attemptDirectPath = options.attemptDirectPath;
826843
this.directedReadOptions = options.directedReadOptions;
827844
this.useVirtualThreads = options.useVirtualThreads;
845+
this.enableExtendedTracing = options.enableExtendedTracing;
828846
}
829847

830848
@Override
@@ -1321,6 +1339,19 @@ protected Builder setUseVirtualThreads(boolean useVirtualThreads) {
13211339
return this;
13221340
}
13231341

1342+
/**
1343+
* Sets whether to enable extended OpenTelemetry tracing. Enabling this option will add the
1344+
* following additional attributes to the traces that are generated by the client:
1345+
*
1346+
* <ul>
1347+
* <li>db.statement: Contains the SQL statement that is being executed.
1348+
* </ul>
1349+
*/
1350+
public Builder setEnableExtendedTracing(boolean enableExtendedTracing) {
1351+
this.enableExtendedTracing = enableExtendedTracing;
1352+
return this;
1353+
}
1354+
13241355
@SuppressWarnings("rawtypes")
13251356
@Override
13261357
public SpannerOptions build() {
@@ -1563,6 +1594,18 @@ public boolean isUseVirtualThreads() {
15631594
return useVirtualThreads;
15641595
}
15651596

1597+
/**
1598+
* Returns whether extended OpenTelemetry tracing is enabled. Enabling this option will add the
1599+
* following additional attributes to the traces that are generated by the client:
1600+
*
1601+
* <ul>
1602+
* <li>db.statement: Contains the SQL statement that is being executed.
1603+
* </ul>
1604+
*/
1605+
public boolean isEnableExtendedTracing() {
1606+
return enableExtendedTracing;
1607+
}
1608+
15661609
/** Returns the default query options to use for the specific database. */
15671610
public QueryOptions getDefaultQueryOptions(DatabaseId databaseId) {
15681611
// Use the specific query options for the database if any have been specified. These have

0 commit comments

Comments
 (0)