Skip to content

Commit 3301572

Browse files
committed
feat: Support Exemplar
1 parent d79855a commit 3301572

11 files changed

+189
-91
lines changed

google-cloud-spanner/pom.xml

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -505,10 +505,10 @@
505505
<classpathScope>test</classpathScope>
506506
<executable>java</executable>
507507
<arguments>
508-
<argument>-classpath</argument>
509-
<classpath/>
510-
<argument>org.openjdk.jmh.Main</argument>
511-
<argument>${benchmark.name}</argument>
508+
<argument>-classpath</argument>
509+
<classpath/>
510+
<argument>org.openjdk.jmh.Main</argument>
511+
<argument>${benchmark.name}</argument>
512512
</arguments>
513513
</configuration>
514514
</execution>
@@ -533,44 +533,44 @@
533533
<profile>
534534
<id>slow-tests</id>
535535
<build>
536-
<plugins>
537-
<plugin>
538-
<groupId>org.apache.maven.plugins</groupId>
539-
<artifactId>maven-surefire-plugin</artifactId>
540-
<executions>
541-
<execution>
542-
<id>default-test</id>
543-
<configuration>
544-
<groups>com.google.cloud.spanner.SlowTest</groups>
545-
</configuration>
546-
</execution>
547-
</executions>
548-
</plugin>
549-
<plugin>
550-
<groupId>org.apache.maven.plugins</groupId>
551-
<artifactId>maven-failsafe-plugin</artifactId>
552-
<executions>
553-
<execution>
554-
<id>default</id>
555-
<configuration>
556-
<groups>com.google.cloud.spanner.SlowTest</groups>
557-
<!-- Overrides default configuration to allow slow integration tests more time -->
558-
<forkedProcessTimeoutInSeconds>7200</forkedProcessTimeoutInSeconds>
559-
</configuration>
560-
</execution>
561-
<!-- Overrides default configuration to skip this step -->
562-
<execution>
563-
<id>parallel-integration-test</id>
564-
<goals>
565-
<goal>integration-test</goal>
566-
</goals>
567-
<configuration>
568-
<skipTests>true</skipTests>
569-
</configuration>
570-
</execution>
571-
</executions>
572-
</plugin>
573-
</plugins>
536+
<plugins>
537+
<plugin>
538+
<groupId>org.apache.maven.plugins</groupId>
539+
<artifactId>maven-surefire-plugin</artifactId>
540+
<executions>
541+
<execution>
542+
<id>default-test</id>
543+
<configuration>
544+
<groups>com.google.cloud.spanner.SlowTest</groups>
545+
</configuration>
546+
</execution>
547+
</executions>
548+
</plugin>
549+
<plugin>
550+
<groupId>org.apache.maven.plugins</groupId>
551+
<artifactId>maven-failsafe-plugin</artifactId>
552+
<executions>
553+
<execution>
554+
<id>default</id>
555+
<configuration>
556+
<groups>com.google.cloud.spanner.SlowTest</groups>
557+
<!-- Overrides default configuration to allow slow integration tests more time -->
558+
<forkedProcessTimeoutInSeconds>7200</forkedProcessTimeoutInSeconds>
559+
</configuration>
560+
</execution>
561+
<!-- Overrides default configuration to skip this step -->
562+
<execution>
563+
<id>parallel-integration-test</id>
564+
<goals>
565+
<goal>integration-test</goal>
566+
</goals>
567+
<configuration>
568+
<skipTests>true</skipTests>
569+
</configuration>
570+
</execution>
571+
</executions>
572+
</plugin>
573+
</plugins>
574574
</build>
575575
</profile>
576576
<profile>
@@ -641,4 +641,4 @@
641641
</dependencies>
642642
</profile>
643643
</profiles>
644-
</project>
644+
</project>

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.google.cloud.spanner;
1818

