Skip to content

Commit be7d426

Browse files
committed
Merge branch 'e2e-tracing-header' into grpc-telemetry-client-interceptor
2 parents 01aa679 + 1883fed commit be7d426

File tree

6 files changed

+151
-0
lines changed

6 files changed

+151
-0
lines changed

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ public class SpannerOptions extends ServiceOptions<Spanner, SpannerOptions> {
158158
private final OpenTelemetry openTelemetry;
159159
private final boolean enableApiTracing;
160160
private final boolean enableExtendedTracing;
161+
private final boolean enableServerSideTracing;
161162

162163
enum TracingFramework {
163164
OPEN_CENSUS,
@@ -664,6 +665,7 @@ protected SpannerOptions(Builder builder) {
664665
openTelemetry = builder.openTelemetry;
665666
enableApiTracing = builder.enableApiTracing;
666667
enableExtendedTracing = builder.enableExtendedTracing;
668+
enableServerSideTracing = builder.enableServerSideTracing;
667669
}
668670

669671
/**
@@ -799,6 +801,7 @@ public static class Builder
799801
private OpenTelemetry openTelemetry;
800802
private boolean enableApiTracing = SpannerOptions.environment.isEnableApiTracing();
801803
private boolean enableExtendedTracing = SpannerOptions.environment.isEnableExtendedTracing();
804+
private boolean enableServerSideTracing = false;
802805

803806
private static String createCustomClientLibToken(String token) {
804807
return token + " " + ServiceOptions.getGoogApiClientLibName();
@@ -864,6 +867,7 @@ protected Builder() {
864867
this.useVirtualThreads = options.useVirtualThreads;
865868
this.enableApiTracing = options.enableApiTracing;
866869
this.enableExtendedTracing = options.enableExtendedTracing;
870+
this.enableServerSideTracing = options.enableServerSideTracing;
867871
}
868872

869873
@Override
@@ -1391,6 +1395,24 @@ public Builder setEnableExtendedTracing(boolean enableExtendedTracing) {
13911395
return this;
13921396
}
13931397

1398+
/**
1399+
* Enable spanner server side tracing. Enabling this option will create the trace
1400+
* spans at the Spanner layer. By default, server side tracing is disabled.
1401+
*/
1402+
public Builder enableServerSideTracing() {
1403+
this.enableServerSideTracing = true;
1404+
return this;
1405+
}
1406+
1407+
/**
1408+
* Disable spanner server side tracing. If server side is disabled, trace
1409+
* spans won't be created at the Spanner layer.
1410+
*/
1411+
public Builder disableServerSideTracing() {
1412+
this.enableServerSideTracing = false;
1413+
return this;
1414+
}
1415+
13941416
@SuppressWarnings("rawtypes")
13951417
@Override
13961418
public SpannerOptions build() {
@@ -1681,6 +1703,14 @@ public boolean isEnableExtendedTracing() {
16811703
return enableExtendedTracing;
16821704
}
16831705

1706+
/**
1707+
* Returns whether Spanner server side tracing is enabled. If this option is enabled then trace spans
1708+
* will be created at the Spanner layer.
1709+
*/
1710+
public boolean isServerSideTracingEnabled() {
1711+
return enableServerSideTracing;
1712+
}
1713+
16841714
/** Returns the default query options to use for the specific database. */
16851715
public QueryOptions getDefaultQueryOptions(DatabaseId databaseId) {
16861716
// Use the specific query options for the database if any have been specified. These have

google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ public class GapicSpannerRpc implements SpannerRpc {
268268
private static final ConcurrentMap<String, RateLimiter> ADMINISTRATIVE_REQUESTS_RATE_LIMITERS =
269269
new ConcurrentHashMap<>();
270270
private final boolean leaderAwareRoutingEnabled;
271+
private final boolean serverSideTracingEnabled;
271272
private final int numChannels;
272273
private final boolean isGrpcGcpExtensionEnabled;
273274

@@ -321,6 +322,7 @@ public GapicSpannerRpc(final SpannerOptions options) {
321322
this.callCredentialsProvider = options.getCallCredentialsProvider();
322323
this.compressorName = options.getCompressorName();
323324
this.leaderAwareRoutingEnabled = options.isLeaderAwareRoutingEnabled();
325+
this.serverSideTracingEnabled = options.isServerSideTracingEnabled();
324326
this.numChannels = options.getNumChannels();
325327
this.isGrpcGcpExtensionEnabled = options.isGrpcGcpExtensionEnabled();
326328

@@ -1988,6 +1990,9 @@ <ReqT, RespT> GrpcCallContext newCallContext(
19881990
if (routeToLeader && leaderAwareRoutingEnabled) {
19891991
context = context.withExtraHeaders(metadataProvider.newRouteToLeaderHeader());
19901992
}
1993+
if (serverSideTracingEnabled) {
1994+
context = context.withExtraHeaders(metadataProvider.newServerSideTracingHeader());
1995+
}
19911996
if (callCredentialsProvider != null) {
19921997
CallCredentials callCredentials = callCredentialsProvider.getCallCredentials();
19931998
if (callCredentials != null) {

google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerMetadataProvider.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,16 @@ class SpannerMetadataProvider {
3737
private final Map<Metadata.Key<String>, String> headers;
3838
private final String resourceHeaderKey;
3939
private static final String ROUTE_TO_LEADER_HEADER_KEY = "x-goog-spanner-route-to-leader";
40+
private static final String SERVER_SIDE_TRACING_HEADER_KEY = "x-goog-spanner-end-to-end-tracing";
4041
private static final Pattern[] RESOURCE_TOKEN_PATTERNS = {
4142
Pattern.compile("^(?<headerValue>projects/[^/]*/instances/[^/]*/databases/[^/]*)(.*)?"),
4243
Pattern.compile("^(?<headerValue>projects/[^/]*/instances/[^/]*)(.*)?")
4344
};
4445

4546
private static final Map<String, List<String>> ROUTE_TO_LEADER_HEADER_MAP =
4647
ImmutableMap.of(ROUTE_TO_LEADER_HEADER_KEY, Collections.singletonList("true"));
48+
private static final Map<String, List<String>> SERVER_SIDE_TRACING_HEADER_MAP =
49+
ImmutableMap.of(SERVER_SIDE_TRACING_HEADER_KEY, Collections.singletonList("true"));
4750

4851
private SpannerMetadataProvider(Map<String, String> headers, String resourceHeaderKey) {
4952
this.resourceHeaderKey = resourceHeaderKey;
@@ -89,6 +92,10 @@ Map<String, List<String>> newRouteToLeaderHeader() {
8992
return ROUTE_TO_LEADER_HEADER_MAP;
9093
}
9194

95+
Map<String, List<String>> newServerSideTracingHeader() {
96+
return SERVER_SIDE_TRACING_HEADER_MAP;
97+
}
98+
9299
private Map<Metadata.Key<String>, String> constructHeadersAsMetadata(
93100
Map<String, String> headers) {
94101
ImmutableMap.Builder<Metadata.Key<String>, String> headersAsMetadataBuilder =

google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,24 @@ public void testLeaderAwareRoutingEnablement() {
731731
.isLeaderAwareRoutingEnabled());
732732
}
733733

734+
@Test
735+
public void testServerSideTracingEnablement() {
736+
// Test that end to end tracing is disabled by default.
737+
assertFalse(SpannerOptions.newBuilder().setProjectId("p").build().isServerSideTracingEnabled());
738+
assertTrue(
739+
SpannerOptions.newBuilder()
740+
.setProjectId("p")
741+
.enableServerSideTracing()
742+
.build()
743+
.isServerSideTracingEnabled());
744+
assertFalse(
745+
SpannerOptions.newBuilder()
746+
.setProjectId("p")
747+
.disableServerSideTracing()
748+
.build()
749+
.isServerSideTracingEnabled());
750+
}
751+
734752
@Test
735753
public void testSetDirectedReadOptions() {
736754
final DirectedReadOptions directedReadOptions =

google-cloud-spanner/src/test/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpcTest.java

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ public class GapicSpannerRpcTest {
154154
private static String defaultUserAgent;
155155
private static Spanner spanner;
156156
private static boolean isRouteToLeader;
157+
private static boolean isServerSideTracing;
157158
private static boolean isTraceContextPresent;
158159

159160
@Parameter public Dialect dialect;
@@ -213,8 +214,15 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
213214
Key.of(
214215
"x-goog-spanner-route-to-leader",
215216
Metadata.ASCII_STRING_MARSHALLER));
217+
String serverSideTracingHeader =
218+
headers.get(
219+
Key.of(
220+
"x-goog-spanner-end-to-end-tracing",
221+
Metadata.ASCII_STRING_MARSHALLER));
216222
isRouteToLeader =
217223
(routeToLeaderHeader != null && routeToLeaderHeader.equals("true"));
224+
isServerSideTracing =
225+
(serverSideTracingHeader != null && serverSideTracingHeader.equals("true"));
218226
}
219227
return Contexts.interceptCall(Context.current(), call, headers, next);
220228
}
@@ -238,6 +246,7 @@ public void reset() throws InterruptedException {
238246
server.awaitTermination();
239247
}
240248
isRouteToLeader = false;
249+
isServerSideTracing = false;
241250
isTraceContextPresent = false;
242251
}
243252

@@ -479,6 +488,77 @@ public void testNewCallContextWithRouteToLeaderHeaderAndLarDisabled() {
479488
rpc.shutdown();
480489
}
481490

491+
@Test
492+
public void testNewCallContextWithServerSideTracingHeader() {
493+
SpannerOptions options =
494+
SpannerOptions.newBuilder().setProjectId("some-project").enableServerSideTracing().build();
495+
GapicSpannerRpc rpc = new GapicSpannerRpc(options, false);
496+
GrpcCallContext callContext =
497+
rpc.newCallContext(
498+
optionsMap,
499+
"/some/resource",
500+
ExecuteSqlRequest.getDefaultInstance(),
501+
SpannerGrpc.getExecuteSqlMethod());
502+
assertNotNull(callContext);
503+
assertEquals(
504+
ImmutableList.of("true"),
505+
callContext.getExtraHeaders().get("x-goog-spanner-end-to-end-tracing"));
506+
assertEquals(
507+
ImmutableList.of("projects/some-project"),
508+
callContext.getExtraHeaders().get(ApiClientHeaderProvider.getDefaultResourceHeaderKey()));
509+
rpc.shutdown();
510+
}
511+
512+
@Test
513+
public void testNewCallContextWithoutServerSideTracingHeader() {
514+
SpannerOptions options =
515+
SpannerOptions.newBuilder().setProjectId("some-project").disableServerSideTracing().build();
516+
GapicSpannerRpc rpc = new GapicSpannerRpc(options, false);
517+
GrpcCallContext callContext =
518+
rpc.newCallContext(
519+
optionsMap,
520+
"/some/resource",
521+
ExecuteSqlRequest.getDefaultInstance(),
522+
SpannerGrpc.getExecuteSqlMethod());
523+
assertNotNull(callContext);
524+
assertNull(callContext.getExtraHeaders().get("x-goog-spanner-end-to-end-tracing"));
525+
rpc.shutdown();
526+
}
527+
528+
@Test
529+
public void testServerSideTracingHeaderWithEnabledTracing() {
530+
final SpannerOptions options =
531+
createSpannerOptions().toBuilder().enableServerSideTracing().build();
532+
try (Spanner spanner = options.getService()) {
533+
final DatabaseClient databaseClient =
534+
spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
535+
TransactionRunner runner = databaseClient.readWriteTransaction();
536+
runner.run(
537+
transaction -> {
538+
transaction.executeUpdate(UPDATE_FOO_STATEMENT);
539+
return null;
540+
});
541+
}
542+
assertTrue(isServerSideTracing);
543+
}
544+
545+
@Test
546+
public void testServerSideTracingHeaderWithDisabledTracing() {
547+
final SpannerOptions options =
548+
createSpannerOptions().toBuilder().disableServerSideTracing().build();
549+
try (Spanner spanner = options.getService()) {
550+
final DatabaseClient databaseClient =
551+
spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
552+
TransactionRunner runner = databaseClient.readWriteTransaction();
553+
runner.run(
554+
transaction -> {
555+
transaction.executeUpdate(UPDATE_FOO_STATEMENT);
556+
return null;
557+
});
558+
}
559+
assertFalse(isServerSideTracing);
560+
}
561+
482562
@Test
483563
public void testAdminRequestsLimitExceededRetryAlgorithm() {
484564
AdminRequestsLimitExceededRetryAlgorithm<Long> alg =

google-cloud-spanner/src/test/java/com/google/cloud/spanner/spi/v1/SpannerMetadataProviderTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,17 @@ public void testNewRouteToLeaderHeader() {
9494
assertTrue(Maps.difference(extraHeaders, expectedHeaders).areEqual());
9595
}
9696

97+
@Test
98+
public void testNewEndToEndTracingHeader() {
99+
SpannerMetadataProvider metadataProvider =
100+
SpannerMetadataProvider.create(ImmutableMap.of(), "header1");
101+
Map<String, List<String>> extraHeaders = metadataProvider.newServerSideTracingHeader();
102+
Map<String, List<String>> expectedHeaders =
103+
ImmutableMap.<String, List<String>>of(
104+
"x-goog-spanner-end-to-end-tracing", ImmutableList.of("true"));
105+
assertTrue(Maps.difference(extraHeaders, expectedHeaders).areEqual());
106+
}
107+
97108
private String getResourceHeaderValue(
98109
SpannerMetadataProvider headerProvider, String resourceTokenTemplate) {
99110
Metadata metadata = headerProvider.newMetadata(resourceTokenTemplate, "projects/p");

0 commit comments

Comments
 (0)