Skip to content

Commit b764925

Browse files
committed
chore: Add implementation for firestore resource
1 parent a382a4e commit b764925

File tree

2 files changed

+258
-0
lines changed

2 files changed

+258
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2026 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.datastore.telemetry;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
21+
import io.opentelemetry.api.OpenTelemetry;
22+
import java.util.Map;
23+
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
import org.junit.runners.JUnit4;
26+
27+
@RunWith(JUnit4.class)
28+
public class DatastoreBuiltInMetricsProviderTest {
29+
30+
private static final String PROJECT_ID = "project-id";
31+
32+
@Test
33+
public void testCreateClientAttributes() {
34+
Map<String, String> attributes =
35+
DatastoreBuiltInMetricsProvider.INSTANCE.createClientAttributes();
36+
assertThat(attributes).containsKey(TelemetryConstants.CLIENT_NAME_KEY.getKey());
37+
assertThat(attributes.get(TelemetryConstants.CLIENT_NAME_KEY.getKey()))
38+
.startsWith("datastore-java/");
39+
assertThat(attributes).containsKey(TelemetryConstants.CLIENT_UID_KEY.getKey());
40+
assertThat(attributes.get(TelemetryConstants.CLIENT_UID_KEY.getKey())).contains("@");
41+
assertThat(attributes).containsKey(TelemetryConstants.SERVICE_KEY.getKey());
42+
assertThat(attributes.get(TelemetryConstants.SERVICE_KEY.getKey()))
43+
.isEqualTo(TelemetryConstants.SERVICE_VALUE);
44+
}
45+
46+
@Test
47+
public void testGetOrCreateOpenTelemetry() {
48+
OpenTelemetry otel =
49+
DatastoreBuiltInMetricsProvider.INSTANCE.getOrCreateOpenTelemetry(
50+
PROJECT_ID, "test-db", null, null, "googleapis.com");
51+
assertThat(otel).isNotNull();
52+
53+
OpenTelemetry otel2 =
54+
DatastoreBuiltInMetricsProvider.INSTANCE.getOrCreateOpenTelemetry(
55+
PROJECT_ID, "test-db", null, null, "googleapis.com");
56+
assertThat(otel2).isSameInstanceAs(otel);
57+
}
58+
59+
@Test
60+
public void testDetectClientLocation() {
61+
String location = DatastoreBuiltInMetricsProvider.detectClientLocation();
62+
assertThat(location).isEqualTo("global");
63+
}
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/*
2+
* Copyright 2026 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.datastore.telemetry;
18+
19+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.CLIENT_NAME_KEY;
20+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.CLIENT_UID_KEY;
21+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.DATABASE_ID_KEY;
22+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.GAX_METER_NAME;
23+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.LOCATION_ID_KEY;
24+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.METRIC_NAME_SHORT_OPERATION_COUNT;
25+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.PROJECT_ID_KEY;
26+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.RESOURCE_LABEL_DATABASE_ID;
27+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.RESOURCE_LABEL_LOCATION;
28+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.RESOURCE_LABEL_PROJECT_ID;
29+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.SERVICE_KEY;
30+
import static com.google.cloud.datastore.telemetry.TelemetryConstants.SERVICE_VALUE;
31+
import static com.google.common.truth.Truth.assertThat;
32+
import static org.easymock.EasyMock.createMock;
33+
import static org.easymock.EasyMock.expect;
34+
import static org.easymock.EasyMock.replay;
35+
import static org.easymock.EasyMock.verify;
36+
37+
import com.google.api.core.ApiFuture;
38+
import com.google.api.core.ApiFutures;
39+
import com.google.api.gax.rpc.UnaryCallable;
40+
import com.google.cloud.monitoring.v3.MetricServiceClient;
41+
import com.google.cloud.monitoring.v3.stub.MetricServiceStub;
42+
import com.google.common.collect.ImmutableList;
43+
import com.google.monitoring.v3.CreateTimeSeriesRequest;
44+
import com.google.monitoring.v3.TimeSeries;
45+
import com.google.protobuf.Empty;
46+
import io.opentelemetry.api.common.Attributes;
47+
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
48+
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
49+
import io.opentelemetry.sdk.metrics.data.LongPointData;
50+
import io.opentelemetry.sdk.metrics.data.MetricData;
51+
import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongPointData;
52+
import io.opentelemetry.sdk.metrics.internal.data.ImmutableMetricData;
53+
import io.opentelemetry.sdk.metrics.internal.data.ImmutableSumData;
54+
import io.opentelemetry.sdk.resources.Resource;
55+
import java.util.Collections;
56+
import java.util.Map;
57+
import org.easymock.Capture;
58+
import org.easymock.EasyMock;
59+
import org.junit.Before;
60+
import org.junit.Test;
61+
62+
public class DatastoreCloudMonitoringExporterTest {
63+
64+
private static final String PROJECT_ID = "test-project";
65+
private static final String LOCATION_ID = "global";
66+
private static final String DATABASE_ID = "test-db";
67+
68+
private MetricServiceStub mockMetricServiceStub;
69+
private MetricServiceClient fakeMetricServiceClient;
70+
private DatastoreCloudMonitoringExporter exporter;
71+
72+
private Attributes attributes;
73+
private Attributes resourceAttributes;
74+
private Resource resource;
75+
private InstrumentationScopeInfo scope;
76+
private String clientUid;
77+
private String clientName;
78+
79+
@Before
80+
public void setUp() {
81+
mockMetricServiceStub = createMock(MetricServiceStub.class);
82+
fakeMetricServiceClient = new FakeMetricServiceClient(mockMetricServiceStub);
83+
exporter = new DatastoreCloudMonitoringExporter(PROJECT_ID, fakeMetricServiceClient);
84+
85+
Map<String, String> clientAttributes =
86+
DatastoreBuiltInMetricsProvider.INSTANCE.createClientAttributes();
87+
this.clientUid = clientAttributes.get(CLIENT_UID_KEY.getKey());
88+
this.clientName = clientAttributes.get(CLIENT_NAME_KEY.getKey());
89+
90+
attributes =
91+
Attributes.builder()
92+
.put(DATABASE_ID_KEY, DATABASE_ID)
93+
.put(CLIENT_NAME_KEY, this.clientName)
94+
.put(CLIENT_UID_KEY, this.clientUid)
95+
.build();
96+
97+
resourceAttributes =
98+
Attributes.builder()
99+
.put(PROJECT_ID_KEY, PROJECT_ID)
100+
.put(DATABASE_ID_KEY, DATABASE_ID)
101+
.put(LOCATION_ID_KEY, LOCATION_ID)
102+
.build();
103+
resource = Resource.create(resourceAttributes);
104+
105+
scope = InstrumentationScopeInfo.create(GAX_METER_NAME);
106+
}
107+
108+
@Test
109+
public void testExportingSumData() {
110+
Capture<CreateTimeSeriesRequest> capture = EasyMock.newCapture();
111+
112+
UnaryCallable<CreateTimeSeriesRequest, Empty> mockCallable = createMock(UnaryCallable.class);
113+
expect(mockMetricServiceStub.isShutdown()).andReturn(false).anyTimes();
114+
expect(mockMetricServiceStub.createServiceTimeSeriesCallable()).andReturn(mockCallable);
115+
ApiFuture<Empty> future = ApiFutures.immediateFuture(Empty.getDefaultInstance());
116+
expect(mockCallable.futureCall(EasyMock.capture(capture))).andReturn(future);
117+
118+
replay(mockMetricServiceStub, mockCallable);
119+
120+
long fakeValue = 11L;
121+
long startEpoch = 10;
122+
long endEpoch = 15;
123+
LongPointData longPointData =
124+
ImmutableLongPointData.create(startEpoch, endEpoch, attributes, fakeValue);
125+
126+
MetricData longData =
127+
ImmutableMetricData.createLongSum(
128+
resource,
129+
scope,
130+
"firestore.googleapis.com/internal/client/" + METRIC_NAME_SHORT_OPERATION_COUNT,
131+
"description",
132+
"1",
133+
ImmutableSumData.create(
134+
true, AggregationTemporality.CUMULATIVE, ImmutableList.of(longPointData)));
135+
136+
exporter.export(Collections.singletonList(longData));
137+
138+
CreateTimeSeriesRequest request = capture.getValue();
139+
assertThat(request.getTimeSeriesList()).hasSize(1);
140+
141+
TimeSeries timeSeries = request.getTimeSeriesList().get(0);
142+
143+
assertThat(timeSeries.getResource().getLabelsMap())
144+
.containsExactly(
145+
RESOURCE_LABEL_PROJECT_ID, PROJECT_ID,
146+
RESOURCE_LABEL_DATABASE_ID, DATABASE_ID,
147+
RESOURCE_LABEL_LOCATION, LOCATION_ID);
148+
149+
assertThat(timeSeries.getMetric().getLabelsMap())
150+
.containsExactly(
151+
DATABASE_ID_KEY.getKey(), DATABASE_ID,
152+
CLIENT_NAME_KEY.getKey(), this.clientName,
153+
CLIENT_UID_KEY.getKey(), this.clientUid,
154+
SERVICE_KEY.getKey(), SERVICE_VALUE);
155+
156+
assertThat(timeSeries.getPoints(0).getValue().getInt64Value()).isEqualTo(fakeValue);
157+
158+
verify(mockMetricServiceStub, mockCallable);
159+
}
160+
161+
@Test
162+
public void testFiltersNonDatastoreMetrics() {
163+
expect(mockMetricServiceStub.isShutdown()).andReturn(false).anyTimes();
164+
replay(mockMetricServiceStub);
165+
166+
long startEpoch = 10;
167+
long endEpoch = 15;
168+
LongPointData longPointData =
169+
ImmutableLongPointData.create(startEpoch, endEpoch, attributes, 1L);
170+
171+
InstrumentationScopeInfo otherScope = InstrumentationScopeInfo.create("other-scope");
172+
MetricData otherData =
173+
ImmutableMetricData.createLongSum(
174+
resource,
175+
otherScope,
176+
"other-metric",
177+
"description",
178+
"1",
179+
ImmutableSumData.create(
180+
true, AggregationTemporality.CUMULATIVE, ImmutableList.of(longPointData)));
181+
182+
exporter.export(Collections.singletonList(otherData));
183+
184+
// Should NOT call the mock service because all metrics were filtered out
185+
// verify() will fail if it was called.
186+
verify(mockMetricServiceStub);
187+
}
188+
189+
private static class FakeMetricServiceClient extends MetricServiceClient {
190+
protected FakeMetricServiceClient(MetricServiceStub stub) {
191+
super(stub);
192+
}
193+
}
194+
}

0 commit comments

Comments
 (0)