Skip to content

Commit d053f2d

Browse files
authored
feat: add the export logic for per-connection error rate metric (#2121)
* Add the metric export logic. * Fix integration test failure by updating set of metrics. * Refactor the creation of MonitoredResource. * Use StackdriverStatsConfiguration to get GCE/GKE monitoring resource. * Use preconditions to check null values. * Remove unnecesary checks.
1 parent 0a7ad66 commit d053f2d

11 files changed

+370
-52
lines changed

google-cloud-bigtable-deps-bom/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@
7777
<type>pom</type>
7878
<scope>import</scope>
7979
</dependency>
80+
<!-- Other opencensus packages' versions are pulled through com.google.cloud:third-party-dependencies, but has to be manually specified for this one. -->
81+
<dependency>
82+
<groupId>io.opencensus</groupId>
83+
<artifactId>opencensus-contrib-resource-util</artifactId>
84+
<version>0.31.1</version>
85+
</dependency>
8086
</dependencies>
8187
</dependencyManagement>
8288

google-cloud-bigtable-stats/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
<groupId>io.opencensus</groupId>
3939
<artifactId>opencensus-exporter-stats-stackdriver</artifactId>
4040
</dependency>
41+
<dependency>
42+
<groupId>io.opencensus</groupId>
43+
<artifactId>opencensus-contrib-resource-util</artifactId>
44+
</dependency>
4145
<dependency>
4246
<groupId>io.opencensus</groupId>
4347
<artifactId>opencensus-impl</artifactId>

google-cloud-bigtable-stats/src/main/java/com/google/cloud/bigtable/stats/BigtableCreateTimeSeriesExporter.java

+5-9
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,22 @@ final class BigtableCreateTimeSeriesExporter extends MetricExporter {
3333
private static final Logger logger =
3434
Logger.getLogger(BigtableCreateTimeSeriesExporter.class.getName());
3535
private final MetricServiceClient metricServiceClient;
36-
private final MonitoredResource monitoredResource;
36+
private final MonitoredResource gceOrGkeMonitoredResource;
3737
private final String clientId;
3838

3939
BigtableCreateTimeSeriesExporter(
40-
MetricServiceClient metricServiceClient, MonitoredResource monitoredResource) {
40+
MetricServiceClient metricServiceClient, MonitoredResource gceOrGkeMonitoredResource) {
4141
this.metricServiceClient = metricServiceClient;
42-
this.monitoredResource = monitoredResource;
4342
this.clientId = BigtableStackdriverExportUtils.getDefaultTaskValue();
43+
this.gceOrGkeMonitoredResource = gceOrGkeMonitoredResource;
4444
}
4545

4646
public void export(Collection<Metric> metrics) {
4747
Map<String, List<com.google.monitoring.v3.TimeSeries>> projectToTimeSeries = new HashMap<>();
4848

4949
for (Metric metric : metrics) {
5050
// only export bigtable metrics
51-
if (!metric.getMetricDescriptor().getName().contains("bigtable")) {
52-
continue;
53-
}
54-
// TODO: temporarily skip exporting per connection metrics.
55-
if (metric.getMetricDescriptor().getName().contains("per_connection_error_count")) {
51+
if (!BigtableStackdriverExportUtils.shouldExportMetric(metric.getMetricDescriptor())) {
5652
continue;
5753
}
5854

@@ -69,7 +65,7 @@ public void export(Collection<Metric> metrics) {
6965
metric.getMetricDescriptor(),
7066
timeSeries,
7167
clientId,
72-
monitoredResource),
68+
gceOrGkeMonitoredResource),
7369
Collectors.toList())));
7470

7571
for (Map.Entry<String, List<com.google.monitoring.v3.TimeSeries>> entry :

google-cloud-bigtable-stats/src/main/java/com/google/cloud/bigtable/stats/BigtableStackdriverExportUtils.java

+79-14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package com.google.cloud.bigtable.stats;
1717

18+
import static com.google.cloud.bigtable.stats.BuiltinViewConstants.PER_CONNECTION_ERROR_COUNT_VIEW;
19+
1820
import com.google.api.Distribution.BucketOptions;
1921
import com.google.api.Distribution.BucketOptions.Explicit;
2022
import com.google.api.Metric;
@@ -52,7 +54,7 @@
5254
import javax.annotation.Nullable;
5355

5456
class BigtableStackdriverExportUtils {
55-
57+
private static final String BIGTABLE_RESOURCE_TYPE = "bigtable_client_raw";
5658
private static final Logger logger =
5759
Logger.getLogger(BigtableStackdriverExportUtils.class.getName());
5860

@@ -90,8 +92,8 @@ class BigtableStackdriverExportUtils {
9092
return builder.build();
9193
};
9294

93-
// promote the following metric labels to monitored resource labels
94-
private static final Set<String> PROMOTED_RESOURCE_LABELS =
95+
// promote the following metric labels to Bigtable monitored resource labels
96+
private static final Set<String> PROMOTED_BIGTABLE_RESOURCE_LABELS =
9597
ImmutableSet.of(
9698
BuiltinMeasureConstants.PROJECT_ID.getName(),
9799
BuiltinMeasureConstants.INSTANCE_ID.getName(),
@@ -102,25 +104,67 @@ class BigtableStackdriverExportUtils {
102104
private static final LabelKey CLIENT_UID_LABEL_KEY =
103105
LabelKey.create(BuiltinMeasureConstants.CLIENT_UID.getName(), "client uid");
104106

107+
static boolean isBigtableTableMetric(MetricDescriptor metricDescriptor) {
108+
return metricDescriptor.getName().contains("bigtable")
109+
&& !metricDescriptor.getName().equals(PER_CONNECTION_ERROR_COUNT_VIEW.getName().asString());
110+
}
111+
112+
static boolean shouldExportMetric(MetricDescriptor metricDescriptor) {
113+
return isBigtableTableMetric(metricDescriptor)
114+
|| (metricDescriptor.getName().equals(PER_CONNECTION_ERROR_COUNT_VIEW.getName().asString())
115+
&& (ConsumerEnvironmentUtils.isEnvGce() || ConsumerEnvironmentUtils.isEnvGke()));
116+
}
117+
105118
static com.google.monitoring.v3.TimeSeries convertTimeSeries(
106119
MetricDescriptor metricDescriptor,
107120
TimeSeries timeSeries,
108121
String clientId,
109-
MonitoredResource monitoredResource) {
110-
String metricName = metricDescriptor.getName();
111-
List<LabelKey> labelKeys = metricDescriptor.getLabelKeys();
122+
MonitoredResource gceOrGkeMonitoredResource) {
112123
Type metricType = metricDescriptor.getType();
113124

114-
MonitoredResource.Builder monitoredResourceBuilder = monitoredResource.toBuilder();
125+
com.google.monitoring.v3.TimeSeries.Builder builder;
126+
if (isBigtableTableMetric(metricDescriptor)) {
127+
builder =
128+
setupBuilderForBigtableResource(
129+
metricDescriptor,
130+
MonitoredResource.newBuilder().setType(BIGTABLE_RESOURCE_TYPE),
131+
timeSeries,
132+
clientId);
133+
} else if (ConsumerEnvironmentUtils.isEnvGce() || ConsumerEnvironmentUtils.isEnvGke()) {
134+
builder =
135+
setupBuilderForGceOrGKEResource(
136+
metricDescriptor, gceOrGkeMonitoredResource, timeSeries, clientId);
137+
} else {
138+
logger.warning(
139+
"Trying to export metric "
140+
+ metricDescriptor.getName()
141+
+ " in a non-GCE/GKE environment.");
142+
return com.google.monitoring.v3.TimeSeries.newBuilder().build();
143+
}
144+
builder.setMetricKind(createMetricKind(metricType));
145+
builder.setValueType(createValueType(metricType));
146+
Timestamp startTimeStamp = timeSeries.getStartTimestamp();
147+
for (Point point : timeSeries.getPoints()) {
148+
builder.addPoints(createPoint(point, startTimeStamp));
149+
}
150+
return builder.build();
151+
}
115152

153+
private static com.google.monitoring.v3.TimeSeries.Builder setupBuilderForBigtableResource(
154+
MetricDescriptor metricDescriptor,
155+
MonitoredResource.Builder monitoredResourceBuilder,
156+
TimeSeries timeSeries,
157+
String clientId) {
158+
List<LabelKey> labelKeys = metricDescriptor.getLabelKeys();
159+
String metricName = metricDescriptor.getName();
116160
List<LabelKey> metricTagKeys = new ArrayList<>();
117161
List<LabelValue> metricTagValues = new ArrayList<>();
118162

119163
List<LabelValue> labelValues = timeSeries.getLabelValues();
120164
for (int i = 0; i < labelValues.size(); i++) {
121165
// If the label is defined in the monitored resource, convert it to
122166
// a monitored resource label. Otherwise, keep it as a metric label.
123-
if (PROMOTED_RESOURCE_LABELS.contains(labelKeys.get(i).getKey())) {
167+
if (PROMOTED_BIGTABLE_RESOURCE_LABELS.contains(labelKeys.get(i).getKey())) {
124168
monitoredResourceBuilder.putLabels(
125169
labelKeys.get(i).getKey(), labelValues.get(i).getValue());
126170
} else {
@@ -135,13 +179,34 @@ static com.google.monitoring.v3.TimeSeries convertTimeSeries(
135179
com.google.monitoring.v3.TimeSeries.newBuilder();
136180
builder.setResource(monitoredResourceBuilder.build());
137181
builder.setMetric(createMetric(metricName, metricTagKeys, metricTagValues));
138-
builder.setMetricKind(createMetricKind(metricType));
139-
builder.setValueType(createValueType(metricType));
140-
Timestamp startTimeStamp = timeSeries.getStartTimestamp();
141-
for (Point point : timeSeries.getPoints()) {
142-
builder.addPoints(createPoint(point, startTimeStamp));
182+
183+
return builder;
184+
}
185+
186+
private static com.google.monitoring.v3.TimeSeries.Builder setupBuilderForGceOrGKEResource(
187+
MetricDescriptor metricDescriptor,
188+
MonitoredResource gceOrGkeMonitoredResource,
189+
TimeSeries timeSeries,
190+
String clientId) {
191+
List<LabelKey> labelKeys = metricDescriptor.getLabelKeys();
192+
String metricName = metricDescriptor.getName();
193+
List<LabelKey> metricTagKeys = new ArrayList<>();
194+
List<LabelValue> metricTagValues = new ArrayList<>();
195+
196+
List<LabelValue> labelValues = timeSeries.getLabelValues();
197+
for (int i = 0; i < labelValues.size(); i++) {
198+
metricTagKeys.add(labelKeys.get(i));
199+
metricTagValues.add(labelValues.get(i));
143200
}
144-
return builder.build();
201+
metricTagKeys.add(CLIENT_UID_LABEL_KEY);
202+
metricTagValues.add(LabelValue.create(clientId));
203+
204+
com.google.monitoring.v3.TimeSeries.Builder builder =
205+
com.google.monitoring.v3.TimeSeries.newBuilder();
206+
builder.setResource(gceOrGkeMonitoredResource);
207+
builder.setMetric(createMetric(metricName, metricTagKeys, metricTagValues));
208+
209+
return builder;
145210
}
146211

147212
static String getProjectId(MetricDescriptor metricDescriptor, TimeSeries timeSeries) {

google-cloud-bigtable-stats/src/main/java/com/google/cloud/bigtable/stats/BigtableStackdriverStatsExporter.java

+10-6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import io.opencensus.common.Duration;
2929
import io.opencensus.exporter.metrics.util.IntervalMetricReader;
3030
import io.opencensus.exporter.metrics.util.MetricReader;
31+
import io.opencensus.exporter.stats.stackdriver.StackdriverStatsConfiguration;
3132
import io.opencensus.metrics.Metrics;
3233
import java.io.IOException;
3334
import javax.annotation.Nullable;
@@ -43,7 +44,6 @@ public class BigtableStackdriverStatsExporter {
4344

4445
// Default export interval is 1 minute
4546
private static final Duration EXPORT_INTERVAL = Duration.create(60, 0);
46-
private static final String RESOURCE_TYPE = "bigtable_client_raw";
4747

4848
private static final String MONITORING_ENDPOINT =
4949
MoreObjects.firstNonNull(
@@ -55,13 +55,13 @@ public class BigtableStackdriverStatsExporter {
5555
private BigtableStackdriverStatsExporter(
5656
MetricServiceClient metricServiceClient,
5757
Duration exportInterval,
58-
MonitoredResource monitoredResource) {
58+
MonitoredResource gceOrGkeMonitoredResource) {
5959
IntervalMetricReader.Options.Builder intervalMetricReaderOptionsBuilder =
6060
IntervalMetricReader.Options.builder();
6161
intervalMetricReaderOptionsBuilder.setExportInterval(exportInterval);
6262
this.intervalMetricReader =
6363
IntervalMetricReader.create(
64-
new BigtableCreateTimeSeriesExporter(metricServiceClient, monitoredResource),
64+
new BigtableCreateTimeSeriesExporter(metricServiceClient, gceOrGkeMonitoredResource),
6565
MetricReader.create(
6666
MetricReader.Options.builder()
6767
.setMetricProducerManager(
@@ -76,9 +76,13 @@ public static void register(Credentials credentials) throws IOException {
7676
instance == null, "Bigtable Stackdriver stats exporter is already created");
7777
// Default timeout for creating a client is 1 minute
7878
MetricServiceClient client = createMetricServiceClient(credentials, Duration.create(60L, 0));
79-
MonitoredResource resourceType =
80-
MonitoredResource.newBuilder().setType(RESOURCE_TYPE).build();
81-
instance = new BigtableStackdriverStatsExporter(client, EXPORT_INTERVAL, resourceType);
79+
MonitoredResource gceOrGkeMonitoredResource = null;
80+
if (ConsumerEnvironmentUtils.isEnvGce() || ConsumerEnvironmentUtils.isEnvGke()) {
81+
gceOrGkeMonitoredResource =
82+
StackdriverStatsConfiguration.builder().build().getMonitoredResource();
83+
}
84+
instance =
85+
new BigtableStackdriverStatsExporter(client, EXPORT_INTERVAL, gceOrGkeMonitoredResource);
8286
}
8387
}
8488

google-cloud-bigtable-stats/src/main/java/com/google/cloud/bigtable/stats/BuiltinViewConstants.java

+19-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,25 @@
1515
*/
1616
package com.google.cloud.bigtable.stats;
1717

18-
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.*;
18+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.APPLICATION_LATENCIES;
19+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.APP_PROFILE;
20+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.ATTEMPT_LATENCIES;
21+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.CLIENT_NAME;
22+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.CLUSTER;
23+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.CONNECTIVITY_ERROR_COUNT;
24+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.FIRST_RESPONSE_LATENCIES;
25+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.INSTANCE_ID;
26+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.METHOD;
27+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.OPERATION_LATENCIES;
28+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.PER_CONNECTION_ERROR_COUNT;
29+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.PROJECT_ID;
30+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.RETRY_COUNT;
31+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.SERVER_LATENCIES;
32+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.STATUS;
33+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.STREAMING;
34+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.TABLE;
35+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.THROTTLING_LATENCIES;
36+
import static com.google.cloud.bigtable.stats.BuiltinMeasureConstants.ZONE;
1937
import static io.opencensus.stats.Aggregation.Distribution;
2038
import static io.opencensus.stats.Aggregation.Sum;
2139

google-cloud-bigtable-stats/src/main/java/com/google/cloud/bigtable/stats/BuiltinViews.java

+10
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,28 @@ public class BuiltinViews {
3737
BuiltinViewConstants.CONNECTIVITY_ERROR_COUNT_VIEW,
3838
BuiltinViewConstants.APPLICATION_LATENCIES_VIEW,
3939
BuiltinViewConstants.THROTTLING_LATENCIES_VIEW);
40+
// We store views that don't use the Bigtable schema and need different tags in a separate set to
41+
// simplify testing.
42+
static final ImmutableSet<View> NON_BIGTABLE_BUILTIN_VIEWS =
43+
ImmutableSet.of(BuiltinViewConstants.PER_CONNECTION_ERROR_COUNT_VIEW);
4044

4145
@VisibleForTesting
4246
void registerPrivateViews(ViewManager viewManager) {
4347
for (View view : BIGTABLE_BUILTIN_VIEWS) {
4448
viewManager.registerView(view);
4549
}
50+
for (View view : NON_BIGTABLE_BUILTIN_VIEWS) {
51+
viewManager.registerView(view);
52+
}
4653
}
4754

4855
public static void registerBigtableBuiltinViews() {
4956
ViewManager viewManager = Stats.getViewManager();
5057
for (View view : BIGTABLE_BUILTIN_VIEWS) {
5158
viewManager.registerView(view);
5259
}
60+
for (View view : NON_BIGTABLE_BUILTIN_VIEWS) {
61+
viewManager.registerView(view);
62+
}
5363
}
5464
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
* https://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+
package com.google.cloud.bigtable.stats;
17+
18+
import com.google.common.annotations.VisibleForTesting;
19+
import io.opencensus.contrib.resource.util.CloudResource;
20+
import io.opencensus.contrib.resource.util.ContainerResource;
21+
import io.opencensus.contrib.resource.util.HostResource;
22+
import io.opencensus.contrib.resource.util.ResourceUtils;
23+
import io.opencensus.resource.Resource;
24+
import java.util.Objects;
25+
26+
/** A class for extracting details about consumer environments (GCE and GKE) for metrics. */
27+
class ConsumerEnvironmentUtils {
28+
29+
private static ResourceUtilsWrapper resourceUtilsWrapper = new ResourceUtilsWrapper();
30+
31+
@VisibleForTesting
32+
public static void setResourceUtilsWrapper(ResourceUtilsWrapper newResourceUtilsWrapper) {
33+
resourceUtilsWrapper = newResourceUtilsWrapper;
34+
}
35+
36+
public static boolean isEnvGce() {
37+
Resource resource = resourceUtilsWrapper.detectResource();
38+
return Objects.equals(resource.getType(), HostResource.TYPE)
39+
&& Objects.equals(
40+
resource.getLabels().get(CloudResource.PROVIDER_KEY), CloudResource.PROVIDER_GCP);
41+
}
42+
43+
public static boolean isEnvGke() {
44+
Resource resource = resourceUtilsWrapper.detectResource();
45+
return Objects.equals(resource.getType(), ContainerResource.TYPE)
46+
&& Objects.equals(
47+
resource.getLabels().get(CloudResource.PROVIDER_KEY), CloudResource.PROVIDER_GCP);
48+
}
49+
50+
// We wrap the static ResourceUtils.detectResource() method in a non-static method for mocking.
51+
@VisibleForTesting
52+
public static class ResourceUtilsWrapper {
53+
public Resource detectResource() {
54+
return ResourceUtils.detectResource();
55+
}
56+
}
57+
}

google-cloud-bigtable-stats/src/main/java/com/google/cloud/bigtable/stats/StatsWrapper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public static List<String> getOperationLatencyViewTagValueStrings() {
6161
// the packaging step. Opencensus classes will be relocated when they are packaged but the
6262
// integration test files will not be. So the integration tests can't reference any transitive
6363
// dependencies that have been relocated.
64-
static Map<String, List<String>> getViewToTagMap() {
64+
static Map<String, List<String>> getBigtableViewToTagMap() {
6565
Map<String, List<String>> map = new HashMap<>();
6666
for (View view : BuiltinViews.BIGTABLE_BUILTIN_VIEWS) {
6767
List<TagKey> tagKeys = view.getColumns();

0 commit comments

Comments
 (0)