Skip to content

Commit 11a362b

Browse files
committed
created builtin metrics tracer factory:
1 parent 3b83448 commit 11a362b

14 files changed

+199
-184
lines changed

Diff for: google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsProvider.java renamed to google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java

+19-76
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@
2828
import com.google.cloud.opentelemetry.detection.AttributeKeys;
2929
import com.google.cloud.opentelemetry.detection.DetectedPlatform;
3030
import com.google.cloud.opentelemetry.detection.GCPPlatformDetector;
31-
import com.google.common.annotations.VisibleForTesting;
32-
import com.google.common.cache.Cache;
33-
import com.google.common.cache.CacheBuilder;
3431
import com.google.common.hash.HashFunction;
3532
import com.google.common.hash.Hashing;
3633
import io.opentelemetry.api.OpenTelemetry;
@@ -49,81 +46,41 @@
4946
import java.util.logging.Logger;
5047
import javax.annotation.Nullable;
5148

52-
final class BuiltInOpenTelemetryMetricsProvider {
49+
final class BuiltInMetricsProvider {
5350

54-
public static BuiltInOpenTelemetryMetricsProvider INSTANCE =
55-
new BuiltInOpenTelemetryMetricsProvider();
51+
static BuiltInMetricsProvider INSTANCE = new BuiltInMetricsProvider();
5652

57-
private static final Logger logger =
58-
Logger.getLogger(BuiltInOpenTelemetryMetricsProvider.class.getName());
59-
60-
private final Cache<String, Map<String, String>> clientAttributesCache =
61-
CacheBuilder.newBuilder().maximumSize(1000).build();
53+
private static final Logger logger = Logger.getLogger(BuiltInMetricsProvider.class.getName());
6254

6355
private static String taskId;
6456

6557
private OpenTelemetry openTelemetry;
6658

67-
private Map<String, String> clientAttributes;
68-
69-
private boolean isInitialized;
70-
71-
private BuiltInOpenTelemetryMetricsRecorder builtInOpenTelemetryMetricsRecorder;
72-
73-
private BuiltInOpenTelemetryMetricsProvider() {};
74-
75-
void initialize(
76-
String projectId,
77-
String client_name,
78-
@Nullable Credentials credentials,
79-
@Nullable String monitoringHost) {
59+
private BuiltInMetricsProvider() {}
8060

61+
OpenTelemetry getOrCreateOpenTelemetry(
62+
String projectId, @Nullable Credentials credentials, @Nullable String monitoringHost) {
8163
try {
82-
if (!isInitialized) {
83-
this.openTelemetry = createOpenTelemetry(projectId, credentials, monitoringHost);
84-
this.clientAttributes = createClientAttributes(projectId, client_name);
85-
this.builtInOpenTelemetryMetricsRecorder =
86-
new BuiltInOpenTelemetryMetricsRecorder(openTelemetry, clientAttributes);
87-
isInitialized = true;
64+
if (this.openTelemetry == null) {
65+
SdkMeterProviderBuilder sdkMeterProviderBuilder = SdkMeterProvider.builder();
66+
BuiltInMetricsView.registerBuiltinMetrics(
67+
SpannerCloudMonitoringExporter.create(projectId, credentials, monitoringHost),
68+
sdkMeterProviderBuilder);
69+
SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder.build();
70+
this.openTelemetry = OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build();
71+
Runtime.getRuntime().addShutdownHook(new Thread(sdkMeterProvider::close));
8872
}
89-
} catch (Exception ex) {
73+
return this.openTelemetry;
74+
} catch (IOException ex) {
9075
logger.log(
9176
Level.WARNING,
92-
"Unable to initialize OpenTelemetry object or attributes for client side metrics, will skip exporting client side metrics",
77+
"Unable to get OpenTelemetry object for client side metrics, will skip exporting client side metrics",
9378
ex);
79+
return null;
9480
}
9581
}
9682

97-
@VisibleForTesting
98-
void initialize(
99-
OpenTelemetry openTelemetry,
100-
String projectId,
101-
String client_name,
102-
@Nullable Credentials credentials,
103-
@Nullable String monitoringHost) {
104-
initialize(projectId, client_name, credentials, monitoringHost);
105-
this.builtInOpenTelemetryMetricsRecorder =
106-
new BuiltInOpenTelemetryMetricsRecorder(openTelemetry, clientAttributes);
107-
}
108-
109-
OpenTelemetry getOpenTelemetry() {
110-
return this.openTelemetry;
111-
}
112-
113-
Map<String, String> getClientAttributes() {
114-
return this.clientAttributes;
115-
}
116-
117-
BuiltInOpenTelemetryMetricsRecorder getBuiltInOpenTelemetryMetricsRecorder() {
118-
return this.builtInOpenTelemetryMetricsRecorder;
119-
}
120-
121-
@VisibleForTesting
122-
void reset() {
123-
isInitialized = false;
124-
}
125-
126-
private Map<String, String> createClientAttributes(String projectId, String client_name) {
83+
Map<String, String> createClientAttributes(String projectId, String client_name) {
12784
Map<String, String> clientAttributes = new HashMap<>();
12885
clientAttributes.put(LOCATION_ID_KEY.getKey(), detectClientLocation());
12986
clientAttributes.put(PROJECT_ID_KEY.getKey(), projectId);
@@ -135,20 +92,6 @@ private Map<String, String> createClientAttributes(String projectId, String clie
13592
return clientAttributes;
13693
}
13794

138-
private OpenTelemetry createOpenTelemetry(
139-
String projectId, @Nullable Credentials credentials, @Nullable String monitoringHost)
140-
throws IOException {
141-
OpenTelemetry openTelemetry;
142-
SdkMeterProviderBuilder sdkMeterProviderBuilder = SdkMeterProvider.builder();
143-
BuiltInOpenTelemetryMetricsView.registerBuiltinMetrics(
144-
SpannerCloudMonitoringExporter.create(projectId, credentials, monitoringHost),
145-
sdkMeterProviderBuilder);
146-
SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder.build();
147-
openTelemetry = OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build();
148-
Runtime.getRuntime().addShutdownHook(new Thread(sdkMeterProvider::close));
149-
return openTelemetry;
150-
}
151-
15295
/**
15396
* Generates a 6-digit zero-padded all lower case hexadecimal representation of hash of the
15497
* accounting group. The hash utilizes the 10 most significant bits of the value returned by

Diff for: google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsRecorder.java renamed to google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsRecorder.java

+7-17
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,21 @@
1717
package com.google.cloud.spanner;
1818

1919
import com.google.api.gax.core.GaxProperties;
20+
import com.google.api.gax.tracing.OpenTelemetryMetricsRecorder;
2021
import com.google.common.annotations.VisibleForTesting;
2122
import com.google.common.base.Preconditions;
2223
import io.opentelemetry.api.OpenTelemetry;
2324
import io.opentelemetry.api.common.Attributes;
2425
import io.opentelemetry.api.common.AttributesBuilder;
2526
import io.opentelemetry.api.metrics.DoubleHistogram;
2627
import io.opentelemetry.api.metrics.Meter;
27-
import java.util.HashMap;
2828
import java.util.Map;
2929

3030
/** OpenTelemetry implementation of recording built in metrics. */
31-
public class BuiltInOpenTelemetryMetricsRecorder {
31+
public class BuiltInMetricsRecorder extends OpenTelemetryMetricsRecorder {
3232

3333
private final DoubleHistogram gfeLatencyRecorder;
34-
private final Map<String, String> attributes = new HashMap<>();
34+
// private final Map<String, String> attributes = new HashMap<>();
3535

3636
/**
3737
* Creates the following instruments for the following metrics:
@@ -42,27 +42,20 @@ public class BuiltInOpenTelemetryMetricsRecorder {
4242
*
4343
* @param openTelemetry OpenTelemetry instance
4444
*/
45-
public BuiltInOpenTelemetryMetricsRecorder(
46-
OpenTelemetry openTelemetry, Map<String, String> clientAttributes) {
47-
if (openTelemetry == null || clientAttributes == null) {
48-
gfeLatencyRecorder = null;
49-
return;
50-
}
51-
45+
public BuiltInMetricsRecorder(OpenTelemetry openTelemetry, String serviceName) {
46+
super(openTelemetry, serviceName);
5247
Meter meter =
5348
openTelemetry
5449
.meterBuilder(BuiltInMetricsConstant.SPANNER_METER_NAME)
5550
.setInstrumentationVersion(GaxProperties.getLibraryVersion(getClass()))
5651
.build();
5752
this.gfeLatencyRecorder =
5853
meter
59-
.histogramBuilder(
60-
BuiltInMetricsConstant.METER_NAME + '/' + BuiltInMetricsConstant.GFE_LATENCIES_NAME)
54+
.histogramBuilder(serviceName + '/' + BuiltInMetricsConstant.GFE_LATENCIES_NAME)
6155
.setDescription(
6256
"Latency between Google's network receiving an RPC and reading back the first byte of the response")
6357
.setUnit("ms")
6458
.build();
65-
this.attributes.putAll(clientAttributes);
6659
}
6760

6861
/**
@@ -73,10 +66,7 @@ public BuiltInOpenTelemetryMetricsRecorder(
7366
* @param attributes Map of the attributes to store
7467
*/
7568
public void recordGFELatency(double gfeLatency, Map<String, String> attributes) {
76-
if (gfeLatencyRecorder != null) {
77-
this.attributes.putAll(attributes);
78-
gfeLatencyRecorder.record(gfeLatency, toOtelAttributes(this.attributes));
79-
}
69+
gfeLatencyRecorder.record(gfeLatency, toOtelAttributes(attributes));
8070
}
8171

8272
@VisibleForTesting
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.spanner;
18+
19+
import com.google.api.gax.tracing.MethodName;
20+
import com.google.api.gax.tracing.MetricsTracer;
21+
import java.util.HashMap;
22+
import java.util.Map;
23+
24+
public class BuiltInMetricsTracer extends MetricsTracer {
25+
26+
private final BuiltInMetricsRecorder builtInOpenTelemetryMetricsRecorder;
27+
// These are RPC specific attributes and pertain to a specific API Trace
28+
private final Map<String, String> attributes = new HashMap<>();
29+
30+
public BuiltInMetricsTracer(
31+
MethodName methodName, BuiltInMetricsRecorder builtInOpenTelemetryMetricsRecorder) {
32+
super(methodName, builtInOpenTelemetryMetricsRecorder);
33+
this.builtInOpenTelemetryMetricsRecorder = builtInOpenTelemetryMetricsRecorder;
34+
this.attributes.put(METHOD_ATTRIBUTE, methodName.toString());
35+
this.attributes.put(LANGUAGE_ATTRIBUTE, DEFAULT_LANGUAGE);
36+
}
37+
38+
public void recordGFELatency(double gfeLatency) {
39+
this.builtInOpenTelemetryMetricsRecorder.recordGFELatency(gfeLatency, this.attributes);
40+
}
41+
42+
@Override
43+
public void addAttributes(Map<String, String> attributes) {
44+
super.addAttributes(attributes);
45+
this.attributes.putAll(attributes);
46+
};
47+
48+
@Override
49+
public void addAttributes(String key, String value) {
50+
super.addAttributes(key, value);
51+
this.attributes.put(key, value);
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.spanner;
18+
19+
import com.google.api.core.BetaApi;
20+
import com.google.api.core.InternalApi;
21+
import com.google.api.gax.tracing.ApiTracer;
22+
import com.google.api.gax.tracing.ApiTracerFactory;
23+
import com.google.api.gax.tracing.MethodName;
24+
import com.google.api.gax.tracing.MetricsRecorder;
25+
import com.google.api.gax.tracing.MetricsTracer;
26+
import com.google.api.gax.tracing.MetricsTracerFactory;
27+
import com.google.api.gax.tracing.SpanName;
28+
import com.google.common.collect.ImmutableMap;
29+
import java.util.Map;
30+
31+
/**
32+
* A {@link ApiTracerFactory} to build instances of {@link MetricsTracer}.
33+
*
34+
* <p>This class wraps the {@link MetricsRecorder} and pass it to {@link MetricsTracer}. It will be
35+
* used to record metrics in {@link MetricsTracer}.
36+
*
37+
* <p>This class is expected to be initialized once during client initialization.
38+
*/
39+
@BetaApi
40+
@InternalApi
41+
public class BuiltInMetricsTracerFactory extends MetricsTracerFactory {
42+
43+
protected BuiltInMetricsRecorder builtInOpenTelemetryMetricsRecorder;
44+
private final Map<String, String> attributes;
45+
46+
/**
47+
* Pass in a Map of client level attributes which will be added to every single MetricsTracer
48+
* created from the ApiTracerFactory.
49+
*/
50+
public BuiltInMetricsTracerFactory(
51+
BuiltInMetricsRecorder builtInOpenTelemetryMetricsRecorder, Map<String, String> attributes) {
52+
super(builtInOpenTelemetryMetricsRecorder, attributes);
53+
this.builtInOpenTelemetryMetricsRecorder = builtInOpenTelemetryMetricsRecorder;
54+
this.attributes = ImmutableMap.copyOf(attributes);
55+
}
56+
57+
@Override
58+
public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) {
59+
BuiltInMetricsTracer metricsTracer =
60+
new BuiltInMetricsTracer(
61+
MethodName.of(spanName.getClientName(), spanName.getMethodName()),
62+
builtInOpenTelemetryMetricsRecorder);
63+
metricsTracer.addAttributes(attributes);
64+
return metricsTracer;
65+
}
66+
}

Diff for: google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsView.java renamed to google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsView.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
import io.opentelemetry.sdk.metrics.export.MetricExporter;
2121
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
2222

23-
class BuiltInOpenTelemetryMetricsView {
23+
class BuiltInMetricsView {
2424

25-
private BuiltInOpenTelemetryMetricsView() {}
25+
private BuiltInMetricsView() {}
2626

2727
/** Register built-in metrics on the {@link SdkMeterProviderBuilder} with credentials. */
2828
static void registerBuiltinMetrics(

Diff for: google-cloud-spanner/src/main/java/com/google/cloud/spanner/CompositeTracer.java

+8
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,12 @@ public void addAttributes(Map<String, String> attributes) {
190190
}
191191
}
192192
}
193+
194+
public void recordGFELatency(double latency) {
195+
for (ApiTracer child : children) {
196+
if (child instanceof BuiltInMetricsTracer) {
197+
((BuiltInMetricsTracer) child).recordGFELatency(latency);
198+
}
199+
}
200+
}
193201
}

Diff for: google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerCloudMonitoringExporterUtils.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ static List<TimeSeries> convertToSpannerTimeSeries(List<MetricData> collection)
7777

7878
for (MetricData metricData : collection) {
7979
// Get metrics data from GAX library and Spanner library
80-
if (!(metricData.getInstrumentationScopeInfo().getName().equals(GAX_METER_NAME) || metricData.getInstrumentationScopeInfo().getName().equals(SPANNER_METER_NAME))) {
80+
if (!(metricData.getInstrumentationScopeInfo().getName().equals(GAX_METER_NAME)
81+
|| metricData.getInstrumentationScopeInfo().getName().equals(SPANNER_METER_NAME))) {
8182
// Filter out metric data for instruments that are not part of the spanner metrics list
8283
continue;
8384
}

0 commit comments

Comments
 (0)