19+
import static com.google.cloud.spanner.XGoogSpannerRequestId.REQUEST_ID;
20+
1921
import com.google.api.core.InternalApi;
2022
import com.google.api.gax.tracing.OpenTelemetryMetricsRecorder;
2123
import com.google.common.collect.ImmutableList;
@@ -26,7 +28,9 @@
2628
import io.opentelemetry.sdk.metrics.InstrumentSelector;
2729
import io.opentelemetry.sdk.metrics.InstrumentType;
2830
import io.opentelemetry.sdk.metrics.View;
31+
import java.util.Arrays;
2932
import java.util.Collection;
33+
import java.util.HashSet;
3034
import java.util.List;
3135
import java.util.Map;
3236
import java.util.Set;
@@ -94,6 +98,8 @@ public class BuiltInMetricsConstant {
9498
AttributeKey.stringKey("directpath_enabled");
9599
public static final AttributeKey<String> DIRECT_PATH_USED_KEY =
96100
AttributeKey.stringKey("directpath_used");
101+
public static final AttributeKey<String> REQUEST_ID_KEY = AttributeKey.stringKey(REQUEST_ID);
102+
public static Set<String> ALLOWED_EXEMPLARS_ATTRIBUTES = new HashSet<>(Arrays.asList(REQUEST_ID));
97103

98104
// IP address prefixes allocated for DirectPath backends.
99105
public static final String DP_IPV6_PREFIX = "2001:4860:8040";
@@ -168,6 +174,7 @@ static Map<InstrumentSelector, View> getAllViews() {
168174
Aggregation.sum(),
169175
InstrumentType.COUNTER,
170176
"1");
177+
defineSpannerView(views);
171178
defineGRPCView(views);
172179
return views.build();
173180
}
@@ -200,6 +207,19 @@ private static void defineView(
200207
viewMap.put(selector, view);
201208
}
202209

