Skip to content

Commit c4085c5

Browse files
authored
Add prefix option to metrics exporter (#189)
* add prefix option to metrics exporter
1 parent 60cf3d6 commit c4085c5

File tree

6 files changed

+78
-32
lines changed

6 files changed

+78
-32
lines changed

exporters/metrics/src/main/java/com/google/cloud/opentelemetry/metric/AggregateByLabelMetricTimeSeriesBuilder.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,16 @@ public final class AggregateByLabelMetricTimeSeriesBuilder implements MetricTime
4545
private final Map<String, MetricDescriptor> descriptors = new HashMap<>();
4646
private final Map<MetricWithLabels, TimeSeries.Builder> pendingTimeSeries = new HashMap<>();
4747
private final String projectId;
48+
private final String prefix;
4849

49-
public AggregateByLabelMetricTimeSeriesBuilder(String projectId) {
50+
public AggregateByLabelMetricTimeSeriesBuilder(String projectId, String prefix) {
5051
this.projectId = projectId;
52+
this.prefix = prefix;
5153
}
5254

5355
@Override
5456
public void recordPoint(MetricData metric, LongPointData point) {
55-
MetricDescriptor descriptor = mapMetricDescriptor(metric, point);
57+
MetricDescriptor descriptor = mapMetricDescriptor(this.prefix, metric, point);
5658
if (descriptor == null) {
5759
// Unsupported type.
5860
return;
@@ -71,7 +73,7 @@ public void recordPoint(MetricData metric, LongPointData point) {
7173

7274
@Override
7375
public void recordPoint(MetricData metric, DoublePointData point) {
74-
MetricDescriptor descriptor = mapMetricDescriptor(metric, point);
76+
MetricDescriptor descriptor = mapMetricDescriptor(this.prefix, metric, point);
7577
if (descriptor == null) {
7678
// Unsupported type.
7779
return;
@@ -89,7 +91,7 @@ public void recordPoint(MetricData metric, DoublePointData point) {
8991

9092
@Override
9193
public void recordPoint(MetricData metric, HistogramPointData point) {
92-
MetricDescriptor descriptor = mapMetricDescriptor(metric, point);
94+
MetricDescriptor descriptor = mapMetricDescriptor(this.prefix, metric, point);
9395
if (descriptor == null) {
9496
// Unsupported type.
9597
return;

exporters/metrics/src/main/java/com/google/cloud/opentelemetry/metric/GoogleCloudMetricExporter.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,16 @@ public class GoogleCloudMetricExporter
5858

5959
private final CloudMetricClient metricServiceClient;
6060
private final String projectId;
61+
private final String prefix;
6162
private final MetricDescriptorStrategy metricDescriptorStrategy;
6263

6364
GoogleCloudMetricExporter(
64-
String projectId, CloudMetricClient client, MetricDescriptorStrategy descriptorStrategy) {
65+
String projectId,
66+
String prefix,
67+
CloudMetricClient client,
68+
MetricDescriptorStrategy descriptorStrategy) {
6569
this.projectId = projectId;
70+
this.prefix = prefix;
6671
this.metricServiceClient = client;
6772
this.metricDescriptorStrategy = descriptorStrategy;
6873
}
@@ -75,6 +80,7 @@ public static GoogleCloudMetricExporter createWithDefaultConfiguration() throws
7580
public static GoogleCloudMetricExporter createWithConfiguration(MetricConfiguration configuration)
7681
throws IOException {
7782
String projectId = configuration.getProjectId();
83+
String prefix = configuration.getPrefix();
7884
MetricServiceSettings.Builder builder = MetricServiceSettings.newBuilder();
7985
// For testing, we need to hack around our gRPC config.
8086
if (configuration.getInsecureEndpoint()) {
@@ -103,16 +109,19 @@ public static GoogleCloudMetricExporter createWithConfiguration(MetricConfigurat
103109

104110
return new GoogleCloudMetricExporter(
105111
projectId,
112+
prefix,
106113
new CloudMetricClientImpl(MetricServiceClient.create(builder.build())),
107114
configuration.getDescriptorStrategy());
108115
}
109116

110117
@VisibleForTesting
111118
static GoogleCloudMetricExporter createWithClient(
112119
String projectId,
120+
String prefix,
113121
CloudMetricClient metricServiceClient,
114122
MetricDescriptorStrategy descriptorStrategy) {
115-
return new GoogleCloudMetricExporter(projectId, metricServiceClient, descriptorStrategy);
123+
return new GoogleCloudMetricExporter(
124+
projectId, prefix, metricServiceClient, descriptorStrategy);
116125
}
117126

118127
private void exportDescriptor(MetricDescriptor descriptor) {
@@ -135,7 +144,8 @@ public CompletableResultCode export(Collection<MetricData> metrics) {
135144
// 1. Iterate over all points in the set of metrics to export
136145
// 2. Attempt to register MetricDescriptors (using configured strategy)
137146
// 3. Fire the set of time series off.
138-
MetricTimeSeriesBuilder builder = new AggregateByLabelMetricTimeSeriesBuilder(projectId);
147+
MetricTimeSeriesBuilder builder =
148+
new AggregateByLabelMetricTimeSeriesBuilder(projectId, prefix);
139149
for (final MetricData metricData : metrics) {
140150
// Extract all the underlying points.
141151
switch (metricData.getType()) {

exporters/metrics/src/main/java/com/google/cloud/opentelemetry/metric/MetricConfiguration.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
@AutoValue
3737
@Immutable
3838
public abstract class MetricConfiguration {
39+
static final String DEFAULT_PREFIX = "workload.googleapis.com";
3940

4041
private static final String DEFAULT_PROJECT_ID =
4142
Strings.nullToEmpty(ServiceOptions.getDefaultProjectId());
@@ -61,6 +62,16 @@ public abstract class MetricConfiguration {
6162
*/
6263
public abstract String getProjectId();
6364

65+
/**
66+
* Returns the prefix prepended to metric names.
67+
*
68+
* @see <a href="https://cloud.google.com/monitoring/custom-metrics#identifier">Custom Metrics
69+
* Identifiers</a>
70+
* <p>Defaults to workload.googleapis.com.
71+
* @return the prefix to attach to metrics.
72+
*/
73+
public abstract String getPrefix();
74+
6475
/**
6576
* Returns the deadline for exporting to Cloud Monitoring backend.
6677
*
@@ -106,6 +117,7 @@ public abstract class MetricConfiguration {
106117
public static Builder builder() {
107118
return new AutoValue_MetricConfiguration.Builder()
108119
.setProjectId(DEFAULT_PROJECT_ID)
120+
.setPrefix(DEFAULT_PREFIX)
109121
.setDeadline(DEFAULT_DEADLINE)
110122
.setDescriptorStrategy(MetricDescriptorStrategy.SEND_ONCE)
111123
.setInsecureEndpoint(false)
@@ -125,6 +137,9 @@ public abstract static class Builder {
125137
/** Set the GCP project where metrics should be writtten. */
126138
public abstract Builder setProjectId(String projectId);
127139

140+
/** Set the prefix prepended to metric names. */
141+
public abstract Builder setPrefix(String prefix);
142+
128143
/** Set the credentials to use when writing metrics. */
129144
public abstract Builder setCredentials(Credentials newCredentials);
130145

exporters/metrics/src/main/java/com/google/cloud/opentelemetry/metric/MetricTranslator.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import io.opentelemetry.sdk.metrics.data.MetricData;
3838
import io.opentelemetry.sdk.metrics.data.MetricDataType;
3939
import io.opentelemetry.sdk.metrics.data.SumData;
40+
import java.nio.file.Paths;
4041
import java.util.Set;
4142
import java.util.concurrent.TimeUnit;
4243
import java.util.stream.Collectors;
@@ -48,7 +49,6 @@ public final class MetricTranslator {
4849

4950
private static final Logger logger = LoggerFactory.getLogger(MetricTranslator.class);
5051

51-
static final String DESCRIPTOR_TYPE_URL = "workload.googleapis.com/";
5252
static final Set<String> KNOWN_DOMAINS =
5353
ImmutableSet.of("googleapis.com", "kubernetes.io", "istio.io", "knative.dev");
5454
static final long NANO_PER_SECOND = (long) 1e9;
@@ -69,12 +69,12 @@ static String cleanAttributeKey(String key) {
6969
}
7070

7171
static MetricDescriptor mapMetricDescriptor(
72-
MetricData metric, io.opentelemetry.sdk.metrics.data.PointData metricPoint) {
72+
String prefix, MetricData metric, io.opentelemetry.sdk.metrics.data.PointData metricPoint) {
7373
MetricDescriptor.Builder builder =
7474
MetricDescriptor.newBuilder()
7575
.setDisplayName(metric.getName())
7676
.setDescription(metric.getDescription())
77-
.setType(mapMetricType(metric.getName()))
77+
.setType(mapMetricType(metric.getName(), prefix))
7878
.setUnit(metric.getUnit());
7979
metricPoint
8080
.getAttributes()
@@ -136,13 +136,13 @@ private static MetricDescriptor fillSumType(SumData<?> sum, MetricDescriptor.Bui
136136
}
137137
}
138138

139-
private static String mapMetricType(String instrumentName) {
139+
private static String mapMetricType(String instrumentName, String prefix) {
140140
for (String domain : KNOWN_DOMAINS) {
141141
if (instrumentName.contains(domain)) {
142142
return instrumentName;
143143
}
144144
}
145-
return DESCRIPTOR_TYPE_URL + instrumentName;
145+
return Paths.get(prefix, instrumentName).toString();
146146
}
147147

148148
static <T> LabelDescriptor mapAttribute(AttributeKey<T> key, Object value) {

exporters/metrics/src/test/java/com/google/cloud/opentelemetry/metric/GoogleCloudMetricExporterTest.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import static com.google.cloud.opentelemetry.metric.FakeData.aSpanId;
2929
import static com.google.cloud.opentelemetry.metric.FakeData.aTraceId;
3030
import static com.google.cloud.opentelemetry.metric.FakeData.anInstrumentationLibraryInfo;
31-
import static com.google.cloud.opentelemetry.metric.MetricTranslator.DESCRIPTOR_TYPE_URL;
31+
import static com.google.cloud.opentelemetry.metric.MetricConfiguration.DEFAULT_PREFIX;
3232
import static com.google.cloud.opentelemetry.metric.MetricTranslator.METRIC_DESCRIPTOR_TIME_UNIT;
3333
import static com.google.cloud.opentelemetry.metric.MetricTranslator.NANO_PER_SECOND;
3434
import static org.junit.Assert.assertEquals;
@@ -111,7 +111,7 @@ public void testCreateWithConfigurationSucceeds() throws IOException {
111111
public void testExportSendsAllDescriptorsOnce() {
112112
GoogleCloudMetricExporter exporter =
113113
GoogleCloudMetricExporter.createWithClient(
114-
aProjectId, mockClient, MetricDescriptorStrategy.SEND_ONCE);
114+
aProjectId, DEFAULT_PREFIX, mockClient, MetricDescriptorStrategy.SEND_ONCE);
115115
CompletableResultCode result = exporter.export(ImmutableList.of(aMetricData, aHistogram));
116116
assertTrue(result.isSuccess());
117117
CompletableResultCode result2 = exporter.export(ImmutableList.of(aMetricData, aHistogram));
@@ -127,16 +127,16 @@ public void testExportSendsAllDescriptorsOnce() {
127127
metricDescriptorCaptor.getAllValues().stream()
128128
.map(d -> d.getMetricDescriptor().getType())
129129
.collect(Collectors.toSet());
130-
assertTrue(metricDescriptorTypes.contains(DESCRIPTOR_TYPE_URL + aMetricData.getName()));
131-
assertTrue(metricDescriptorTypes.contains(DESCRIPTOR_TYPE_URL + aHistogram.getName()));
130+
assertTrue(metricDescriptorTypes.contains(DEFAULT_PREFIX + "/" + aMetricData.getName()));
131+
assertTrue(metricDescriptorTypes.contains(DEFAULT_PREFIX + "/" + aHistogram.getName()));
132132
}
133133

134134
@Test
135135
public void testExportSucceeds() {
136136
MetricDescriptor expectedDescriptor =
137137
MetricDescriptor.newBuilder()
138138
.setDisplayName(aMetricData.getName())
139-
.setType(DESCRIPTOR_TYPE_URL + aMetricData.getName())
139+
.setType(DEFAULT_PREFIX + "/" + aMetricData.getName())
140140
.addLabels(
141141
LabelDescriptor.newBuilder()
142142
.setKey("label1")
@@ -193,7 +193,7 @@ public void testExportSucceeds() {
193193

194194
GoogleCloudMetricExporter exporter =
195195
GoogleCloudMetricExporter.createWithClient(
196-
aProjectId, mockClient, MetricDescriptorStrategy.ALWAYS_SEND);
196+
aProjectId, DEFAULT_PREFIX, mockClient, MetricDescriptorStrategy.ALWAYS_SEND);
197197

198198
CompletableResultCode result = exporter.export(ImmutableList.of(aMetricData));
199199
verify(mockClient, times(1)).createMetricDescriptor(metricDescriptorCaptor.capture());
@@ -212,7 +212,7 @@ public void testExportWithHistogram_Succeeds() {
212212
MetricDescriptor expectedDescriptor =
213213
MetricDescriptor.newBuilder()
214214
.setDisplayName(aHistogram.getName())
215-
.setType(DESCRIPTOR_TYPE_URL + aHistogram.getName())
215+
.setType(DEFAULT_PREFIX + "/" + aHistogram.getName())
216216
.addLabels(
217217
LabelDescriptor.newBuilder().setKey("test").setValueType(ValueType.STRING).build())
218218
.setMetricKind(MetricKind.CUMULATIVE)
@@ -290,7 +290,7 @@ public void testExportWithHistogram_Succeeds() {
290290
.build();
291291
GoogleCloudMetricExporter exporter =
292292
GoogleCloudMetricExporter.createWithClient(
293-
aProjectId, mockClient, MetricDescriptorStrategy.ALWAYS_SEND);
293+
aProjectId, DEFAULT_PREFIX, mockClient, MetricDescriptorStrategy.ALWAYS_SEND);
294294
CompletableResultCode result = exporter.export(ImmutableList.of(aHistogram));
295295
verify(mockClient, times(1)).createMetricDescriptor(metricDescriptorCaptor.capture());
296296
verify(mockClient, times(1))
@@ -306,7 +306,7 @@ public void testExportWithHistogram_Succeeds() {
306306
public void testExportWithNonSupportedMetricTypeReturnsFailure() {
307307
GoogleCloudMetricExporter exporter =
308308
GoogleCloudMetricExporter.createWithClient(
309-
aProjectId, mockClient, MetricDescriptorStrategy.ALWAYS_SEND);
309+
aProjectId, DEFAULT_PREFIX, mockClient, MetricDescriptorStrategy.ALWAYS_SEND);
310310

311311
MetricData metricData =
312312
ImmutableMetricData.createDoubleSummary(

exporters/metrics/src/test/java/com/google/cloud/opentelemetry/metric/MetricTranslatorTest.java

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import static com.google.cloud.opentelemetry.metric.FakeData.aLongPoint;
2323
import static com.google.cloud.opentelemetry.metric.FakeData.aMetricData;
2424
import static com.google.cloud.opentelemetry.metric.FakeData.anInstrumentationLibraryInfo;
25-
import static com.google.cloud.opentelemetry.metric.MetricTranslator.DESCRIPTOR_TYPE_URL;
25+
import static com.google.cloud.opentelemetry.metric.MetricConfiguration.DEFAULT_PREFIX;
2626
import static com.google.cloud.opentelemetry.metric.MetricTranslator.METRIC_DESCRIPTOR_TIME_UNIT;
2727
import static io.opentelemetry.api.common.AttributeKey.booleanKey;
2828
import static io.opentelemetry.api.common.AttributeKey.longKey;
@@ -54,10 +54,11 @@
5454

5555
@RunWith(JUnit4.class)
5656
public class MetricTranslatorTest {
57+
static final String customPrefix = "custom.googleapis.com";
5758

5859
@Test
5960
public void testMapMetricSucceeds() {
60-
String type = "workload.googleapis.com/" + anInstrumentationLibraryInfo.getName();
61+
String type = DEFAULT_PREFIX + "/" + anInstrumentationLibraryInfo.getName();
6162

6263
Builder expectedMetricBuilder = Metric.newBuilder().setType(type);
6364
aLongPoint
@@ -70,7 +71,7 @@ public void testMapMetricSucceeds() {
7071

7172
@Test
7273
public void testMapMetricWithWierdAttributeNameSucceeds() {
73-
String type = "workload.googleapis.com/" + anInstrumentationLibraryInfo.getName();
74+
String type = DEFAULT_PREFIX + "/" + anInstrumentationLibraryInfo.getName();
7475
Attributes attributes =
7576
io.opentelemetry.api.common.Attributes.of(stringKey("test.bad"), "value");
7677
Metric expectedMetric =
@@ -84,7 +85,7 @@ public void testMapMetricDescriptorSucceeds() {
8485
MetricDescriptor.Builder expectedDescriptor =
8586
MetricDescriptor.newBuilder()
8687
.setDisplayName(aMetricData.getName())
87-
.setType(DESCRIPTOR_TYPE_URL + aMetricData.getName())
88+
.setType(DEFAULT_PREFIX + "/" + aMetricData.getName())
8889
.addLabels(LabelDescriptor.newBuilder().setKey("label1").setValueType(ValueType.STRING))
8990
.addLabels(LabelDescriptor.newBuilder().setKey("label2").setValueType(ValueType.BOOL))
9091
.setUnit(METRIC_DESCRIPTOR_TIME_UNIT)
@@ -93,7 +94,25 @@ public void testMapMetricDescriptorSucceeds() {
9394
.setValueType(MetricDescriptor.ValueType.INT64);
9495

9596
MetricDescriptor actualDescriptor =
96-
MetricTranslator.mapMetricDescriptor(aMetricData, aLongPoint);
97+
MetricTranslator.mapMetricDescriptor(DEFAULT_PREFIX, aMetricData, aLongPoint);
98+
assertEquals(expectedDescriptor.build(), actualDescriptor);
99+
}
100+
101+
@Test
102+
public void testMapMetricDescriptorCustomPrefixSucceeds() {
103+
MetricDescriptor.Builder expectedDescriptor =
104+
MetricDescriptor.newBuilder()
105+
.setDisplayName(aMetricData.getName())
106+
.setType(customPrefix + "/" + aMetricData.getName())
107+
.addLabels(LabelDescriptor.newBuilder().setKey("label1").setValueType(ValueType.STRING))
108+
.addLabels(LabelDescriptor.newBuilder().setKey("label2").setValueType(ValueType.BOOL))
109+
.setUnit(METRIC_DESCRIPTOR_TIME_UNIT)
110+
.setDescription(aMetricData.getDescription())
111+
.setMetricKind(MetricKind.CUMULATIVE)
112+
.setValueType(MetricDescriptor.ValueType.INT64);
113+
114+
MetricDescriptor actualDescriptor =
115+
MetricTranslator.mapMetricDescriptor(customPrefix, aMetricData, aLongPoint);
97116
assertEquals(expectedDescriptor.build(), actualDescriptor);
98117
}
99118

@@ -114,7 +133,7 @@ public void testMapMetricDescriptorNonMonotonicSumIsGauage() {
114133
MetricDescriptor.Builder expectedDescriptor =
115134
MetricDescriptor.newBuilder()
116135
.setDisplayName(metricData.getName())
117-
.setType(DESCRIPTOR_TYPE_URL + metricData.getName())
136+
.setType(DEFAULT_PREFIX + "/" + metricData.getName())
118137
.addLabels(LabelDescriptor.newBuilder().setKey("label1").setValueType(ValueType.STRING))
119138
.addLabels(LabelDescriptor.newBuilder().setKey("label2").setValueType(ValueType.BOOL))
120139
.setUnit(METRIC_DESCRIPTOR_TIME_UNIT)
@@ -123,7 +142,7 @@ public void testMapMetricDescriptorNonMonotonicSumIsGauage() {
123142
.setValueType(MetricDescriptor.ValueType.INT64);
124143

125144
MetricDescriptor actualDescriptor =
126-
MetricTranslator.mapMetricDescriptor(metricData, aLongPoint);
145+
MetricTranslator.mapMetricDescriptor(DEFAULT_PREFIX, metricData, aLongPoint);
127146
assertEquals(expectedDescriptor.build(), actualDescriptor);
128147
}
129148

@@ -144,15 +163,15 @@ public void testMapMetricDescriptorHistogramIsDistribution() {
144163
MetricDescriptor.Builder expectedDescriptor =
145164
MetricDescriptor.newBuilder()
146165
.setDisplayName(metricData.getName())
147-
.setType(DESCRIPTOR_TYPE_URL + metricData.getName())
166+
.setType(DEFAULT_PREFIX + "/" + metricData.getName())
148167
.addLabels(LabelDescriptor.newBuilder().setKey("test").setValueType(ValueType.STRING))
149168
.setUnit(METRIC_DESCRIPTOR_TIME_UNIT)
150169
.setDescription(metricData.getDescription())
151170
.setMetricKind(MetricKind.CUMULATIVE)
152171
.setValueType(MetricDescriptor.ValueType.DISTRIBUTION);
153172

154173
MetricDescriptor actualDescriptor =
155-
MetricTranslator.mapMetricDescriptor(metricData, aHistogramPoint);
174+
MetricTranslator.mapMetricDescriptor(DEFAULT_PREFIX, metricData, aHistogramPoint);
156175
assertEquals(expectedDescriptor.build(), actualDescriptor);
157176
}
158177

@@ -171,7 +190,7 @@ public void testMapMetricDescriptorWithInvalidMetricKindReturnsNull() {
171190
ImmutableSummaryData.create(ImmutableList.of(aDoubleSummaryPoint)));
172191

173192
MetricDescriptor actualDescriptor =
174-
MetricTranslator.mapMetricDescriptor(metricData, aLongPoint);
193+
MetricTranslator.mapMetricDescriptor(DEFAULT_PREFIX, metricData, aLongPoint);
175194
assertNull(actualDescriptor);
176195
}
177196

@@ -191,7 +210,7 @@ public void testMapMetricDescriptorWithDeltaSumReturnsNull() {
191210
true, AggregationTemporality.DELTA, ImmutableList.of(aDoublePoint)));
192211

193212
MetricDescriptor actualDescriptor =
194-
MetricTranslator.mapMetricDescriptor(metricData, aLongPoint);
213+
MetricTranslator.mapMetricDescriptor(DEFAULT_PREFIX, metricData, aLongPoint);
195214
assertNull(actualDescriptor);
196215
}
197216

0 commit comments

Comments
 (0)