210+
private static void defineSpannerView(ImmutableMap.Builder<InstrumentSelector, View> viewMap) {
211+
InstrumentSelector selector =
212+
InstrumentSelector.builder()
213+
.setMeterName(BuiltInMetricsConstant.SPANNER_METER_NAME)
214+
.build();
215+
Set<String> attributesFilter =
216+
BuiltInMetricsConstant.COMMON_ATTRIBUTES.stream()
217+
.map(AttributeKey::getKey)
218+
.collect(Collectors.toSet());
219+
View view = View.builder().setAttributeFilter(attributesFilter).build();
220+
viewMap.put(selector, view);
221+
}
222+
203223
private static void defineGRPCView(ImmutableMap.Builder<InstrumentSelector, View> viewMap) {
204224
for (String metric : BuiltInMetricsConstant.GRPC_METRICS_TO_ENABLE) {
205225
InstrumentSelector selector =

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

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,21 @@ class BuiltInMetricsTracer extends MetricsTracer implements ApiTracer {
3939
private final Map<String, String> attributes = new HashMap<>();
4040
private Float gfeLatency = null;
4141
private Float afeLatency = null;
42+
private TraceWrapper traceWrapper;
4243
private long gfeHeaderMissingCount = 0;
4344
private long afeHeaderMissingCount = 0;
45+
private final ISpan currentSpan;
4446

4547
BuiltInMetricsTracer(
46-
MethodName methodName, BuiltInMetricsRecorder builtInOpenTelemetryMetricsRecorder) {
48+
MethodName methodName,
49+
BuiltInMetricsRecorder builtInOpenTelemetryMetricsRecorder,
50+
TraceWrapper traceWrapper,
51+
ISpan currentSpan) {
4752
super(methodName, builtInOpenTelemetryMetricsRecorder);
4853
this.builtInOpenTelemetryMetricsRecorder = builtInOpenTelemetryMetricsRecorder;
4954
this.attributes.put(METHOD_ATTRIBUTE, methodName.toString());
55+
this.traceWrapper = traceWrapper;
56+
this.currentSpan = currentSpan;
5057
}
5158

5259
/**
@@ -55,10 +62,12 @@ class BuiltInMetricsTracer extends MetricsTracer implements ApiTracer {
5562
*/
5663
@Override
5764
public void attemptSucceeded() {
58-
super.attemptSucceeded();
59-
attributes.put(STATUS_ATTRIBUTE, StatusCode.Code.OK.toString());
60-
builtInOpenTelemetryMetricsRecorder.recordServerTimingHeaderMetrics(
61-
gfeLatency, afeLatency, gfeHeaderMissingCount, afeHeaderMissingCount, attributes);
65+
try (IScope s = this.traceWrapper.withSpan(this.currentSpan)) {
66+
super.attemptSucceeded();
67+
attributes.put(STATUS_ATTRIBUTE, StatusCode.Code.OK.toString());
68+
builtInOpenTelemetryMetricsRecorder.recordServerTimingHeaderMetrics(
69+
gfeLatency, afeLatency, gfeHeaderMissingCount, afeHeaderMissingCount, attributes);
70+
}
6271
}
6372

6473
/**
@@ -67,10 +76,12 @@ public void attemptSucceeded() {
6776
*/
6877
@Override
6978
public void attemptCancelled() {
70-
super.attemptCancelled();
71-
attributes.put(STATUS_ATTRIBUTE, StatusCode.Code.CANCELLED.toString());
72-
builtInOpenTelemetryMetricsRecorder.recordServerTimingHeaderMetrics(
73-
gfeLatency, afeLatency, gfeHeaderMissingCount, afeHeaderMissingCount, attributes);
79+
try (IScope s = this.traceWrapper.withSpan(this.currentSpan)) {
80+
super.attemptCancelled();
81+
attributes.put(STATUS_ATTRIBUTE, StatusCode.Code.CANCELLED.toString());
82+
builtInOpenTelemetryMetricsRecorder.recordServerTimingHeaderMetrics(
83+
gfeLatency, afeLatency, gfeHeaderMissingCount, afeHeaderMissingCount, attributes);
84+
}
7485
}
7586

7687
/**
@@ -83,10 +94,12 @@ public void attemptCancelled() {
8394
*/
8495
@Override
8596
public void attemptFailedDuration(Throwable error, java.time.Duration delay) {
86-
super.attemptFailedDuration(error, delay);
87-
attributes.put(STATUS_ATTRIBUTE, extractStatus(error));
88-
builtInOpenTelemetryMetricsRecorder.recordServerTimingHeaderMetrics(
89-
gfeLatency, afeLatency, gfeHeaderMissingCount, afeHeaderMissingCount, attributes);
97+
try (IScope s = this.traceWrapper.withSpan(this.currentSpan)) {
98+
super.attemptFailedDuration(error, delay);
99+
attributes.put(STATUS_ATTRIBUTE, extractStatus(error));
100+
builtInOpenTelemetryMetricsRecorder.recordServerTimingHeaderMetrics(
101+
gfeLatency, afeLatency, gfeHeaderMissingCount, afeHeaderMissingCount, attributes);
102+
}
90103
}
91104

92105
/**
@@ -98,10 +111,12 @@ public void attemptFailedDuration(Throwable error, java.time.Duration delay) {
98111
*/
99112
@Override
100113
public void attemptFailedRetriesExhausted(Throwable error) {
101-
super.attemptFailedRetriesExhausted(error);
102-
attributes.put(STATUS_ATTRIBUTE, extractStatus(error));
103-
builtInOpenTelemetryMetricsRecorder.recordServerTimingHeaderMetrics(
104-
gfeLatency, afeLatency, gfeHeaderMissingCount, afeHeaderMissingCount, attributes);
114+
try (IScope s = this.traceWrapper.withSpan(this.currentSpan)) {
115+
super.attemptFailedRetriesExhausted(error);
116+
attributes.put(STATUS_ATTRIBUTE, extractStatus(error));
117+
builtInOpenTelemetryMetricsRecorder.recordServerTimingHeaderMetrics(
118+
gfeLatency, afeLatency, gfeHeaderMissingCount, afeHeaderMissingCount, attributes);
119+
}
105120
}
106121

107122
/**
@@ -113,10 +128,12 @@ public void attemptFailedRetriesExhausted(Throwable error) {
113128
*/
114129
@Override
115130
public void attemptPermanentFailure(Throwable error) {
116-
super.attemptPermanentFailure(error);
117-
attributes.put(STATUS_ATTRIBUTE, extractStatus(error));
118-
builtInOpenTelemetryMetricsRecorder.recordServerTimingHeaderMetrics(
119-
gfeLatency, afeLatency, gfeHeaderMissingCount, afeHeaderMissingCount, attributes);
131+
try (IScope s = this.traceWrapper.withSpan(this.currentSpan)) {
132+
super.attemptPermanentFailure(error);
133+
attributes.put(STATUS_ATTRIBUTE, extractStatus(error));
134+
builtInOpenTelemetryMetricsRecorder.recordServerTimingHeaderMetrics(
135+
gfeLatency, afeLatency, gfeHeaderMissingCount, afeHeaderMissingCount, attributes);
136+
}
120137
}
121138

122139
void recordGFELatency(Float gfeLatency) {
@@ -140,7 +157,6 @@ public void addAttributes(Map<String, String> attributes) {
140157
super.addAttributes(attributes);
141158
this.attributes.putAll(attributes);
142159
}
143-
;
144160

145161
@Override
146162
public void addAttributes(String key, String value) {

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,31 @@ class BuiltInMetricsTracerFactory extends MetricsTracerFactory {
3838

3939
protected BuiltInMetricsRecorder builtInMetricsRecorder;
4040
private final Map<String, String> attributes;
41+
private final TraceWrapper traceWrapper;
4142

4243
/**
4344
* Pass in a Map of client level attributes which will be added to every single MetricsTracer
4445
* created from the ApiTracerFactory.
4546
*/
4647
public BuiltInMetricsTracerFactory(
47-
BuiltInMetricsRecorder builtInMetricsRecorder, Map<String, String> attributes) {
48+
BuiltInMetricsRecorder builtInMetricsRecorder,
49+
Map<String, String> attributes,
50+
TraceWrapper traceWrapper) {
4851
super(builtInMetricsRecorder, attributes);
4952
this.builtInMetricsRecorder = builtInMetricsRecorder;
5053
this.attributes = ImmutableMap.copyOf(attributes);
54+
this.traceWrapper = traceWrapper;
5155
}
5256

5357
@Override
5458
public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) {
59+
ISpan currentSpan = this.traceWrapper.getCurrentSpan();
5560
BuiltInMetricsTracer metricsTracer =
5661
new BuiltInMetricsTracer(
5762
MethodName.of(spanName.getClientName(), spanName.getMethodName()),
58-
builtInMetricsRecorder);
63+
builtInMetricsRecorder,
64+
this.traceWrapper,
65+
currentSpan);
5966
metricsTracer.addAttributes(attributes);
6067
return metricsTracer;
6168
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static com.google.api.MetricDescriptor.ValueType.DISTRIBUTION;
2323
import static com.google.api.MetricDescriptor.ValueType.DOUBLE;
2424
import static com.google.api.MetricDescriptor.ValueType.INT64;
25+
import static com.google.cloud.spanner.BuiltInMetricsConstant.ALLOWED_EXEMPLARS_ATTRIBUTES;
2526
import static com.google.cloud.spanner.BuiltInMetricsConstant.GAX_METER_NAME;
2627
import static com.google.cloud.spanner.BuiltInMetricsConstant.GRPC_METER_NAME;
2728
import static com.google.cloud.spanner.BuiltInMetricsConstant.PROJECT_ID_KEY;
@@ -293,7 +294,13 @@ private static String makeSpanName(String projectId, String traceId, String span
293294

294295
private static DroppedLabels mapFilteredAttributes(Attributes attributes) {
295296
DroppedLabels.Builder labels = DroppedLabels.newBuilder();
296-
attributes.forEach((k, v) -> labels.putLabel(cleanAttributeKey(k.getKey()), v.toString()));
297+
attributes.forEach(
298+
(k, v) -> {
299+
String key = cleanAttributeKey(k.getKey());
300+
if (ALLOWED_EXEMPLARS_ATTRIBUTES.contains(key)) {
301+
labels.putLabel(key, v.toString());
302+
}
303+
});
297304
return labels.build();
298305
}
299306

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
7979
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
8080
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext;
81+
import io.opencensus.trace.Tracing;
8182
import io.opentelemetry.api.GlobalOpenTelemetry;
8283
import io.opentelemetry.api.OpenTelemetry;
8384
import io.opentelemetry.api.common.Attributes;
@@ -2073,7 +2074,15 @@ private ApiTracerFactory createMetricsApiTracerFactory() {
20732074
return openTelemetry != null
20742075
? new BuiltInMetricsTracerFactory(
20752076
new BuiltInMetricsRecorder(openTelemetry, BuiltInMetricsConstant.METER_NAME),
2076-
new HashMap<>())
2077+
new HashMap<>(),
2078+
new TraceWrapper(
2079+
Tracing.getTracer(),
2080+
// Using the OpenTelemetry object set in Spanner Options, will be NoOp if not set
2081+
this.getOpenTelemetry()
2082+
.getTracer(
2083+
MetricRegistryConstants.INSTRUMENTATION_SCOPE,
2084+
GaxProperties.getLibraryVersion(getClass())),
2085+
true))
20772086
: null;
20782087
}
20792088

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ public class XGoogSpannerRequestId {
3535
@VisibleForTesting
3636
static final String RAND_PROCESS_ID = XGoogSpannerRequestId.generateRandProcessId();
3737

38+
static String REQUEST_ID = "x-goog-spanner-request-id";
3839
public static final Metadata.Key<String> REQUEST_HEADER_KEY =
39-
Metadata.Key.of("x-goog-spanner-request-id", Metadata.ASCII_STRING_MARSHALLER);
40+
Metadata.Key.of(REQUEST_ID, Metadata.ASCII_STRING_MARSHALLER);
4041

4142
@VisibleForTesting
4243
static final long VERSION = 1; // The version of the specification being implemented.

0 commit comments

Comments
 (0)