diff --git a/.github/workflows/hermetic_library_generation.yaml b/.github/workflows/hermetic_library_generation.yaml
index 9f1a24bd6..46b80edc1 100644
--- a/.github/workflows/hermetic_library_generation.yaml
+++ b/.github/workflows/hermetic_library_generation.yaml
@@ -37,7 +37,7 @@ jobs:
with:
fetch-depth: 0
token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }}
- - uses: googleapis/sdk-platform-java/.github/scripts@v2.46.1
+ - uses: googleapis/sdk-platform-java/.github/scripts@v2.49.0
if: env.SHOULD_RUN == 'true'
with:
base_ref: ${{ github.base_ref }}
diff --git a/.github/workflows/unmanaged-dependency-check.yaml b/.github/workflows/unmanaged-dependency-check.yaml
index 54b4586ba..b9df243af 100644
--- a/.github/workflows/unmanaged-dependency-check.yaml
+++ b/.github/workflows/unmanaged-dependency-check.yaml
@@ -14,6 +14,6 @@ jobs:
shell: bash
run: .kokoro/build.sh
- name: Unmanaged dependency check
- uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v3.36.1
+ uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v3.39.0
with:
bom-path: google-cloud-firestore-bom/pom.xml
diff --git a/.kokoro/presubmit/graalvm-native-17.cfg b/.kokoro/presubmit/graalvm-native-17.cfg
index 0b57b9330..f4570c657 100644
--- a/.kokoro/presubmit/graalvm-native-17.cfg
+++ b/.kokoro/presubmit/graalvm-native-17.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.36.1"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.39.0"
}
env_vars: {
diff --git a/.kokoro/presubmit/graalvm-native.cfg b/.kokoro/presubmit/graalvm-native.cfg
index e00ff1103..e8a2b9a3a 100644
--- a/.kokoro/presubmit/graalvm-native.cfg
+++ b/.kokoro/presubmit/graalvm-native.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.36.1"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.39.0"
}
env_vars: {
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d59955cbf..a3eac07be 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,64 @@
# Changelog
+## [3.28.0](https://github.com/googleapis/java-firestore/compare/v3.27.4...v3.28.0) (2024-10-29)
+
+
+### Features
+
+* Improve Logging ([#1892](https://github.com/googleapis/java-firestore/issues/1892)) ([e74457a](https://github.com/googleapis/java-firestore/commit/e74457a1448189978e791fb3efe76d5fe8370ff7))
+
+
+### Dependencies
+
+* Update dependency com.google.api.grpc:proto-google-cloud-trace-v1 to v2.53.0 ([#1913](https://github.com/googleapis/java-firestore/issues/1913)) ([cbaa7a7](https://github.com/googleapis/java-firestore/commit/cbaa7a7c44c82a173194e3c36289bc6b867b93b7))
+* Update dependency com.google.cloud:google-cloud-trace to v2.53.0 ([#1914](https://github.com/googleapis/java-firestore/issues/1914)) ([d3834e1](https://github.com/googleapis/java-firestore/commit/d3834e10b509b3d5c0e1a55318001f9eb80e7f45))
+
+## [3.27.4](https://github.com/googleapis/java-firestore/compare/v3.27.3...v3.27.4) (2024-10-28)
+
+
+### Bug Fixes
+
+* Add the deprecation notice for tracing enable/disable option. ([#1866](https://github.com/googleapis/java-firestore/issues/1866)) ([d213245](https://github.com/googleapis/java-firestore/commit/d213245a77b42eca110ef579a0c9fa7108357717))
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.49.0 ([0bd75f1](https://github.com/googleapis/java-firestore/commit/0bd75f11587a55eb380b094f2900f2f847a7a103))
+
+
+### Dependencies
+
+* Update beam.version to v2.60.0 ([#1894](https://github.com/googleapis/java-firestore/issues/1894)) ([434e6e0](https://github.com/googleapis/java-firestore/commit/434e6e0b9a738f9ac08788dbf5dd94a0678733aa))
+* Update googleapis/sdk-platform-java action to v2.48.0 ([#1899](https://github.com/googleapis/java-firestore/issues/1899)) ([eaf3c0c](https://github.com/googleapis/java-firestore/commit/eaf3c0cfe3dd4dce8afeb9fbb8e2455492c31443))
+* Update sdk-platform-java dependencies ([#1901](https://github.com/googleapis/java-firestore/issues/1901)) ([a698223](https://github.com/googleapis/java-firestore/commit/a698223668a5886c65f00760051b8e022d18559c))
+* Update sdk-platform-java dependencies ([#1906](https://github.com/googleapis/java-firestore/issues/1906)) ([d70f77a](https://github.com/googleapis/java-firestore/commit/d70f77a85c2e17930626674ff292713a276d71ce))
+
+## [3.27.3](https://github.com/googleapis/java-firestore/compare/v3.27.2...v3.27.3) (2024-10-16)
+
+
+### Dependencies
+
+* Update opentelemetry.version to v1.43.0 ([#1884](https://github.com/googleapis/java-firestore/issues/1884)) ([f07ac99](https://github.com/googleapis/java-firestore/commit/f07ac990fece6d59d898419d1cca0b2a91a64248))
+
+## [3.27.2](https://github.com/googleapis/java-firestore/compare/v3.27.1...v3.27.2) (2024-10-10)
+
+
+### Dependencies
+
+* Update dependency com.google.api.grpc:proto-google-cloud-trace-v1 to v2.52.0 ([#1879](https://github.com/googleapis/java-firestore/issues/1879)) ([33cdd41](https://github.com/googleapis/java-firestore/commit/33cdd41949739d37c66830d9b85757d19dbbe31e))
+* Update dependency com.google.cloud:google-cloud-trace to v2.52.0 ([#1880](https://github.com/googleapis/java-firestore/issues/1880)) ([2827f77](https://github.com/googleapis/java-firestore/commit/2827f777bf08bdda3599f1a81193e6957533aa19))
+* Update dependency com.google.cloud.opentelemetry:exporter-trace to v0.33.0 ([#1876](https://github.com/googleapis/java-firestore/issues/1876)) ([b3fba1f](https://github.com/googleapis/java-firestore/commit/b3fba1f58317e00573f37060bd082283ce9ec2ed))
+
+## [3.27.1](https://github.com/googleapis/java-firestore/compare/v3.27.0...v3.27.1) (2024-10-07)
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.47.0 ([c606cea](https://github.com/googleapis/java-firestore/commit/c606ceaccd61cede8799d12b074682a15a03ccff))
+* Update to Java 11, since runtime doesn't support 8. ([#1867](https://github.com/googleapis/java-firestore/issues/1867)) ([723c7cc](https://github.com/googleapis/java-firestore/commit/723c7ccc783b2f56ca72867cd741df197a9f68d7))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.37.0 ([#1871](https://github.com/googleapis/java-firestore/issues/1871)) ([8503a3e](https://github.com/googleapis/java-firestore/commit/8503a3e6badc31eaae4d318925097d010d9d73e4))
+* Update googleapis/sdk-platform-java action to v2.47.0 ([#1870](https://github.com/googleapis/java-firestore/issues/1870)) ([971b164](https://github.com/googleapis/java-firestore/commit/971b164104fe072255a26dfaa4e93958fb43b706))
+
## [3.27.0](https://github.com/googleapis/java-firestore/compare/v3.26.5...v3.27.0) (2024-10-02)
diff --git a/README.md b/README.md
index a2308f34e..dce2c6bfd 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file:
com.google.cloud
libraries-bom
- 26.48.0
+ 26.49.0
pom
import
@@ -36,13 +36,12 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file:
If you are using Maven without the BOM, add this to your dependencies:
-
```xml
com.google.cloud
google-cloud-firestore
- 3.27.0
+ 3.27.3
```
@@ -50,22 +49,21 @@ If you are using Maven without the BOM, add this to your dependencies:
If you are using Gradle 5.x or later, add this to your dependencies:
```Groovy
-implementation platform('com.google.cloud:libraries-bom:26.47.0')
+implementation platform('com.google.cloud:libraries-bom:26.49.0')
implementation 'com.google.cloud:google-cloud-firestore'
```
If you are using Gradle without BOM, add this to your dependencies:
```Groovy
-implementation 'com.google.cloud:google-cloud-firestore:3.27.0'
+implementation 'com.google.cloud:google-cloud-firestore:3.27.3'
```
If you are using SBT, add this to your dependencies:
```Scala
-libraryDependencies += "com.google.cloud" % "google-cloud-firestore" % "3.27.0"
+libraryDependencies += "com.google.cloud" % "google-cloud-firestore" % "3.27.3"
```
-
## Authentication
@@ -221,7 +219,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
[kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-firestore/java11.html
[stability-image]: https://img.shields.io/badge/stability-stable-green
[maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-firestore.svg
-[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-firestore/3.27.0
+[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-firestore/3.27.3
[authentication]: https://github.com/googleapis/google-cloud-java#authentication
[auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes
[predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles
diff --git a/generation_config.yaml b/generation_config.yaml
index f6faade4b..070aa2045 100644
--- a/generation_config.yaml
+++ b/generation_config.yaml
@@ -1,6 +1,6 @@
-gapic_generator_version: 2.46.1
-googleapis_commitish: ce31830ddebce4442c987c7e5daff16d4905f7a3
-libraries_bom_version: 26.47.0
+gapic_generator_version: 2.49.0
+googleapis_commitish: 1f2e5aab4f95b9bd38dd1ac8c7486657f93c1975
+libraries_bom_version: 26.50.0
libraries:
- api_shortname: firestore
name_pretty: Cloud Firestore
diff --git a/google-cloud-firestore-admin/pom.xml b/google-cloud-firestore-admin/pom.xml
index 9634062d4..9ae4e0f4c 100644
--- a/google-cloud-firestore-admin/pom.xml
+++ b/google-cloud-firestore-admin/pom.xml
@@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
google-cloud-firestore-admin
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
jar
Google Cloud Firestore Admin Client
https://github.com/googleapis/java-firestore
@@ -14,7 +14,7 @@
com.google.cloud
google-cloud-firestore-parent
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
diff --git a/google-cloud-firestore-admin/src/main/resources/META-INF/native-image/com.google.cloud.firestore.v1/reflect-config.json b/google-cloud-firestore-admin/src/main/resources/META-INF/native-image/com.google.cloud.firestore.v1/reflect-config.json
index eee0e21ed..de6d04910 100644
--- a/google-cloud-firestore-admin/src/main/resources/META-INF/native-image/com.google.cloud.firestore.v1/reflect-config.json
+++ b/google-cloud-firestore-admin/src/main/resources/META-INF/native-image/com.google.cloud.firestore.v1/reflect-config.json
@@ -395,6 +395,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.api.SelectiveGapicGeneration",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.api.SelectiveGapicGeneration$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.cloud.location.GetLocationRequest",
"queryAllDeclaredConstructors": true,
diff --git a/google-cloud-firestore-bom/pom.xml b/google-cloud-firestore-bom/pom.xml
index b56a470c2..e94832ba9 100644
--- a/google-cloud-firestore-bom/pom.xml
+++ b/google-cloud-firestore-bom/pom.xml
@@ -3,12 +3,12 @@
4.0.0
com.google.cloud
google-cloud-firestore-bom
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
pom
com.google.cloud
sdk-platform-java-config
- 3.36.1
+ 3.39.0
Google Cloud Firestore BOM
@@ -52,37 +52,37 @@
com.google.cloud
google-cloud-firestore
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
com.google.cloud
google-cloud-firestore-admin
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-firestore-admin-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-firestore-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
com.google.api.grpc
proto-google-cloud-firestore-admin-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
com.google.api.grpc
proto-google-cloud-firestore-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
com.google.cloud
proto-google-cloud-firestore-bundle-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
diff --git a/google-cloud-firestore/clirr-ignored-differences.xml b/google-cloud-firestore/clirr-ignored-differences.xml
index 23fa84422..0455ac95e 100644
--- a/google-cloud-firestore/clirr-ignored-differences.xml
+++ b/google-cloud-firestore/clirr-ignored-differences.xml
@@ -326,4 +326,25 @@
com.google.cloud.firestore.FirestoreOpenTelemetryOptions$Builder setTracingEnabled(boolean)
+
+ com/google/cloud/firestore/StreamableQuery
+ 7009
+ void internalStream(*)
+
+
+
+
+ 6011
+ com/google/cloud/firestore/telemetry/TraceUtil
+ SPAN_NAME_*
+
+
+
+
+ 7005
+ com/google/cloud/firestore/StreamableQuery
+ void internalStream(*)
+ *
+
+>>>>>>> origin/main
diff --git a/google-cloud-firestore/pom.xml b/google-cloud-firestore/pom.xml
index 94a5f599f..fc1ed3b02 100644
--- a/google-cloud-firestore/pom.xml
+++ b/google-cloud-firestore/pom.xml
@@ -2,7 +2,7 @@
4.0.0
google-cloud-firestore
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
jar
Google Cloud Firestore
https://github.com/googleapis/java-firestore
@@ -12,11 +12,11 @@
com.google.cloud
google-cloud-firestore-parent
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
google-cloud-firestore
- 1.42.1
+ 1.43.0
@@ -119,6 +119,18 @@
io.opentelemetry.instrumentation
opentelemetry-grpc-1.6
+
+ io.opentelemetry
+ opentelemetry-sdk
+
+
+ io.opentelemetry
+ opentelemetry-sdk-metrics
+
+
+ com.google.cloud.opentelemetry
+ exporter-metrics
+
@@ -181,12 +193,6 @@
test
-
- io.opentelemetry
- opentelemetry-sdk
- ${opentelemetry.version}
- test
-
io.opentelemetry
opentelemetry-sdk-testing
@@ -214,21 +220,7 @@
com.google.cloud.opentelemetry
exporter-trace
- 0.32.0
- test
-
-
-
-
- com.google.api.grpc
- proto-google-cloud-trace-v1
- 2.51.0
- test
-
-
- com.google.cloud.opentelemetry
- exporter-trace
- 0.32.0
+ 0.33.0
test
@@ -236,13 +228,13 @@
com.google.api.grpc
proto-google-cloud-trace-v1
- 2.51.0
+ 2.53.0
test
com.google.cloud
google-cloud-trace
- 2.51.0
+ 2.53.0
test
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/AggregateQuery.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/AggregateQuery.java
index e1f5aacd9..89702e423 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/AggregateQuery.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/AggregateQuery.java
@@ -16,8 +16,8 @@
package com.google.cloud.firestore;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_RUN_AGGREGATION_QUERY;
import static com.google.cloud.firestore.telemetry.TraceUtil.ATTRIBUTE_KEY_ATTEMPT;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_RUN_AGGREGATION_QUERY;
import com.google.api.core.ApiFuture;
import com.google.api.core.InternalExtensionOnly;
@@ -27,6 +27,9 @@
import com.google.api.gax.rpc.StatusCode;
import com.google.api.gax.rpc.StreamController;
import com.google.cloud.Timestamp;
+import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
import com.google.cloud.firestore.telemetry.TraceUtil;
import com.google.cloud.firestore.telemetry.TraceUtil.Scope;
import com.google.cloud.firestore.v1.FirestoreSettings;
@@ -70,6 +73,11 @@ private TraceUtil getTraceUtil() {
return query.getFirestore().getOptions().getTraceUtil();
}
+ @Nonnull
+ private MetricsContext createMetricsContext(String method) {
+ return query.getFirestore().getOptions().getMetricsUtil().createMetricsContext(method);
+ }
+
/** Returns the query whose aggregations will be calculated by this object. */
@Nonnull
public Query getQuery() {
@@ -96,14 +104,20 @@ public ApiFuture get() {
*/
@Nonnull
public ApiFuture> explain(ExplainOptions options) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_AGGREGATION_QUERY_GET);
+ TraceUtil.Span span =
+ getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_AGGREGATION_QUERY_GET);
+
+ MetricsContext metricsContext =
+ createMetricsContext(TelemetryConstants.METHOD_NAME_RUN_AGGREGATION_QUERY_EXPLAIN);
+
try (Scope ignored = span.makeCurrent()) {
AggregateQueryExplainResponseDeliverer responseDeliverer =
new AggregateQueryExplainResponseDeliverer(
/* transactionId= */ null,
/* readTime= */ null,
/* startTimeNanos= */ query.rpcContext.getClock().nanoTime(),
- /* explainOptions= */ options);
+ /* explainOptions= */ options,
+ metricsContext);
runQuery(responseDeliverer, /* attempt */ 0);
ApiFuture> result = responseDeliverer.getFuture();
span.endAtFuture(result);
@@ -121,14 +135,22 @@ ApiFuture get(
getTraceUtil()
.startSpan(
transactionId == null
- ? TraceUtil.SPAN_NAME_AGGREGATION_QUERY_GET
- : TraceUtil.SPAN_NAME_TRANSACTION_GET_AGGREGATION_QUERY);
+ ? TelemetryConstants.METHOD_NAME_AGGREGATION_QUERY_GET
+ : TelemetryConstants.METHOD_NAME_TRANSACTION_GET_AGGREGATION_QUERY);
+
+ MetricsContext metricsContext =
+ createMetricsContext(
+ transactionId == null
+ ? TelemetryConstants.METHOD_NAME_RUN_AGGREGATION_QUERY_GET
+ : TelemetryConstants.METHOD_NAME_RUN_AGGREGATION_QUERY_TRANSACTIONAL);
+
try (Scope ignored = span.makeCurrent()) {
AggregateQueryResponseDeliverer responseDeliverer =
new AggregateQueryResponseDeliverer(
transactionId,
readTime,
- /* startTimeNanos= */ query.rpcContext.getClock().nanoTime());
+ /* startTimeNanos= */ query.rpcContext.getClock().nanoTime(),
+ metricsContext);
runQuery(responseDeliverer, /* attempt= */ 0);
ApiFuture result = responseDeliverer.getFuture();
span.endAtFuture(result);
@@ -165,14 +187,17 @@ private abstract static class ResponseDeliverer {
private final @Nullable com.google.protobuf.Timestamp readTime;
private final long startTimeNanos;
private final SettableApiFuture future = SettableApiFuture.create();
+ private MetricsContext metricsContext;
ResponseDeliverer(
@Nullable ByteString transactionId,
@Nullable com.google.protobuf.Timestamp readTime,
- long startTimeNanos) {
+ long startTimeNanos,
+ MetricsContext metricsContext) {
this.transactionId = transactionId;
this.readTime = readTime;
this.startTimeNanos = startTimeNanos;
+ this.metricsContext = metricsContext;
}
@Nullable
@@ -198,15 +223,29 @@ ApiFuture getFuture() {
return future;
}
- protected void setFuture(T value) {
- future.set(value);
+ void deliverFirstResponse() {
+ metricsContext.recordLatency(MetricType.FIRST_RESPONSE_LATENCY);
}
void deliverError(Throwable throwable) {
future.setException(throwable);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, throwable);
}
- abstract void deliverResult(
+ void deliverResult(
+ @Nullable Map serverData,
+ Timestamp readTime,
+ @Nullable ExplainMetrics metrics) {
+ try {
+ T result = processResult(serverData, readTime, metrics);
+ future.set(result);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY);
+ } catch (Exception error) {
+ deliverError(error);
+ }
+ }
+
+ abstract T processResult(
@Nullable Map serverData,
Timestamp readTime,
@Nullable ExplainMetrics metrics);
@@ -216,24 +255,23 @@ private class AggregateQueryResponseDeliverer extends ResponseDeliverer serverData,
Timestamp readTime,
@Nullable ExplainMetrics metrics) {
if (serverData == null) {
- deliverError(new RuntimeException("Did not receive any aggregate query results."));
- return;
+ throw new RuntimeException("Did not receive any aggregate query results.");
}
- setFuture(
- new AggregateQuerySnapshot(
- AggregateQuery.this,
- readTime,
- convertServerAggregateFieldsMapToClientAggregateFieldsMap(serverData)));
+ return new AggregateQuerySnapshot(
+ AggregateQuery.this,
+ readTime,
+ convertServerAggregateFieldsMapToClientAggregateFieldsMap(serverData));
}
}
@@ -245,8 +283,9 @@ private final class AggregateQueryExplainResponseDeliverer
@Nullable ByteString transactionId,
@Nullable com.google.protobuf.Timestamp readTime,
long startTimeNanos,
- @Nullable ExplainOptions explainOptions) {
- super(transactionId, readTime, startTimeNanos);
+ @Nullable ExplainOptions explainOptions,
+ MetricsContext metricsContext) {
+ super(transactionId, readTime, startTimeNanos, metricsContext);
this.explainOptions = explainOptions;
}
@@ -257,14 +296,13 @@ ExplainOptions getExplainOptions() {
}
@Override
- void deliverResult(
+ ExplainResults processResult(
@Nullable Map serverData,
Timestamp readTime,
@Nullable ExplainMetrics metrics) {
// The server is required to provide ExplainMetrics for explain queries.
if (metrics == null) {
- deliverError(new RuntimeException("Did not receive any metrics for explain query."));
- return;
+ throw new RuntimeException("Did not receive any metrics for explain query.");
}
AggregateQuerySnapshot snapshot =
serverData == null
@@ -273,7 +311,7 @@ void deliverResult(
AggregateQuery.this,
readTime,
convertServerAggregateFieldsMapToClientAggregateFieldsMap(serverData));
- setFuture(new ExplainResults<>(metrics, snapshot));
+ return new ExplainResults<>(metrics, snapshot);
}
}
@@ -284,6 +322,7 @@ private final class AggregateQueryResponseObserver
@Nullable private Map aggregateFieldsMap = null;
@Nullable private ExplainMetrics metrics = null;
private int attempt;
+ private boolean firstResponse = false;
AggregateQueryResponseObserver(ResponseDeliverer responseDeliverer, int attempt) {
this.responseDeliverer = responseDeliverer;
@@ -302,15 +341,20 @@ private boolean isExplainQuery() {
public void onStart(StreamController streamController) {
getTraceUtil()
.currentSpan()
- .addEvent(SPAN_NAME_RUN_AGGREGATION_QUERY + " Stream started.", getAttemptAttributes());
+ .addEvent(METHOD_NAME_RUN_AGGREGATION_QUERY + " Stream started.", getAttemptAttributes());
}
@Override
public void onResponse(RunAggregationQueryResponse response) {
+ if (!firstResponse) {
+ firstResponse = true;
+ responseDeliverer.deliverFirstResponse();
+ }
+
getTraceUtil()
.currentSpan()
.addEvent(
- SPAN_NAME_RUN_AGGREGATION_QUERY + " Response Received.", getAttemptAttributes());
+ METHOD_NAME_RUN_AGGREGATION_QUERY + " Response Received.", getAttemptAttributes());
if (response.hasReadTime()) {
readTime = Timestamp.fromProto(response.getReadTime());
}
@@ -339,7 +383,7 @@ public void onError(Throwable throwable) {
getTraceUtil()
.currentSpan()
.addEvent(
- SPAN_NAME_RUN_AGGREGATION_QUERY + ": Retryable Error",
+ METHOD_NAME_RUN_AGGREGATION_QUERY + ": Retryable Error",
Collections.singletonMap("error.message", throwable.toString()));
runQuery(responseDeliverer, attempt + 1);
@@ -347,7 +391,7 @@ public void onError(Throwable throwable) {
getTraceUtil()
.currentSpan()
.addEvent(
- SPAN_NAME_RUN_AGGREGATION_QUERY + ": Error",
+ METHOD_NAME_RUN_AGGREGATION_QUERY + ": Error",
Collections.singletonMap("error.message", throwable.toString()));
responseDeliverer.deliverError(throwable);
}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/BulkWriter.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/BulkWriter.java
index bc881979c..0a713fe40 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/BulkWriter.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/BulkWriter.java
@@ -26,6 +26,9 @@
import com.google.api.core.SettableApiFuture;
import com.google.api.gax.rpc.ApiException;
import com.google.api.gax.rpc.StatusCode.Code;
+import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
import com.google.cloud.firestore.telemetry.TraceUtil;
import com.google.cloud.firestore.telemetry.TraceUtil.Context;
import com.google.cloud.firestore.telemetry.TraceUtil.Scope;
@@ -912,8 +915,15 @@ private void sendBatchLocked(final BulkCommitBatch batch, final boolean flush) {
firestore
.getOptions()
.getTraceUtil()
- .startSpan(TraceUtil.SPAN_NAME_BULK_WRITER_COMMIT, traceContext)
+ .startSpan(TelemetryConstants.METHOD_NAME_BULK_WRITER_COMMIT, traceContext)
.setAttribute(ATTRIBUTE_KEY_DOC_COUNT, batch.getMutationsSize());
+
+ MetricsContext metricsContext =
+ firestore
+ .getOptions()
+ .getMetricsUtil()
+ .createMetricsContext(TelemetryConstants.METHOD_NAME_BULK_WRITER_COMMIT);
+
try (Scope ignored = span.makeCurrent()) {
ApiFuture result = batch.bulkCommit();
result.addListener(
@@ -926,8 +936,10 @@ private void sendBatchLocked(final BulkCommitBatch batch, final boolean flush) {
},
bulkWriterExecutor);
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
} else {
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CollectionGroup.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CollectionGroup.java
index 3026e5183..159f7077d 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CollectionGroup.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CollectionGroup.java
@@ -21,6 +21,9 @@
import com.google.api.gax.rpc.ApiException;
import com.google.api.gax.rpc.ApiExceptions;
import com.google.api.gax.rpc.ApiStreamObserver;
+import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
import com.google.cloud.firestore.telemetry.TraceUtil;
import com.google.cloud.firestore.telemetry.TraceUtil.Scope;
import com.google.cloud.firestore.v1.FirestoreClient.PartitionQueryPagedResponse;
@@ -109,7 +112,15 @@ public ApiFuture> getPartitions(long desiredPartitionCount)
.getFirestore()
.getOptions()
.getTraceUtil()
- .startSpan(TraceUtil.SPAN_NAME_PARTITION_QUERY);
+ .startSpan(TelemetryConstants.METHOD_NAME_PARTITION_QUERY);
+
+ MetricsContext metricsContext =
+ rpcContext
+ .getFirestore()
+ .getOptions()
+ .getMetricsUtil()
+ .createMetricsContext(TelemetryConstants.METHOD_NAME_PARTITION_QUERY);
+
try (Scope ignored = span.makeCurrent()) {
ApiFuture> result =
ApiFutures.transform(
@@ -127,12 +138,15 @@ public ApiFuture> getPartitions(long desiredPartitionCount)
},
MoreExecutors.directExecutor());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (ApiException exception) {
span.end(exception);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, exception);
throw FirestoreException.forApiException(exception);
} catch (Throwable throwable) {
span.end(throwable);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, throwable);
throw throwable;
}
}
@@ -174,4 +188,10 @@ private void consumePartitions(
}
consumer.apply(new QueryPartition(partitionQuery, lastCursor, null));
}
+
+ @SuppressWarnings("MethodDoesntCallSuperMethod")
+ @Override
+ public String toString() {
+ return String.format("CollectionGroup{partitionQuery=%s, options=%s}", partitionQuery, options);
+ }
}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CollectionReference.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CollectionReference.java
index e1c2841d6..75954d82d 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CollectionReference.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/CollectionReference.java
@@ -24,6 +24,9 @@
import com.google.api.gax.rpc.UnaryCallable;
import com.google.cloud.firestore.encoding.CustomClassMapper;
import com.google.cloud.firestore.spi.v1.FirestoreRpc;
+import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
import com.google.cloud.firestore.telemetry.TraceUtil;
import com.google.cloud.firestore.telemetry.TraceUtil.Scope;
import com.google.cloud.firestore.v1.FirestoreClient.ListDocumentsPagedResponse;
@@ -134,7 +137,15 @@ public Iterable listDocuments() {
.getFirestore()
.getOptions()
.getTraceUtil()
- .startSpan(TraceUtil.SPAN_NAME_COL_REF_LIST_DOCUMENTS);
+ .startSpan(TelemetryConstants.METHOD_NAME_COL_REF_LIST_DOCUMENTS);
+
+ MetricsContext metricsContext =
+ rpcContext
+ .getFirestore()
+ .getOptions()
+ .getMetricsUtil()
+ .createMetricsContext(TelemetryConstants.METHOD_NAME_COL_REF_LIST_DOCUMENTS);
+
try (Scope ignored = span.makeCurrent()) {
ListDocumentsRequest.Builder request = ListDocumentsRequest.newBuilder();
request.setParent(options.getParentPath().toString());
@@ -174,12 +185,15 @@ public void remove() {
}
};
span.end();
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY);
return result;
} catch (ApiException exception) {
span.end(exception);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, exception);
throw FirestoreException.forApiException(exception);
} catch (Throwable throwable) {
span.end(throwable);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, throwable);
throw throwable;
}
}
@@ -200,7 +214,15 @@ public ApiFuture add(@Nonnull final Map field
.getFirestore()
.getOptions()
.getTraceUtil()
- .startSpan(TraceUtil.SPAN_NAME_COL_REF_ADD);
+ .startSpan(TelemetryConstants.METHOD_NAME_COL_REF_ADD);
+
+ MetricsContext metricsContext =
+ rpcContext
+ .getFirestore()
+ .getOptions()
+ .getMetricsUtil()
+ .createMetricsContext(TelemetryConstants.METHOD_NAME_COL_REF_ADD);
+
try (Scope ignored = span.makeCurrent()) {
final DocumentReference documentReference = document();
ApiFuture createFuture = documentReference.create(fields);
@@ -208,9 +230,11 @@ public ApiFuture add(@Nonnull final Map field
ApiFutures.transform(
createFuture, writeResult -> documentReference, MoreExecutors.directExecutor());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentChange.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentChange.java
index cb2e8e0d5..5bfe91e74 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentChange.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentChange.java
@@ -114,4 +114,11 @@ public boolean equals(Object obj) {
public int hashCode() {
return Objects.hash(type, document, oldIndex, newIndex);
}
+
+ @Override
+ public String toString() {
+ return String.format(
+ "DocumentChange{type=%s, document=%s, oldIndex=%d, newIndex=%d}",
+ type, document, oldIndex, newIndex);
+ }
}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java
index 57254bb2b..2b0cc1ddc 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentReference.java
@@ -21,6 +21,10 @@
import com.google.api.core.InternalExtensionOnly;
import com.google.api.gax.rpc.ApiException;
import com.google.api.gax.rpc.ApiExceptions;
+import com.google.cloud.firestore.telemetry.MetricsUtil;
+import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
import com.google.cloud.firestore.telemetry.TraceUtil;
import com.google.cloud.firestore.telemetry.TraceUtil.Scope;
import com.google.cloud.firestore.v1.FirestoreClient.ListCollectionIdsPagedResponse;
@@ -139,6 +143,11 @@ private TraceUtil getTraceUtil() {
return getFirestore().getOptions().getTraceUtil();
}
+ @Nonnull
+ private MetricsUtil getMetricsUtil() {
+ return getFirestore().getOptions().getMetricsUtil();
+ }
+
/**
* Creates a new Document at the DocumentReference's Location. It fails the write if the document
* exists.
@@ -148,14 +157,20 @@ private TraceUtil getTraceUtil() {
*/
@Nonnull
public ApiFuture create(@Nonnull Map fields) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_CREATE);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_CREATE);
+
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_CREATE);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result = extractFirst(writeBatch.create(this, fields).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -169,14 +184,19 @@ public ApiFuture create(@Nonnull Map fields) {
*/
@Nonnull
public ApiFuture create(@Nonnull Object pojo) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_CREATE);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_CREATE);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_CREATE);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result = extractFirst(writeBatch.create(this, pojo).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -190,14 +210,19 @@ public ApiFuture create(@Nonnull Object pojo) {
*/
@Nonnull
public ApiFuture set(@Nonnull Map fields) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_SET);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_SET);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_SET);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result = extractFirst(writeBatch.set(this, fields).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -214,14 +239,19 @@ public ApiFuture set(@Nonnull Map fields) {
@Nonnull
public ApiFuture set(
@Nonnull Map fields, @Nonnull SetOptions options) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_SET);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_SET);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_SET);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result = extractFirst(writeBatch.set(this, fields, options).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -235,14 +265,19 @@ public ApiFuture set(
*/
@Nonnull
public ApiFuture set(@Nonnull Object pojo) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_SET);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_SET);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_SET);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result = extractFirst(writeBatch.set(this, pojo).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -258,14 +293,19 @@ public ApiFuture set(@Nonnull Object pojo) {
*/
@Nonnull
public ApiFuture set(@Nonnull Object pojo, @Nonnull SetOptions options) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_SET);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_SET);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_SET);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result = extractFirst(writeBatch.set(this, pojo, options).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -279,14 +319,19 @@ public ApiFuture set(@Nonnull Object pojo, @Nonnull SetOptions opti
*/
@Nonnull
public ApiFuture update(@Nonnull Map fields) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_UPDATE);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result = extractFirst(writeBatch.update(this, fields).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -301,15 +346,20 @@ public ApiFuture update(@Nonnull Map fields) {
*/
@Nonnull
public ApiFuture update(@Nonnull Map fields, Precondition options) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_UPDATE);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result =
extractFirst(writeBatch.update(this, fields, options).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -326,15 +376,20 @@ public ApiFuture update(@Nonnull Map fields, Precon
@Nonnull
public ApiFuture update(
@Nonnull String field, @Nullable Object value, Object... moreFieldsAndValues) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_UPDATE);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result =
extractFirst(writeBatch.update(this, field, value, moreFieldsAndValues).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -351,15 +406,20 @@ public ApiFuture update(
@Nonnull
public ApiFuture update(
@Nonnull FieldPath fieldPath, @Nullable Object value, Object... moreFieldsAndValues) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_UPDATE);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result =
extractFirst(writeBatch.update(this, fieldPath, value, moreFieldsAndValues).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -380,16 +440,21 @@ public ApiFuture update(
@Nonnull String field,
@Nullable Object value,
Object... moreFieldsAndValues) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_UPDATE);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result =
extractFirst(
writeBatch.update(this, options, field, value, moreFieldsAndValues).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -410,16 +475,21 @@ public ApiFuture update(
@Nonnull FieldPath fieldPath,
@Nullable Object value,
Object... moreFieldsAndValues) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_UPDATE);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result =
extractFirst(
writeBatch.update(this, options, fieldPath, value, moreFieldsAndValues).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -432,14 +502,19 @@ public ApiFuture update(
*/
@Nonnull
public ApiFuture delete(@Nonnull Precondition options) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_DELETE);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_DELETE);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_DELETE);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result = extractFirst(writeBatch.delete(this, options).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -451,14 +526,19 @@ public ApiFuture delete(@Nonnull Precondition options) {
*/
@Nonnull
public ApiFuture delete() {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_DELETE);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_DELETE);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_DELETE);
+
try (Scope ignored = span.makeCurrent()) {
WriteBatch writeBatch = rpcContext.getFirestore().batch();
ApiFuture result = extractFirst(writeBatch.delete(this).commit());
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -472,13 +552,18 @@ public ApiFuture delete() {
*/
@Nonnull
public ApiFuture get() {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_GET);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_GET);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_GET);
+
try (Scope ignored = span.makeCurrent()) {
ApiFuture result = extractFirst(rpcContext.getFirestore().getAll(this));
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -493,14 +578,19 @@ public ApiFuture get() {
*/
@Nonnull
public ApiFuture get(FieldMask fieldMask) {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_GET);
+ TraceUtil.Span span = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_GET);
+ MetricsContext metricsContext =
+ getMetricsUtil().createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_GET);
+
try (Scope ignored = span.makeCurrent()) {
ApiFuture result =
extractFirst(rpcContext.getFirestore().getAll(new DocumentReference[] {this}, fieldMask));
span.endAtFuture(result);
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -513,7 +603,12 @@ public ApiFuture get(FieldMask fieldMask) {
*/
@Nonnull
public Iterable listCollections() {
- TraceUtil.Span span = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_DOC_REF_LIST_COLLECTIONS);
+ TraceUtil.Span span =
+ getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_DOC_REF_LIST_COLLECTIONS);
+ MetricsContext metricsContext =
+ getMetricsUtil()
+ .createMetricsContext(TelemetryConstants.METHOD_NAME_DOC_REF_LIST_COLLECTIONS);
+
try (Scope ignored = span.makeCurrent()) {
ListCollectionIdsRequest.Builder request = ListCollectionIdsRequest.newBuilder();
request.setParent(path.toString());
@@ -547,9 +642,11 @@ public void remove() {
}
};
span.end();
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY);
return result;
} catch (ApiException exception) {
span.end(exception);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, exception);
throw FirestoreException.forApiException(exception);
}
}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java
index 48c691466..5c7217141 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreImpl.java
@@ -32,6 +32,9 @@
import com.google.api.gax.rpc.UnaryCallable;
import com.google.cloud.Timestamp;
import com.google.cloud.firestore.spi.v1.FirestoreRpc;
+import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
import com.google.cloud.firestore.telemetry.TraceUtil;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
@@ -227,6 +230,14 @@ void getAll(
// that we receive from the server.
final int NUM_RESPONSES_PER_TRACE_EVENT = 100;
+ MetricsContext metricsContext =
+ getOptions()
+ .getMetricsUtil()
+ .createMetricsContext(
+ transactionId == null
+ ? TelemetryConstants.METHOD_NAME_BATCH_GET_DOCUMENTS_GET_ALL
+ : TelemetryConstants.METHOD_NAME_BATCH_GET_DOCUMENTS_TRANSACTIONAL);
+
ResponseObserver responseObserver =
new ResponseObserver() {
int numResponses = 0;
@@ -237,7 +248,7 @@ public void onStart(StreamController streamController) {
getTraceUtil()
.currentSpan()
.addEvent(
- TraceUtil.SPAN_NAME_BATCH_GET_DOCUMENTS + ": Start",
+ TelemetryConstants.METHOD_NAME_BATCH_GET_DOCUMENTS + ": Start",
new ImmutableMap.Builder()
.put(ATTRIBUTE_KEY_DOC_COUNT, documentReferences.length)
.put(ATTRIBUTE_KEY_IS_TRANSACTIONAL, transactionId != null)
@@ -253,12 +264,15 @@ public void onResponse(BatchGetDocumentsResponse response) {
if (numResponses == 1) {
getTraceUtil()
.currentSpan()
- .addEvent(TraceUtil.SPAN_NAME_BATCH_GET_DOCUMENTS + ": First response received");
+ .addEvent(
+ TelemetryConstants.METHOD_NAME_BATCH_GET_DOCUMENTS
+ + ": First response received");
+ metricsContext.recordLatency(MetricType.FIRST_RESPONSE_LATENCY);
} else if (numResponses % NUM_RESPONSES_PER_TRACE_EVENT == 0) {
getTraceUtil()
.currentSpan()
.addEvent(
- TraceUtil.SPAN_NAME_BATCH_GET_DOCUMENTS
+ TelemetryConstants.METHOD_NAME_BATCH_GET_DOCUMENTS
+ ": Received "
+ numResponses
+ " responses");
@@ -298,6 +312,7 @@ public void onResponse(BatchGetDocumentsResponse response) {
@Override
public void onError(Throwable throwable) {
getTraceUtil().currentSpan().end(throwable);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, throwable);
apiStreamObserver.onError(throwable);
}
@@ -308,11 +323,12 @@ public void onComplete() {
getTraceUtil()
.currentSpan()
.addEvent(
- TraceUtil.SPAN_NAME_BATCH_GET_DOCUMENTS
+ TelemetryConstants.METHOD_NAME_BATCH_GET_DOCUMENTS
+ ": Completed with "
+ numResponses
+ " responses.",
Collections.singletonMap(ATTRIBUTE_KEY_NUM_RESPONSES, numResponses));
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY);
apiStreamObserver.onCompleted();
}
};
@@ -427,16 +443,30 @@ public ApiFuture runAsyncTransaction(
@Nonnull final Transaction.AsyncFunction updateFunction,
@Nonnull TransactionOptions transactionOptions) {
- if (transactionOptions.getReadTime() != null) {
- // READ_ONLY transactions with readTime have no retry, nor transaction state, so we don't need
- // a runner.
- return updateFunction.updateCallback(
- new ReadTimeTransaction(this, transactionOptions.getReadTime()));
- } else {
- // For READ_ONLY transactions without readTime, there is still strong consistency applied,
- // that cannot be tracked client side.
- return new ServerSideTransactionRunner<>(this, updateFunction, transactionOptions).run();
+ MetricsContext metricsContext =
+ getOptions()
+ .getMetricsUtil()
+ .createMetricsContext(TelemetryConstants.METHOD_NAME_RUN_TRANSACTION);
+ ApiFuture result;
+
+ try {
+ if (transactionOptions.getReadTime() != null) {
+ // READ_ONLY transactions with readTime have no retry, nor transaction state, so we don't
+ // need a runner.
+ result =
+ updateFunction.updateCallback(
+ new ReadTimeTransaction(this, transactionOptions.getReadTime()));
+ } else {
+ // For READ_ONLY transactions without readTime, there is still strong consistency applied,
+ // that cannot be tracked client side.
+ result = new ServerSideTransactionRunner<>(this, updateFunction, transactionOptions).run();
+ }
+ metricsContext.recordLatencyAtFuture(MetricType.END_TO_END_LATENCY, result);
+ } catch (Exception error) {
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
+ throw error;
}
+ return result;
}
@Nonnull
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreOpenTelemetryOptions.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreOpenTelemetryOptions.java
index 175a20c1a..6fe0c4375 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreOpenTelemetryOptions.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreOpenTelemetryOptions.java
@@ -27,12 +27,19 @@
*/
@BetaApi
public class FirestoreOpenTelemetryOptions {
+ private final boolean exportBuiltinMetricsToGoogleCloudMonitoring;
private final @Nullable OpenTelemetry openTelemetry;
FirestoreOpenTelemetryOptions(Builder builder) {
+ this.exportBuiltinMetricsToGoogleCloudMonitoring =
+ builder.exportBuiltinMetricsToGoogleCloudMonitoring;
this.openTelemetry = builder.openTelemetry;
}
+ public boolean exportBuiltinMetricsToGoogleCloudMonitoring() {
+ return exportBuiltinMetricsToGoogleCloudMonitoring;
+ }
+
public OpenTelemetry getOpenTelemetry() {
return openTelemetry;
}
@@ -48,13 +55,18 @@ public static FirestoreOpenTelemetryOptions.Builder newBuilder() {
}
public static class Builder {
+ private boolean exportBuiltinMetricsToGoogleCloudMonitoring;
@Nullable private OpenTelemetry openTelemetry;
private Builder() {
+ // TODO(metrics): default this to true when feature is ready
+ exportBuiltinMetricsToGoogleCloudMonitoring = false;
openTelemetry = null;
}
private Builder(FirestoreOpenTelemetryOptions options) {
+ this.exportBuiltinMetricsToGoogleCloudMonitoring =
+ options.exportBuiltinMetricsToGoogleCloudMonitoring;
this.openTelemetry = options.openTelemetry;
}
@@ -63,6 +75,20 @@ public FirestoreOpenTelemetryOptions build() {
return new FirestoreOpenTelemetryOptions(this);
}
+ // TODO(metrics): make this public when feature is ready.
+ /**
+ * Sets whether built-in metrics should be exported to Google Cloud Monitoring
+ *
+ * @param exportBuiltinMetrics Whether built-in metrics should be exported to Google Cloud
+ * Monitoring.
+ */
+ @Nonnull
+ private FirestoreOpenTelemetryOptions.Builder exportBuiltinMetricsToGoogleCloudMonitoring(
+ boolean exportBuiltinMetrics) {
+ this.exportBuiltinMetricsToGoogleCloudMonitoring = exportBuiltinMetrics;
+ return this;
+ }
+
/**
* Sets the {@link OpenTelemetry} to use with this Firestore instance. If telemetry collection
* is enabled, but an `OpenTelemetry` is not provided, the Firestore SDK will attempt to use the
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreOptions.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreOptions.java
index b80b9dacd..b0887f602 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreOptions.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FirestoreOptions.java
@@ -24,12 +24,15 @@
import com.google.api.gax.core.GoogleCredentialsProvider;
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
import com.google.api.gax.rpc.TransportChannelProvider;
+import com.google.api.gax.tracing.ApiTracerFactory;
import com.google.auth.Credentials;
import com.google.cloud.ServiceDefaults;
import com.google.cloud.ServiceOptions;
import com.google.cloud.TransportOptions;
import com.google.cloud.firestore.spi.v1.FirestoreRpc;
import com.google.cloud.firestore.spi.v1.GrpcFirestoreRpc;
+import com.google.cloud.firestore.telemetry.CompositeApiTracerFactory;
+import com.google.cloud.firestore.telemetry.MetricsUtil;
import com.google.cloud.firestore.v1.FirestoreSettings;
import com.google.cloud.grpc.GrpcTransportOptions;
import com.google.common.collect.ImmutableMap;
@@ -37,6 +40,7 @@
import io.grpc.ManagedChannelBuilder;
import java.io.IOException;
import java.net.URI;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -64,6 +68,7 @@ public final class FirestoreOptions extends ServiceOptions apiTracerFactories = new ArrayList<>();
+ // Prefer any direct ApiTracerFactory that might have been set on the builder.
+ if (super.getApiTracerFactory() != null) {
+ apiTracerFactories.add(super.getApiTracerFactory());
+ }
+ // Add Metrics Tracer factory if built-in metrics are enabled.
+ metricsUtil.addMetricsTracerFactory(apiTracerFactories);
+
+ if (apiTracerFactories.isEmpty()) {
+ return null;
+ }
+ return new CompositeApiTracerFactory(apiTracerFactories);
+ }
+
public String getDatabaseId() {
return databaseId;
}
@@ -127,6 +149,11 @@ com.google.cloud.firestore.telemetry.TraceUtil getTraceUtil() {
return traceUtil;
}
+ @Nonnull
+ com.google.cloud.firestore.telemetry.MetricsUtil getMetricsUtil() {
+ return metricsUtil;
+ }
+
@BetaApi
@Nonnull
public FirestoreOpenTelemetryOptions getOpenTelemetryOptions() {
@@ -325,6 +352,9 @@ protected FirestoreOptions(Builder builder) {
? builder.databaseId
: FirestoreDefaults.INSTANCE.getDatabaseId();
+ // Set up the `MetricsUtil` instance after the database ID has been set.
+ this.metricsUtil = MetricsUtil.getInstance(this);
+
if (builder.channelProvider == null) {
ApiFunction channelConfigurator =
this.traceUtil.getChannelConfigurator();
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/GenericQuerySnapshot.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/GenericQuerySnapshot.java
index a7b02e22a..cd7348de4 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/GenericQuerySnapshot.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/GenericQuerySnapshot.java
@@ -162,4 +162,11 @@ public boolean equals(Object o) {
public int hashCode() {
return Objects.hash(query, this.getDocumentChanges(), this.getDocuments());
}
+
+ @Override
+ public String toString() {
+ return String.format(
+ "%s{query=%s, readTime=%s, documentChanges=%s, documents=%s}",
+ getClass().getSimpleName(), query, readTime, documentChanges, documents);
+ }
}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Query.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Query.java
index e66393b84..f93ec2c29 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Query.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Query.java
@@ -35,6 +35,8 @@
import com.google.cloud.Timestamp;
import com.google.cloud.firestore.Query.QueryOptions.Builder;
import com.google.cloud.firestore.encoding.CustomClassMapper;
+import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.firestore.bundle.BundledQuery;
@@ -1487,7 +1489,10 @@ public void stream(@Nonnull final ApiStreamObserver responseOb
"Query results for queries that include limitToLast() constraints cannot be streamed. "
+ "Use Query.get() instead.");
- internalStream(
+ MetricsContext metricsContext =
+ createMetricsContext(TelemetryConstants.METHOD_NAME_RUN_QUERY_GET);
+
+ ApiStreamObserver observer =
new ApiStreamObserver() {
@Override
public void onNext(RunQueryResponse runQueryResponse) {
@@ -1509,7 +1514,10 @@ public void onError(Throwable throwable) {
public void onCompleted() {
responseObserver.onCompleted();
}
- },
+ };
+
+ internalStream(
+ new MonitoredStreamResponseObserver(observer, metricsContext),
/* startTimeNanos= */ rpcContext.getClock().nanoTime(),
/* transactionId= */ null,
/* readTime= */ null,
@@ -1533,8 +1541,12 @@ public ApiFuture explainStream(
"Query results for queries that include limitToLast() constraints cannot be streamed. "
+ "Use Query.explain() instead.");
+ MetricsContext metricsContext =
+ createMetricsContext(TelemetryConstants.METHOD_NAME_RUN_QUERY_EXPLAIN);
+
final SettableApiFuture metricsFuture = SettableApiFuture.create();
- internalStream(
+
+ ApiStreamObserver observer =
new ApiStreamObserver() {
@Override
public void onNext(RunQueryResponse runQueryResponse) {
@@ -1566,7 +1578,10 @@ public void onCompleted() {
new RuntimeException("Did not receive any explain results."));
}
}
- },
+ };
+
+ internalStream(
+ new MonitoredStreamResponseObserver(observer, metricsContext),
/* startTimeNanos= */ rpcContext.getClock().nanoTime(),
/* transactionId= */ null,
/* readTime= */ null,
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ReadTimeTransaction.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ReadTimeTransaction.java
index 0c423469a..8780e9c63 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ReadTimeTransaction.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ReadTimeTransaction.java
@@ -18,6 +18,7 @@
import com.google.api.core.ApiFuture;
import com.google.api.core.ApiFutures;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
import com.google.cloud.firestore.telemetry.TraceUtil;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.MoreExecutors;
@@ -57,7 +58,8 @@ public boolean hasTransactionId() {
public ApiFuture get(@Nonnull DocumentReference documentRef) {
TraceUtil.Span span =
getTraceUtil()
- .startSpan(TraceUtil.SPAN_NAME_TRANSACTION_GET_DOCUMENT, transactionTraceContext);
+ .startSpan(
+ TelemetryConstants.METHOD_NAME_TRANSACTION_GET_DOCUMENT, transactionTraceContext);
try (TraceUtil.Scope ignored = span.makeCurrent()) {
ApiFuture result =
ApiFutures.transform(
@@ -79,7 +81,8 @@ public ApiFuture> getAll(
@Nonnull DocumentReference... documentReferences) {
TraceUtil.Span span =
getTraceUtil()
- .startSpan(TraceUtil.SPAN_NAME_TRANSACTION_GET_DOCUMENTS, transactionTraceContext);
+ .startSpan(
+ TelemetryConstants.METHOD_NAME_TRANSACTION_GET_DOCUMENTS, transactionTraceContext);
try (TraceUtil.Scope ignored = span.makeCurrent()) {
ApiFuture> result =
firestore.getAll(documentReferences, /* fieldMask= */ null, readTime);
@@ -97,7 +100,8 @@ public ApiFuture> getAll(
@Nonnull DocumentReference[] documentReferences, @Nullable FieldMask fieldMask) {
TraceUtil.Span span =
getTraceUtil()
- .startSpan(TraceUtil.SPAN_NAME_TRANSACTION_GET_DOCUMENTS, transactionTraceContext);
+ .startSpan(
+ TelemetryConstants.METHOD_NAME_TRANSACTION_GET_DOCUMENTS, transactionTraceContext);
try (TraceUtil.Scope ignored = span.makeCurrent()) {
ApiFuture> result =
firestore.getAll(documentReferences, /* fieldMask= */ null, readTime);
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ServerSideTransaction.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ServerSideTransaction.java
index 5d366c965..40dd64ce8 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ServerSideTransaction.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ServerSideTransaction.java
@@ -19,6 +19,7 @@
import com.google.api.core.ApiFuture;
import com.google.api.core.ApiFutures;
import com.google.cloud.firestore.TransactionOptions.TransactionOptionsType;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
import com.google.cloud.firestore.telemetry.TraceUtil;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.MoreExecutors;
@@ -108,7 +109,9 @@ ApiFuture> commit() {
/** Rolls a transaction back and releases all read locks. */
ApiFuture rollback() {
TraceUtil.Span span =
- getTraceUtil().startSpan(TraceUtil.SPAN_NAME_TRANSACTION_ROLLBACK, transactionTraceContext);
+ getTraceUtil()
+ .startSpan(
+ TelemetryConstants.METHOD_NAME_TRANSACTION_ROLLBACK, transactionTraceContext);
try (TraceUtil.Scope ignored = span.makeCurrent()) {
RollbackRequest req =
RollbackRequest.newBuilder()
@@ -158,7 +161,8 @@ public boolean hasTransactionId() {
public ApiFuture get(@Nonnull DocumentReference documentRef) {
TraceUtil.Span span =
getTraceUtil()
- .startSpan(TraceUtil.SPAN_NAME_TRANSACTION_GET_DOCUMENT, transactionTraceContext);
+ .startSpan(
+ TelemetryConstants.METHOD_NAME_TRANSACTION_GET_DOCUMENT, transactionTraceContext);
try (TraceUtil.Scope ignored = span.makeCurrent()) {
Preconditions.checkState(isEmpty(), READ_BEFORE_WRITE_ERROR_MSG);
ApiFuture result =
@@ -191,7 +195,8 @@ public ApiFuture> getAll(
Preconditions.checkState(isEmpty(), READ_BEFORE_WRITE_ERROR_MSG);
TraceUtil.Span span =
getTraceUtil()
- .startSpan(TraceUtil.SPAN_NAME_TRANSACTION_GET_DOCUMENTS, transactionTraceContext);
+ .startSpan(
+ TelemetryConstants.METHOD_NAME_TRANSACTION_GET_DOCUMENTS, transactionTraceContext);
try (TraceUtil.Scope ignored = span.makeCurrent()) {
ApiFuture> result =
firestore.getAll(
@@ -219,7 +224,8 @@ public ApiFuture> getAll(
Preconditions.checkState(isEmpty(), READ_BEFORE_WRITE_ERROR_MSG);
TraceUtil.Span span =
getTraceUtil()
- .startSpan(TraceUtil.SPAN_NAME_TRANSACTION_GET_DOCUMENTS, transactionTraceContext);
+ .startSpan(
+ TelemetryConstants.METHOD_NAME_TRANSACTION_GET_DOCUMENTS, transactionTraceContext);
try (TraceUtil.Scope ignored = span.makeCurrent()) {
ApiFuture> result =
firestore.getAll(documentReferences, fieldMask, transactionId, /* readTime= */ null);
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ServerSideTransactionRunner.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ServerSideTransactionRunner.java
index db8ebff63..29c92331a 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ServerSideTransactionRunner.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/ServerSideTransactionRunner.java
@@ -26,6 +26,9 @@
import com.google.api.gax.retrying.ExponentialRetryAlgorithm;
import com.google.api.gax.retrying.TimedAttemptSettings;
import com.google.api.gax.rpc.ApiException;
+import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
import com.google.cloud.firestore.telemetry.TraceUtil;
import com.google.cloud.firestore.telemetry.TraceUtil.Scope;
import com.google.cloud.firestore.telemetry.TraceUtil.Span;
@@ -59,6 +62,7 @@ final class ServerSideTransactionRunner {
private int attemptsRemaining;
private Span runTransactionSpan;
private TraceUtil.Context runTransactionContext;
+ private MetricsContext metricsContext;
/**
* @param firestore The active Firestore instance
@@ -85,6 +89,11 @@ final class ServerSideTransactionRunner {
new ExponentialRetryAlgorithm(
firestore.getOptions().getRetrySettings(), CurrentMillisClock.getDefaultClock());
this.nextBackoffAttempt = backoffAlgorithm.createFirstAttempt();
+ this.metricsContext =
+ firestore
+ .getOptions()
+ .getMetricsUtil()
+ .createMetricsContext(TelemetryConstants.METHOD_NAME_TRANSACTION_RUN);
}
@Nonnull
@@ -93,7 +102,14 @@ private TraceUtil getTraceUtil() {
}
ApiFuture run() {
- runTransactionSpan = getTraceUtil().startSpan(TraceUtil.SPAN_NAME_TRANSACTION_RUN);
+ ApiFuture result = runInternally();
+ metricsContext.recordLatencyAtFuture(MetricType.TRANSACTION_LATENCY, result);
+ metricsContext.recordCounterAtFuture(MetricType.TRANSACTION_ATTEMPT_COUNT, result);
+ return result;
+ }
+
+ ApiFuture runInternally() {
+ runTransactionSpan = getTraceUtil().startSpan(TelemetryConstants.METHOD_NAME_TRANSACTION_RUN);
runTransactionSpan.setAttribute(
ATTRIBUTE_KEY_TRANSACTION_TYPE, transactionOptions.getType().name());
runTransactionSpan.setAttribute(
@@ -102,6 +118,7 @@ ApiFuture run() {
try (Scope ignored = runTransactionSpan.makeCurrent()) {
runTransactionContext = getTraceUtil().currentContext();
--attemptsRemaining;
+ metricsContext.incrementCounter();
ApiFuture result =
ApiFutures.catchingAsync(
ApiFutures.transformAsync(
@@ -119,7 +136,8 @@ ApiFuture run() {
ApiFuture begin() {
TraceUtil.Span span =
- getTraceUtil().startSpan(TraceUtil.SPAN_NAME_TRANSACTION_BEGIN, runTransactionContext);
+ getTraceUtil()
+ .startSpan(TelemetryConstants.METHOD_NAME_TRANSACTION_BEGIN, runTransactionContext);
try (Scope ignored = span.makeCurrent()) {
ServerSideTransaction previousTransaction = this.transaction;
this.transaction = null;
@@ -235,7 +253,7 @@ private ApiFuture restartTransactionCallback(Throwable throwable) {
getTraceUtil()
.currentSpan()
.addEvent("Initiating transaction retry. Attempts remaining: " + attemptsRemaining);
- return run();
+ return runInternally();
} else {
final FirestoreException firestoreException =
FirestoreException.forApiException(
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/SilenceableBidiStream.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/SilenceableBidiStream.java
index fa358ecaa..634e08ca8 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/SilenceableBidiStream.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/SilenceableBidiStream.java
@@ -45,11 +45,11 @@
*/
final class SilenceableBidiStream
implements BidiStreamObserver {
+ private static final Logger LOGGER = Logger.getLogger(SilenceableBidiStream.class.getName());
private final ClientStream stream;
private final BidiStreamObserver delegate;
private boolean silence = false;
- private static final Logger LOGGER = Logger.getLogger(Watch.class.getName());
SilenceableBidiStream(
BidiStreamObserver responseObserverT,
@@ -63,17 +63,17 @@ public boolean isSilenced() {
}
public void send(RequestT request) {
- LOGGER.info(stream.toString());
+ LOGGER.fine(stream.toString());
stream.send(request);
}
public void closeSend() {
- LOGGER.info(stream::toString);
+ LOGGER.fine(stream::toString);
stream.closeSend();
}
public void closeSendAndSilence() {
- LOGGER.info(stream::toString);
+ LOGGER.fine(stream::toString);
silence = true;
stream.closeSend();
}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/StreamableQuery.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/StreamableQuery.java
index fcba40f47..a959f9a15 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/StreamableQuery.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/StreamableQuery.java
@@ -20,13 +20,18 @@
import static com.google.common.collect.Lists.reverse;
import com.google.api.core.ApiFuture;
+import com.google.api.core.InternalApi;
import com.google.api.core.SettableApiFuture;
import com.google.api.gax.rpc.ApiStreamObserver;
import com.google.api.gax.rpc.ResponseObserver;
import com.google.api.gax.rpc.StatusCode;
import com.google.api.gax.rpc.StreamController;
import com.google.cloud.Timestamp;
+import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
import com.google.cloud.firestore.telemetry.TraceUtil;
+import com.google.cloud.firestore.telemetry.TraceUtil.Scope;
import com.google.cloud.firestore.v1.FirestoreSettings;
import com.google.common.collect.ImmutableMap;
import com.google.firestore.v1.Document;
@@ -49,6 +54,7 @@
* `isRetryableWithCursor`. Retrying with a cursor means that the StreamableQuery can be resumed
* where it failed by first calling `startAfter(lastDocumentReceived)`.
*/
+@InternalApi
public abstract class StreamableQuery {
final Query.QueryOptions options;
final FirestoreRpcContext> rpcContext;
@@ -79,6 +85,10 @@ abstract SnapshotType createSnaphot(
public Firestore getFirestore() {
return rpcContext.getFirestore();
}
+
+ MetricsContext createMetricsContext(String methodName) {
+ return getFirestore().getOptions().getMetricsUtil().createMetricsContext(methodName);
+ }
/**
* Executes the query and returns the results as QuerySnapshot.
*
@@ -100,11 +110,19 @@ ApiFuture get(
.getTraceUtil()
.startSpan(
transactionId == null
- ? TraceUtil.SPAN_NAME_QUERY_GET
- : TraceUtil.SPAN_NAME_TRANSACTION_GET_QUERY);
+ ? TelemetryConstants.METHOD_NAME_QUERY_GET
+ : TelemetryConstants.METHOD_NAME_TRANSACTION_GET_QUERY);
+
+ MetricsContext metricsContext =
+ createMetricsContext(
+ transactionId != null
+ ? TelemetryConstants.METHOD_NAME_RUN_QUERY_TRANSACTIONAL
+ : TelemetryConstants.METHOD_NAME_RUN_QUERY_GET);
+
try (Scope ignored = span.makeCurrent()) {
final SettableApiFuture result = SettableApiFuture.create();
- internalStream(
+
+ ApiStreamObserver observer =
new ApiStreamObserver() {
final List documentSnapshots = new ArrayList<>();
Timestamp responseReadTime;
@@ -139,7 +157,10 @@ public void onCompleted() {
SnapshotType querySnapshot = createSnaphot(responseReadTime, resultView);
result.set(querySnapshot);
}
- },
+ };
+
+ internalStream(
+ new MonitoredStreamResponseObserver(observer, metricsContext),
/* startTimeNanos= */ rpcContext.getClock().nanoTime(),
transactionId,
/* readTime= */ requestReadTime,
@@ -150,6 +171,7 @@ public void onCompleted() {
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
@@ -165,11 +187,18 @@ public void onCompleted() {
@Nonnull
public ApiFuture> explain(ExplainOptions options) {
TraceUtil.Span span =
- getFirestore().getOptions().getTraceUtil().startSpan(TraceUtil.SPAN_NAME_QUERY_GET);
+ getFirestore()
+ .getOptions()
+ .getTraceUtil()
+ .startSpan(TelemetryConstants.METHOD_NAME_QUERY_GET);
+
+ MetricsContext metricsContext =
+ createMetricsContext(TelemetryConstants.METHOD_NAME_RUN_QUERY_EXPLAIN);
try (Scope ignored = span.makeCurrent()) {
final SettableApiFuture> result = SettableApiFuture.create();
- internalStream(
+
+ ApiStreamObserver observer =
new ApiStreamObserver() {
@Nullable List documentSnapshots = null;
Timestamp readTime;
@@ -222,7 +251,10 @@ public void onCompleted() {
}
result.set(new ExplainResults<>(metrics, snapshot));
}
- },
+ };
+
+ internalStream(
+ new MonitoredStreamResponseObserver(observer, metricsContext),
/* startTimeNanos= */ rpcContext.getClock().nanoTime(),
/* transactionId= */ null,
/* readTime= */ null,
@@ -233,25 +265,61 @@ public void onCompleted() {
return result;
} catch (Exception error) {
span.end(error);
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, error);
throw error;
}
}
- protected void internalStream(
- final ApiStreamObserver runQueryResponseObserver,
+ class MonitoredStreamResponseObserver implements ApiStreamObserver {
+ private final ApiStreamObserver observer;
+ private final MetricsContext metricsContext;
+ private boolean receivedFirstResponse = false;
+
+ // Constructor to initialize with the delegate and MetricsContext
+ public MonitoredStreamResponseObserver(
+ ApiStreamObserver observer, MetricsContext metricsContext) {
+ this.observer = observer;
+ this.metricsContext = metricsContext;
+ }
+
+ @Override
+ public void onNext(RunQueryResponse value) {
+ if (!receivedFirstResponse) {
+ receivedFirstResponse = true;
+ metricsContext.recordLatency(MetricType.FIRST_RESPONSE_LATENCY);
+ }
+ observer.onNext(value);
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY, t);
+ observer.onError(t);
+ }
+
+ @Override
+ public void onCompleted() {
+ metricsContext.recordLatency(MetricType.END_TO_END_LATENCY);
+ observer.onCompleted();
+ }
+ }
+
+ void internalStream(
+ final MonitoredStreamResponseObserver streamResponseObserver,
final long startTimeNanos,
@Nullable final ByteString transactionId,
@Nullable final Timestamp readTime,
@Nullable final ExplainOptions explainOptions,
final boolean isRetryRequestWithCursor) {
TraceUtil traceUtil = getFirestore().getOptions().getTraceUtil();
+
// To reduce the size of traces, we only register one event for every 100 responses
// that we receive from the server.
final int NUM_RESPONSES_PER_TRACE_EVENT = 100;
TraceUtil.Span currentSpan = traceUtil.currentSpan();
currentSpan.addEvent(
- TraceUtil.SPAN_NAME_RUN_QUERY,
+ TelemetryConstants.METHOD_NAME_RUN_QUERY,
new ImmutableMap.Builder()
.put(ATTRIBUTE_KEY_IS_TRANSACTIONAL, transactionId != null)
.put(ATTRIBUTE_KEY_IS_RETRY_WITH_CURSOR, isRetryRequestWithCursor)
@@ -276,16 +344,19 @@ public void onStart(StreamController streamController) {}
public void onResponse(RunQueryResponse response) {
if (!firstResponse) {
firstResponse = true;
- currentSpan.addEvent(TraceUtil.SPAN_NAME_RUN_QUERY + ": First Response");
+ currentSpan.addEvent(TelemetryConstants.METHOD_NAME_RUN_QUERY + ": First Response");
}
- runQueryResponseObserver.onNext(response);
+ streamResponseObserver.onNext(response);
if (response.hasDocument()) {
numDocuments++;
if (numDocuments % NUM_RESPONSES_PER_TRACE_EVENT == 0) {
currentSpan.addEvent(
- TraceUtil.SPAN_NAME_RUN_QUERY + ": Received " + numDocuments + " documents");
+ TelemetryConstants.METHOD_NAME_RUN_QUERY
+ + ": Received "
+ + numDocuments
+ + " documents");
}
Document document = response.getDocument();
QueryDocumentSnapshot documentSnapshot =
@@ -296,7 +367,7 @@ public void onResponse(RunQueryResponse response) {
if (response.getDone()) {
currentSpan.addEvent(
- TraceUtil.SPAN_NAME_RUN_QUERY + ": Received RunQueryResponse.Done");
+ TelemetryConstants.METHOD_NAME_RUN_QUERY + ": Received RunQueryResponse.Done");
onComplete();
}
}
@@ -306,12 +377,12 @@ public void onError(Throwable throwable) {
QueryDocumentSnapshot cursor = lastReceivedDocument.get();
if (isRetryableWithCursor() && shouldRetry(cursor, throwable)) {
currentSpan.addEvent(
- TraceUtil.SPAN_NAME_RUN_QUERY + ": Retryable Error",
+ TelemetryConstants.METHOD_NAME_RUN_QUERY + ": Retryable Error",
Collections.singletonMap("error.message", throwable.toString()));
startAfter(cursor)
.internalStream(
- runQueryResponseObserver,
+ streamResponseObserver,
startTimeNanos,
/* transactionId= */ null,
options.getRequireConsistency() ? cursor.getReadTime() : null,
@@ -319,9 +390,9 @@ public void onError(Throwable throwable) {
/* isRetryRequestWithCursor= */ true);
} else {
currentSpan.addEvent(
- TraceUtil.SPAN_NAME_RUN_QUERY + ": Error",
+ TelemetryConstants.METHOD_NAME_RUN_QUERY + ": Error",
Collections.singletonMap("error.message", throwable.toString()));
- runQueryResponseObserver.onError(throwable);
+ streamResponseObserver.onError(throwable);
}
}
@@ -330,9 +401,9 @@ public void onComplete() {
if (hasCompleted) return;
hasCompleted = true;
currentSpan.addEvent(
- TraceUtil.SPAN_NAME_RUN_QUERY + ": Completed",
+ TelemetryConstants.METHOD_NAME_RUN_QUERY + ": Completed",
Collections.singletonMap(ATTRIBUTE_KEY_DOC_COUNT, numDocuments));
- runQueryResponseObserver.onCompleted();
+ streamResponseObserver.onCompleted();
}
boolean shouldRetry(DocumentSnapshot lastDocument, Throwable t) {
@@ -397,4 +468,9 @@ private boolean isRetryableError(Throwable throwable, Set retry
}
return false;
}
+
+ @Override
+ public String toString() {
+ return String.format("%s{options=%s}", getClass().getSimpleName(), options);
+ }
}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java
index 04d83a1a1..ff1b7e2d6 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java
@@ -18,6 +18,7 @@
import com.google.api.core.ApiFuture;
import com.google.api.core.InternalExtensionOnly;
+import com.google.cloud.firestore.telemetry.MetricsUtil;
import com.google.cloud.firestore.telemetry.TraceUtil;
import com.google.cloud.firestore.telemetry.TraceUtil.Context;
import java.util.List;
@@ -49,6 +50,12 @@ TraceUtil getTraceUtil() {
return firestore.getOptions().getTraceUtil();
}
+ // TODO(Metrics): implement transaction latency and attempt count metrics
+ @Nonnull
+ MetricsUtil getMetricsUtil() {
+ return firestore.getOptions().getMetricsUtil();
+ }
+
@Nonnull
Context setTransactionTraceContext(Context context) {
return transactionTraceContext = context;
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java
index 31434667b..cfa852ce4 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java
@@ -26,6 +26,7 @@
import com.google.api.core.InternalExtensionOnly;
import com.google.cloud.firestore.UserDataConverter.EncodingOptions;
import com.google.cloud.firestore.encoding.CustomClassMapper;
+import com.google.cloud.firestore.telemetry.TelemetryConstants;
import com.google.cloud.firestore.telemetry.TraceUtil;
import com.google.cloud.firestore.telemetry.TraceUtil.Scope;
import com.google.common.base.Preconditions;
@@ -616,8 +617,8 @@ ApiFuture> commit(@Nullable ByteString transactionId) {
.getTraceUtil()
.startSpan(
transactionId == null
- ? TraceUtil.SPAN_NAME_BATCH_COMMIT
- : TraceUtil.SPAN_NAME_TRANSACTION_COMMIT);
+ ? TelemetryConstants.METHOD_NAME_BATCH_COMMIT
+ : TelemetryConstants.METHOD_NAME_TRANSACTION_COMMIT);
span.setAttribute(ATTRIBUTE_KEY_DOC_COUNT, writes.size());
span.setAttribute(ATTRIBUTE_KEY_IS_TRANSACTIONAL, transactionId != null);
try (Scope ignored = span.makeCurrent()) {
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorQuery.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorQuery.java
index 2f8c2ac42..7cdc6ebb5 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorQuery.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorQuery.java
@@ -171,6 +171,14 @@ VectorQuerySnapshot createSnaphot(
return VectorQuerySnapshot.withDocuments(this, readTime, documents);
}
+ @SuppressWarnings("MethodDoesntCallSuperMethod")
+ @Override
+ public String toString() {
+ return String.format(
+ "VectorQuery{query=%s, vectorField=%s, queryVector=%s, limit=%d, distanceMeasure=%s, options=%s, options=%s}",
+ query, vectorField, queryVector, limit, distanceMeasure, options, options);
+ }
+
/**
* The distance measure to use when comparing vectors in a {@link VectorQuery}.
*
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorQueryOptions.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorQueryOptions.java
index 38ca68d23..f06cc9469 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorQueryOptions.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorQueryOptions.java
@@ -148,6 +148,13 @@ public boolean equals(Object obj) {
&& Objects.equals(distanceThreshold, otherOptions.distanceThreshold);
}
+ @Override
+ public String toString() {
+ return String.format(
+ "VectorQueryOptions{distanceResultField=%s, distanceThreshold=%s}",
+ distanceResultField, distanceThreshold);
+ }
+
/** Default VectorQueryOptions instance. */
private static VectorQueryOptions DEFAULT = newBuilder().build();
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorValue.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorValue.java
index 347e721f1..aac7dd11e 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorValue.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/VectorValue.java
@@ -76,4 +76,9 @@ MapValue toProto() {
int size() {
return this.values.length;
}
+
+ @Override
+ public String toString() {
+ return String.format("VectorValue{values=%s}", Arrays.toString(values));
+ }
}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Watch.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Watch.java
index 52d18cecc..ef57821d4 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Watch.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Watch.java
@@ -60,6 +60,8 @@
* synchronization.
*/
final class Watch implements BidiStreamObserver {
+ private static final Logger LOGGER = Logger.getLogger(Watch.class.getName());
+
/**
* Target ID used by watch. Watch uses a fixed target id since we only support one target per
* stream. The actual target ID we use is arbitrary.
@@ -115,8 +117,6 @@ static class ChangeSet {
List updates = new ArrayList<>();
}
- private static final Logger LOGGER = Logger.getLogger(Watch.class.getName());
-
/**
* @param firestore The Firestore Database client.
* @param query The query that is used to order the document snapshots returned by this watch.
@@ -474,7 +474,7 @@ private void pushSnapshot(final Timestamp readTime, ByteString nextResumeToken)
if (!hasPushed || !changes.isEmpty()) {
final QuerySnapshot querySnapshot =
QuerySnapshot.withChanges(query, readTime, documentSet, changes);
- LOGGER.info(querySnapshot.toString());
+ LOGGER.fine(querySnapshot.toString());
userCallbackExecutor.execute(() -> listener.onEvent(querySnapshot, null));
hasPushed = true;
}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/spi/v1/GrpcFirestoreRpc.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/spi/v1/GrpcFirestoreRpc.java
index c391e9b80..9668fbeb0 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/spi/v1/GrpcFirestoreRpc.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/spi/v1/GrpcFirestoreRpc.java
@@ -28,6 +28,7 @@
import com.google.api.gax.rpc.ServerStreamingCallable;
import com.google.api.gax.rpc.TransportChannel;
import com.google.api.gax.rpc.UnaryCallable;
+import com.google.api.gax.tracing.ApiTracerFactory;
import com.google.cloud.NoCredentials;
import com.google.cloud.ServiceOptions;
import com.google.cloud.firestore.FirestoreOptions;
@@ -157,6 +158,11 @@ public GrpcFirestoreRpc(final FirestoreOptions options) throws IOException {
firestoreBuilder.batchGetDocumentsSettings().setRetrySettings(retrySettings);
}
+ ApiTracerFactory apiTracerFactory = options.getApiTracerFactory();
+ if (apiTracerFactory != null) {
+ firestoreBuilder.setTracerFactory(apiTracerFactory);
+ }
+
firestoreStub = GrpcFirestoreStub.create(firestoreBuilder.build());
} catch (Exception e) {
throw new IOException(e);
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/BuiltinMetricsProvider.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/BuiltinMetricsProvider.java
new file mode 100644
index 000000000..621efb914
--- /dev/null
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/BuiltinMetricsProvider.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.firestore.telemetry;
+
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.FIRESTORE_METER_NAME;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METRIC_ATTRIBUTE_KEY_CLIENT_UID;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METRIC_ATTRIBUTE_KEY_LIBRARY_NAME;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METRIC_ATTRIBUTE_KEY_LIBRARY_VERSION;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METRIC_NAME_END_TO_END_LATENCY;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METRIC_NAME_FIRST_RESPONSE_LATENCY;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METRIC_NAME_TRANSACTION_ATTEMPT_COUNT;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METRIC_NAME_TRANSACTION_LATENCY;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METRIC_PREFIX;
+
+import com.google.api.gax.tracing.ApiTracerFactory;
+import com.google.api.gax.tracing.MetricsTracerFactory;
+import com.google.api.gax.tracing.OpenTelemetryMetricsRecorder;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.common.AttributesBuilder;
+import io.opentelemetry.api.metrics.DoubleHistogram;
+import io.opentelemetry.api.metrics.LongCounter;
+import io.opentelemetry.api.metrics.Meter;
+import io.opentelemetry.api.metrics.MeterProvider;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A provider for built-in metrics. This class is responsible for storing OpenTelemetry metrics
+ * configuration and recording built-in metrics for the Firestore SDK.
+ */
+class BuiltinMetricsProvider {
+ private static final Logger logger = Logger.getLogger(BuiltinMetricsProvider.class.getName());
+
+ private OpenTelemetry openTelemetry;
+ private DoubleHistogram endToEndLatency;
+ private DoubleHistogram firstResponseLatency;
+ private DoubleHistogram transactionLatency;
+ private LongCounter transactionAttemptCount;
+
+ private ApiTracerFactory apiTracerFactory;
+ private final Map staticAttributes;
+
+ private static final String MILLISECOND_UNIT = "ms";
+ private static final String INTEGER_UNIT = "1";
+ private static final String FIRESTORE_LIBRARY_NAME = "com.google.cloud.firestore";
+
+ public BuiltinMetricsProvider(OpenTelemetry openTelemetry) {
+ this.openTelemetry = openTelemetry;
+ this.staticAttributes = createStaticAttributes();
+
+ if (openTelemetry.getMeterProvider() != MeterProvider.noop()) {
+ configureRPCLayerMetrics();
+ configureSDKLayerMetrics();
+ }
+ }
+
+ private Map createStaticAttributes() {
+ Map staticAttributes = new HashMap<>();
+ staticAttributes.put(METRIC_ATTRIBUTE_KEY_CLIENT_UID.getKey(), ClientIdentifier.getClientUid());
+ staticAttributes.put(METRIC_ATTRIBUTE_KEY_LIBRARY_NAME.getKey(), FIRESTORE_LIBRARY_NAME);
+ String pkgVersion = this.getClass().getPackage().getImplementationVersion();
+ if (pkgVersion != null) {
+ staticAttributes.put(METRIC_ATTRIBUTE_KEY_LIBRARY_VERSION.getKey(), pkgVersion);
+ }
+ return staticAttributes;
+ }
+
+ /** Creates an ApiTracerFactory to be passed into GAX library and collect RPC layer metrics. */
+ private void configureRPCLayerMetrics() {
+ OpenTelemetryMetricsRecorder recorder =
+ new OpenTelemetryMetricsRecorder(openTelemetry, METRIC_PREFIX);
+ this.apiTracerFactory = new MetricsTracerFactory(recorder, staticAttributes);
+ }
+
+ /** Registers metrics to be collected at the Firestore SDK layer */
+ private void configureSDKLayerMetrics() {
+ Meter meter = openTelemetry.getMeter(FIRESTORE_METER_NAME);
+
+ this.endToEndLatency =
+ meter
+ .histogramBuilder(METRIC_PREFIX + "/" + METRIC_NAME_END_TO_END_LATENCY)
+ .setDescription("Firestore operations' end-to-end latency")
+ .setUnit(MILLISECOND_UNIT)
+ .build();
+
+ this.firstResponseLatency =
+ meter
+ .histogramBuilder(METRIC_PREFIX + "/" + METRIC_NAME_FIRST_RESPONSE_LATENCY)
+ .setDescription("Firestore streaming operations' first response latency")
+ .setUnit(MILLISECOND_UNIT)
+ .build();
+
+ this.transactionLatency =
+ meter
+ .histogramBuilder(METRIC_PREFIX + "/" + METRIC_NAME_TRANSACTION_LATENCY)
+ .setDescription("Firestore transactions' end-to-end latency")
+ .setUnit(MILLISECOND_UNIT)
+ .build();
+
+ this.transactionAttemptCount =
+ meter
+ .counterBuilder(METRIC_PREFIX + "/" + METRIC_NAME_TRANSACTION_ATTEMPT_COUNT)
+ .setDescription("Number of Firestore transaction attempts including retries")
+ .setUnit(INTEGER_UNIT)
+ .build();
+ }
+
+ public ApiTracerFactory getApiTracerFactory() {
+ return this.apiTracerFactory;
+ }
+
+ public void latencyRecorder(
+ MetricType metricType, double latency, Map attributes) {
+ DoubleHistogram histogram = getHistogram(metricType);
+ if (histogram != null) {
+ attributes.putAll(staticAttributes);
+ try {
+ histogram.record(latency, toOtelAttributes(attributes));
+ } catch (Exception e) {
+ logger.log(Level.WARNING, "Failed to record latency metric: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ public void counterRecorder(MetricType metricType, long count, Map attributes) {
+ LongCounter counter = getCounter(metricType);
+ if (counter != null) {
+ attributes.putAll(staticAttributes);
+ try {
+ counter.add(count, toOtelAttributes(attributes));
+ } catch (Exception e) {
+ logger.log(Level.WARNING, "Failed to record counter metric:" + e.getMessage(), e);
+ }
+ }
+ }
+
+ public DoubleHistogram getHistogram(MetricType metricType) {
+ switch (metricType) {
+ case END_TO_END_LATENCY:
+ return endToEndLatency;
+ case FIRST_RESPONSE_LATENCY:
+ return firstResponseLatency;
+ case TRANSACTION_LATENCY:
+ return transactionLatency;
+ default:
+ throw new IllegalArgumentException("Unknown latency MetricType: " + metricType);
+ }
+ }
+
+ public LongCounter getCounter(MetricType metricType) {
+ if (metricType == MetricType.TRANSACTION_ATTEMPT_COUNT) {
+ return transactionAttemptCount;
+ } else {
+ throw new IllegalArgumentException("Unknown counter MetricType: " + metricType);
+ }
+ }
+
+ private Attributes toOtelAttributes(Map attributes) {
+ AttributesBuilder attributesBuilder = Attributes.builder();
+ attributes.forEach(attributesBuilder::put);
+ return attributesBuilder.build();
+ }
+}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/ClientIdentifier.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/ClientIdentifier.java
new file mode 100644
index 000000000..dc4a3eae0
--- /dev/null
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/ClientIdentifier.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.firestore.telemetry;
+
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.util.UUID;
+
+/** A utility class for retrieving a unique client identifier (CLIENT_UID) */
+final class ClientIdentifier {
+
+ private ClientIdentifier() {}
+
+ private static String CLIENT_UID;
+
+ /** Gets the unique identifier for the client. */
+ public static String getClientUid() {
+ if (CLIENT_UID == null) {
+ CLIENT_UID = generateClientUid();
+ }
+ return CLIENT_UID;
+ }
+
+ /**
+ * Generates a unique identifier for the client that is composed of a random UUID, the process ID,
+ * and the hostname of the machine.
+ */
+ private static String generateClientUid() {
+ String identifier = UUID.randomUUID().toString();
+ String pid = getProcessId();
+ String hostname = getHostName();
+ return String.format("%s@%s@%s", identifier, pid, hostname);
+ }
+
+ private static String getHostName() {
+ try {
+ return InetAddress.getLocalHost().getHostName();
+ } catch (Exception e) {
+ return "localhost";
+ }
+ }
+
+ private static String getProcessId() {
+ try {
+ // Check if Java 9+ and ProcessHandle class is available
+ Class> processHandleClass = Class.forName("java.lang.ProcessHandle");
+ Method currentMethod = processHandleClass.getMethod("current");
+ Object processHandleInstance = currentMethod.invoke(null);
+ Method pidMethod = processHandleClass.getMethod("pid");
+ long pid = (long) pidMethod.invoke(processHandleInstance);
+ return Long.toString(pid);
+ } catch (Exception e) {
+ // Fallback to Java 8 method
+ final String jvmName = ManagementFactory.getRuntimeMXBean().getName();
+ if (jvmName != null && jvmName.contains("@")) {
+ return jvmName.split("@")[0];
+ } else {
+ return "unknown";
+ }
+ }
+ }
+}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/CompositeApiTracer.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/CompositeApiTracer.java
new file mode 100644
index 000000000..31dbddbbf
--- /dev/null
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/CompositeApiTracer.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.firestore.telemetry;
+
+import com.google.api.gax.tracing.ApiTracer;
+import com.google.api.gax.tracing.BaseApiTracer;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.threeten.bp.Duration;
+
+/** Combines multiple {@link ApiTracer}s into a single {@link ApiTracer}. */
+class CompositeApiTracer extends BaseApiTracer {
+ private final List children;
+
+ public CompositeApiTracer(List children) {
+ this.children = ImmutableList.copyOf(children);
+ }
+
+ @Override
+ public Scope inScope() {
+ List childScopes =
+ children.stream()
+ .map(ApiTracer::inScope)
+ .collect(Collectors.toCollection(() -> new ArrayList<>(children.size())));
+
+ return () -> childScopes.forEach(Scope::close);
+ }
+
+ @Override
+ public void operationSucceeded() {
+ children.forEach(ApiTracer::operationSucceeded);
+ }
+
+ @Override
+ public void operationCancelled() {
+ children.forEach(ApiTracer::operationCancelled);
+ }
+
+ @Override
+ public void operationFailed(Throwable error) {
+ children.forEach(child -> child.operationFailed(error));
+ }
+
+ @Override
+ public void connectionSelected(String id) {
+ children.forEach(child -> child.connectionSelected(id));
+ }
+
+ @Override
+ public void attemptStarted(int attemptNumber) {
+ children.forEach(child -> child.attemptStarted(null, attemptNumber));
+ }
+
+ @Override
+ public void attemptStarted(Object request, int attemptNumber) {
+ children.forEach(child -> child.attemptStarted(request, attemptNumber));
+ }
+
+ @Override
+ public void attemptSucceeded() {
+ children.forEach(ApiTracer::attemptSucceeded);
+ }
+
+ @Override
+ public void attemptCancelled() {
+ children.forEach(ApiTracer::attemptCancelled);
+ }
+
+ @Override
+ public void attemptFailed(Throwable error, Duration delay) {
+ children.forEach(child -> child.attemptFailed(error, delay));
+ }
+
+ @Override
+ public void attemptFailedDuration(Throwable error, java.time.Duration delay) {
+ children.forEach(child -> child.attemptFailedDuration(error, delay));
+ }
+
+ @Override
+ public void attemptFailedRetriesExhausted(Throwable error) {
+ children.forEach(child -> child.attemptFailedRetriesExhausted(error));
+ }
+
+ @Override
+ public void attemptPermanentFailure(Throwable error) {
+ children.forEach(child -> child.attemptPermanentFailure(error));
+ }
+
+ @Override
+ public void lroStartFailed(Throwable error) {
+ children.forEach(child -> child.lroStartFailed(error));
+ }
+
+ @Override
+ public void lroStartSucceeded() {
+ children.forEach(ApiTracer::lroStartSucceeded);
+ }
+
+ @Override
+ public void responseReceived() {
+ children.forEach(ApiTracer::responseReceived);
+ }
+
+ @Override
+ public void requestSent() {
+ children.forEach(ApiTracer::requestSent);
+ }
+
+ @Override
+ public void batchRequestSent(long elementCount, long requestSize) {
+ children.forEach(child -> child.batchRequestSent(elementCount, requestSize));
+ }
+}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/CompositeApiTracerFactory.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/CompositeApiTracerFactory.java
new file mode 100644
index 000000000..ddd0f226d
--- /dev/null
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/CompositeApiTracerFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.firestore.telemetry;
+
+import com.google.api.core.InternalApi;
+import com.google.api.gax.tracing.ApiTracer;
+import com.google.api.gax.tracing.ApiTracerFactory;
+import com.google.api.gax.tracing.BaseApiTracerFactory;
+import com.google.api.gax.tracing.SpanName;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Combines multiple {@link ApiTracerFactory} into a single {@link ApiTracerFactory}. */
+@InternalApi
+public class CompositeApiTracerFactory extends BaseApiTracerFactory {
+
+ private final List apiTracerFactories;
+
+ public CompositeApiTracerFactory(List apiTracerFactories) {
+ this.apiTracerFactories = ImmutableList.copyOf(apiTracerFactories);
+ }
+
+ @Override
+ public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) {
+ List children = new ArrayList<>(apiTracerFactories.size());
+
+ for (ApiTracerFactory factory : apiTracerFactories) {
+ children.add(factory.newTracer(parent, spanName, operationType));
+ }
+ return new CompositeApiTracer(children);
+ }
+}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/DisabledMetricsUtil.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/DisabledMetricsUtil.java
new file mode 100644
index 000000000..0642033c0
--- /dev/null
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/DisabledMetricsUtil.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.firestore.telemetry;
+
+import com.google.api.core.ApiFuture;
+import com.google.api.gax.tracing.ApiTracerFactory;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
+import java.util.List;
+
+/**
+ * A fully disabled (No-op) MetricsUtil class that does not perform any metrics collection actions
+ * and has near-zero overhead.
+ */
+class DisabledMetricsUtil implements MetricsUtil {
+
+ class MetricsContext implements MetricsUtil.MetricsContext {
+
+ @Override
+ public void recordLatencyAtFuture(MetricType metric, ApiFuture futureValue) {}
+
+ @Override
+ public void recordLatency(MetricType metric) {}
+
+ @Override
+ public void recordLatency(MetricType metric, Throwable t) {}
+
+ @Override
+ public void recordCounterAtFuture(MetricType metric, ApiFuture futureValue) {}
+
+ @Override
+ public void incrementCounter() {}
+ }
+
+ @Override
+ public MetricsContext createMetricsContext(String methodName) {
+ return new MetricsContext();
+ }
+
+ @Override
+ public void addMetricsTracerFactory(List apiTracerFactories) {}
+}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/DisabledTraceUtil.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/DisabledTraceUtil.java
index de03b1276..16428b8cf 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/DisabledTraceUtil.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/DisabledTraceUtil.java
@@ -25,7 +25,7 @@
import javax.annotation.Nullable;
/**
- * A fully disabled (No-op) tracing utility class that does not perform any tracing actions and has
+ * A no-op implementation of {@link MetricsUtil} that does not collect or export any metrics and has
* near-zero overhead.
*/
@InternalApi
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/EnabledMetricsUtil.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/EnabledMetricsUtil.java
new file mode 100644
index 000000000..5a9bd4d7b
--- /dev/null
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/EnabledMetricsUtil.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.firestore.telemetry;
+
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.COMMON_ATTRIBUTES;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.FIRESTORE_METER_NAME;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.FIRESTORE_METRICS;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.GAX_METER_NAME;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.GAX_METRICS;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METRIC_ATTRIBUTE_KEY_METHOD;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METRIC_ATTRIBUTE_KEY_STATUS;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METRIC_PREFIX;
+
+import com.google.api.core.ApiFuture;
+import com.google.api.core.ApiFutureCallback;
+import com.google.api.core.ApiFutures;
+import com.google.api.gax.rpc.StatusCode;
+import com.google.api.gax.tracing.ApiTracerFactory;
+import com.google.cloud.firestore.FirestoreException;
+import com.google.cloud.firestore.FirestoreOptions;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
+import com.google.cloud.opentelemetry.metric.GoogleCloudMetricExporter;
+import com.google.cloud.opentelemetry.metric.MetricConfiguration;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.MoreExecutors;
+import io.grpc.Status;
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
+import io.opentelemetry.sdk.metrics.InstrumentSelector;
+import io.opentelemetry.sdk.metrics.SdkMeterProvider;
+import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
+import io.opentelemetry.sdk.metrics.View;
+import io.opentelemetry.sdk.metrics.export.MetricExporter;
+import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/**
+ * An implementation of {@link MetricsUtil} that uses OpenTelemetry to collect and export metrics.
+ * `FirestoreOpenTelemetryOptions` in `FirestoreOptions` can be used to configure its behavior.
+ */
+class EnabledMetricsUtil implements MetricsUtil {
+ private BuiltinMetricsProvider defaultMetricsProvider;
+ private BuiltinMetricsProvider customMetricsProvider;
+
+ private static final Logger logger = Logger.getLogger(EnabledMetricsUtil.class.getName());
+
+ EnabledMetricsUtil(FirestoreOptions firestoreOptions) {
+ try {
+ configureDefaultMetricsProvider(firestoreOptions);
+ configureCustomMetricsProvider(firestoreOptions);
+ } catch (IOException e) {
+ logger.warning(
+ "Unable to create MetricsUtil object for client side metrics, will skip exporting client side metrics"
+ + e);
+ }
+ }
+
+ private void configureDefaultMetricsProvider(FirestoreOptions firestoreOptions)
+ throws IOException {
+ OpenTelemetry defaultOpenTelemetry;
+ boolean exportBuiltinMetricsToGoogleCloudMonitoring =
+ firestoreOptions.getOpenTelemetryOptions().exportBuiltinMetricsToGoogleCloudMonitoring();
+ if (exportBuiltinMetricsToGoogleCloudMonitoring) {
+ defaultOpenTelemetry = getDefaultOpenTelemetryInstance(firestoreOptions.getProjectId());
+ } else {
+ defaultOpenTelemetry = OpenTelemetry.noop();
+ }
+ this.defaultMetricsProvider = new BuiltinMetricsProvider(defaultOpenTelemetry);
+ }
+
+ private void configureCustomMetricsProvider(FirestoreOptions firestoreOptions)
+ throws IOException {
+ OpenTelemetry customOpenTelemetry =
+ firestoreOptions.getOpenTelemetryOptions().getOpenTelemetry();
+ if (customOpenTelemetry == null) {
+ customOpenTelemetry = GlobalOpenTelemetry.get();
+ }
+ this.customMetricsProvider = new BuiltinMetricsProvider(customOpenTelemetry);
+ }
+
+ @Override
+ public MetricsContext createMetricsContext(String methodName) {
+ return new MetricsContext(methodName);
+ }
+
+ @Override
+ public void addMetricsTracerFactory(List apiTracerFactories) {
+ addTracerFactory(apiTracerFactories, defaultMetricsProvider);
+ addTracerFactory(apiTracerFactories, customMetricsProvider);
+ }
+
+ /**
+ * Creates a default {@link OpenTelemetry} instance to collect and export built-in client side
+ * metrics to Google Cloud Monitoring.
+ */
+ private OpenTelemetry getDefaultOpenTelemetryInstance(String projectId) throws IOException {
+ SdkMeterProviderBuilder sdkMeterProviderBuilder = SdkMeterProvider.builder();
+
+ // Filter out attributes that are not defined
+ for (Map.Entry entry : getAllViews().entrySet()) {
+ sdkMeterProviderBuilder.registerView(entry.getKey(), entry.getValue());
+ }
+
+ MetricExporter metricExporter =
+ GoogleCloudMetricExporter.createWithConfiguration(
+ MetricConfiguration.builder()
+ .setProjectId(projectId)
+ // Ignore library info as it is collected by the metric attributes as well
+ .setInstrumentationLibraryLabelsEnabled(false)
+ .build());
+ sdkMeterProviderBuilder.registerMetricReader(PeriodicMetricReader.create(metricExporter));
+
+ return OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProviderBuilder.build()).build();
+ }
+
+ private static Map getAllViews() {
+ ImmutableMap.Builder views = ImmutableMap.builder();
+ GAX_METRICS.forEach(metric -> defineView(views, metric, GAX_METER_NAME));
+ FIRESTORE_METRICS.forEach(metric -> defineView(views, metric, FIRESTORE_METER_NAME));
+ return views.build();
+ }
+
+ private static void defineView(
+ ImmutableMap.Builder viewMap, String id, String meter) {
+ InstrumentSelector selector =
+ InstrumentSelector.builder().setMeterName(meter).setName(METRIC_PREFIX + "/" + id).build();
+ Set attributesFilter =
+ ImmutableSet.builder()
+ .addAll(
+ COMMON_ATTRIBUTES.stream().map(AttributeKey::getKey).collect(Collectors.toSet()))
+ .build();
+ View view = View.builder().setAttributeFilter(attributesFilter).build();
+
+ viewMap.put(selector, view);
+ }
+
+ private void addTracerFactory(
+ List apiTracerFactories, BuiltinMetricsProvider metricsProvider) {
+ ApiTracerFactory tracerFactory = metricsProvider.getApiTracerFactory();
+ if (tracerFactory != null) {
+ apiTracerFactories.add(tracerFactory);
+ }
+ }
+
+ class MetricsContext implements MetricsUtil.MetricsContext {
+ private final Stopwatch stopwatch;
+ private int counter;
+ protected final String methodName;
+
+ public MetricsContext(String methodName) {
+ this.stopwatch = Stopwatch.createStarted();
+ this.methodName = methodName;
+ this.counter = 0;
+ }
+
+ public void recordLatencyAtFuture(MetricType metric, ApiFuture futureValue) {
+ ApiFutures.addCallback(
+ futureValue,
+ new ApiFutureCallback() {
+ @Override
+ public void onFailure(Throwable t) {
+ recordLatency(metric, t);
+ }
+
+ @Override
+ public void onSuccess(T result) {
+ recordLatency(metric);
+ }
+ },
+ MoreExecutors.directExecutor());
+ }
+
+ public void recordLatency(MetricType metric) {
+ recordLatency(metric, StatusCode.Code.OK.toString());
+ }
+
+ public void recordLatency(MetricType metric, Throwable t) {
+ recordLatency(metric, extractErrorStatus(t));
+ }
+
+ private void recordLatency(MetricType metric, String status) {
+ double elapsedTime = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+ Map attributes = createAttributes(status, methodName);
+ defaultMetricsProvider.latencyRecorder(metric, elapsedTime, attributes);
+ customMetricsProvider.latencyRecorder(metric, elapsedTime, attributes);
+ }
+
+ public void incrementCounter() {
+ counter++;
+ }
+
+ public void recordCounterAtFuture(MetricType metric, ApiFuture futureValue) {
+ ApiFutures.addCallback(
+ futureValue,
+ new ApiFutureCallback() {
+ @Override
+ public void onFailure(Throwable t) {
+ recordCounter(metric, extractErrorStatus(t));
+ }
+
+ @Override
+ public void onSuccess(T result) {
+ recordCounter(metric, StatusCode.Code.OK.toString());
+ }
+ },
+ MoreExecutors.directExecutor());
+ }
+
+ private void recordCounter(MetricType metric, String status) {
+ Map attributes = createAttributes(status, methodName);
+ defaultMetricsProvider.counterRecorder(
+ MetricType.TRANSACTION_ATTEMPT_COUNT, (long) counter, attributes);
+ customMetricsProvider.counterRecorder(
+ MetricType.TRANSACTION_ATTEMPT_COUNT, (long) counter, attributes);
+ }
+ }
+
+ private Map createAttributes(String status, String methodName) {
+ Map attributes = new HashMap<>();
+ attributes.put(METRIC_ATTRIBUTE_KEY_METHOD.getKey(), methodName);
+ attributes.put(METRIC_ATTRIBUTE_KEY_STATUS.getKey(), status);
+ return attributes;
+ }
+
+ private String extractErrorStatus(@Nullable Throwable throwable) {
+ if (!(throwable instanceof FirestoreException)) {
+ return StatusCode.Code.UNKNOWN.toString();
+ }
+
+ Status status = ((FirestoreException) throwable).getStatus();
+ if (status == null) {
+ return StatusCode.Code.UNKNOWN.toString();
+ }
+ return status.getCode().name();
+ }
+}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/MetricsUtil.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/MetricsUtil.java
new file mode 100644
index 000000000..02ac3a26b
--- /dev/null
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/MetricsUtil.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.firestore.telemetry;
+
+import com.google.api.core.ApiFuture;
+import com.google.api.core.InternalApi;
+import com.google.api.gax.tracing.ApiTracerFactory;
+import com.google.cloud.firestore.FirestoreOptions;
+import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType;
+import java.util.List;
+import java.util.logging.Logger;
+import javax.annotation.Nonnull;
+
+/**
+ * A utility interface for metrics collection. Classes that implement this interface may make their
+ * own design choices for how they approach metrics collection. For instance, they may be no-op, or
+ * they may use a particular metrics framework such as OpenTelemetry.
+ */
+@InternalApi
+public interface MetricsUtil {
+ final Logger logger = Logger.getLogger(MetricsUtil.class.getName());
+
+ static final String ENABLE_METRICS_ENV_VAR = "FIRESTORE_ENABLE_METRICS";
+
+ /**
+ * Creates an instance of {@code MetricsUtil}. If the environment variable
+ * `FIRESTORE_ENABLE_METRICS` is set to false or off, an instance of {@link DisabledMetricsUtil}
+ * will be returned. Otherwise, an instance of {@link EnabledMetricsUtil} will be returned.
+ *
+ * @param firestoreOptions The Firestore options that configures client side metrics.
+ * @return An instance of {@code MetricsUtil}.
+ */
+ static MetricsUtil getInstance(@Nonnull FirestoreOptions firestoreOptions) {
+ if (shouldCreateEnabledInstance()) {
+ return new EnabledMetricsUtil(firestoreOptions);
+ } else {
+ return new DisabledMetricsUtil();
+ }
+ }
+
+ static boolean shouldCreateEnabledInstance() {
+ // Client side metrics feature is default on unless it is manually turned off by
+ // environment variables
+ // TODO(metrics): The feature is disabled before it is ready for general release.
+ boolean shouldCreateEnabledInstance = false;
+
+ String enableMetricsEnvVar = System.getenv(ENABLE_METRICS_ENV_VAR);
+ if (enableMetricsEnvVar != null) {
+ switch (enableMetricsEnvVar.toLowerCase()) {
+ case "true":
+ case "on":
+ // The feature is default on.
+ break;
+ case "false":
+ case "off":
+ shouldCreateEnabledInstance = false;
+ break;
+ default:
+ logger.warning("Invalid value for FIRESTORE_ENABLE_METRICS: " + enableMetricsEnvVar);
+ }
+ }
+
+ return shouldCreateEnabledInstance;
+ }
+
+ /**
+ * Creates a new {@code MetricsContext} for the given method and starts timing.
+ *
+ * @param methodName The name of the method.
+ * @return A new {@code MetricsContext}.
+ */
+ abstract MetricsContext createMetricsContext(String methodName);
+
+ /**
+ * Adds a metrics tracer factory to the given list of API tracer factories.
+ *
+ * @param apiTracerFactories The list of API tracer factories.
+ */
+ abstract void addMetricsTracerFactory(List apiTracerFactories);
+
+ /** A context for recording metrics in the Firestore SDK. */
+ interface MetricsContext {
+ /**
+ * If the operation ends in the future, its relevant metrics should be recorded _after_ the
+ * future has been completed. This method "appends" the metrics recording code at the completion
+ * of the given future.
+ */
+ void recordLatencyAtFuture(MetricType metric, ApiFuture futureValue);
+
+ /** Records specific type of latency for the current operation. */
+ void recordLatency(MetricType metric);
+
+ /** Records specific type of latency for the current operation, which ended with a throwable. */
+ void recordLatency(MetricType metric, Throwable t);
+
+ /**
+ * Records the counter value for a metric type _after_ the future has been completed. This
+ * method "appends" the metrics recording code at the completion of the given future.
+ */
+ void recordCounterAtFuture(MetricType metric, ApiFuture futureValue);
+
+ /** Increments the counter tracked inside the MetricsContext. */
+ void incrementCounter();
+ }
+}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/TelemetryConstants.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/TelemetryConstants.java
new file mode 100644
index 000000000..d2ab8bf17
--- /dev/null
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/TelemetryConstants.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.firestore.telemetry;
+
+import com.google.api.core.InternalApi;
+import com.google.api.gax.tracing.OpenTelemetryMetricsRecorder;
+import com.google.common.collect.ImmutableSet;
+import io.opentelemetry.api.common.AttributeKey;
+import java.util.Set;
+
+/** Constants used for telemetry in the Firestore SDK. */
+@InternalApi
+public interface TelemetryConstants {
+ // Method names for Firestore operations
+ String METHOD_NAME_DOC_REF_CREATE = "DocumentReference.Create";
+ String METHOD_NAME_DOC_REF_SET = "DocumentReference.Set";
+ String METHOD_NAME_DOC_REF_UPDATE = "DocumentReference.Update";
+ String METHOD_NAME_DOC_REF_DELETE = "DocumentReference.Delete";
+ String METHOD_NAME_DOC_REF_GET = "DocumentReference.Get";
+ String METHOD_NAME_DOC_REF_LIST_COLLECTIONS = "DocumentReference.ListCollections";
+ String METHOD_NAME_COL_REF_ADD = "CollectionReference.Add";
+ String METHOD_NAME_COL_REF_LIST_DOCUMENTS = "CollectionReference.ListDocuments";
+ String METHOD_NAME_QUERY_GET = "Query.Get";
+ String METHOD_NAME_AGGREGATION_QUERY_GET = "AggregationQuery.Get";
+ String METHOD_NAME_RUN_QUERY = "RunQuery";
+ String METHOD_NAME_RUN_QUERY_EXPLAIN = "RunQuery.Explain";
+ String METHOD_NAME_RUN_QUERY_GET = "RunQuery.Get";
+ String METHOD_NAME_RUN_QUERY_TRANSACTIONAL = "RunQuery.Transactional";
+ String METHOD_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
+ String METHOD_NAME_RUN_AGGREGATION_QUERY_EXPLAIN = "RunAggregationQuery.Explain";
+ String METHOD_NAME_RUN_AGGREGATION_QUERY_GET = "RunAggregationQuery.Get";
+ String METHOD_NAME_RUN_AGGREGATION_QUERY_TRANSACTIONAL = "RunAggregationQuery.Transactional";
+ String METHOD_NAME_BATCH_GET_DOCUMENTS = "BatchGetDocuments";
+ String METHOD_NAME_BATCH_GET_DOCUMENTS_GET_ALL = "BatchGetDocuments.GetAll";
+ String METHOD_NAME_BATCH_GET_DOCUMENTS_TRANSACTIONAL = "BatchGetDocuments.Transactional";
+ String METHOD_NAME_TRANSACTION_RUN = "Transaction.Run";
+ String METHOD_NAME_TRANSACTION_BEGIN = "Transaction.Begin";
+ String METHOD_NAME_TRANSACTION_GET_QUERY = "Transaction.Get.Query";
+ String METHOD_NAME_TRANSACTION_GET_AGGREGATION_QUERY = "Transaction.Get.AggregationQuery";
+ String METHOD_NAME_TRANSACTION_GET_DOCUMENT = "Transaction.Get.Document";
+ String METHOD_NAME_TRANSACTION_GET_DOCUMENTS = "Transaction.Get.Documents";
+ String METHOD_NAME_TRANSACTION_ROLLBACK = "Transaction.Rollback";
+ String METHOD_NAME_BATCH_COMMIT = "Batch.Commit";
+ String METHOD_NAME_TRANSACTION_COMMIT = "Transaction.Commit";
+ String METHOD_NAME_PARTITION_QUERY = "PartitionQuery";
+ String METHOD_NAME_BULK_WRITER_COMMIT = "BulkWriter.Commit";
+ String METHOD_NAME_RUN_TRANSACTION = "RunTransaction";
+
+ // OpenTelemetry built-in metrics constants
+ String FIRESTORE_RESOURCE_TYPE = "firestore_client_raw";
+ // TODO(metrics): change to firestore.googleapis.com
+ String METRIC_PREFIX = "custom.googleapis.com/internal/client";
+ String FIRESTORE_METER_NAME = "java_firestore";
+ String GAX_METER_NAME = OpenTelemetryMetricsRecorder.GAX_METER_NAME;
+
+ // Monitored resource keys for labels
+ String RESOURCE_KEY_RESOURCE_CONTAINER = "resource_container";
+ String RESOURCE_KEY_LOCATION = "location";
+ String RESOURCE_KEY_DATABASE_ID = "database_id";
+ Set FIRESTORE_RESOURCE_LABELS =
+ ImmutableSet.of(
+ RESOURCE_KEY_RESOURCE_CONTAINER, RESOURCE_KEY_LOCATION, RESOURCE_KEY_DATABASE_ID);
+
+ // Metric attribute keys for labels
+ AttributeKey METRIC_ATTRIBUTE_KEY_METHOD = AttributeKey.stringKey("method");
+ AttributeKey METRIC_ATTRIBUTE_KEY_STATUS = AttributeKey.stringKey("status");
+ AttributeKey METRIC_ATTRIBUTE_KEY_LIBRARY_NAME = AttributeKey.stringKey("library_name");
+ AttributeKey METRIC_ATTRIBUTE_KEY_LIBRARY_VERSION =
+ AttributeKey.stringKey("library_version");
+ AttributeKey METRIC_ATTRIBUTE_KEY_CLIENT_UID = AttributeKey.stringKey("client_uid");
+ Set COMMON_ATTRIBUTES =
+ ImmutableSet.of(
+ METRIC_ATTRIBUTE_KEY_CLIENT_UID,
+ METRIC_ATTRIBUTE_KEY_LIBRARY_NAME,
+ METRIC_ATTRIBUTE_KEY_LIBRARY_VERSION,
+ METRIC_ATTRIBUTE_KEY_STATUS,
+ METRIC_ATTRIBUTE_KEY_METHOD);
+
+ // Metric names
+ String METRIC_NAME_OPERATION_LATENCY = "operation_latency";
+ String METRIC_NAME_OPERATION_COUNT = "operation_count";
+ String METRIC_NAME_ATTEMPT_LATENCY = "attempt_latency";
+ String METRIC_NAME_ATTEMPT_COUNT = "attempt_count";
+ String METRIC_NAME_FIRST_RESPONSE_LATENCY = "first_response_latency";
+ String METRIC_NAME_END_TO_END_LATENCY = "end_to_end_latency";
+ String METRIC_NAME_TRANSACTION_LATENCY = "transaction_latency";
+ String METRIC_NAME_TRANSACTION_ATTEMPT_COUNT = "transaction_attempt_count";
+
+ // Metrics collected on GAX and Firestore SDK layer
+ Set GAX_METRICS =
+ ImmutableSet.of(
+ METRIC_NAME_OPERATION_LATENCY,
+ METRIC_NAME_ATTEMPT_LATENCY,
+ METRIC_NAME_OPERATION_COUNT,
+ METRIC_NAME_ATTEMPT_COUNT);
+
+ Set FIRESTORE_METRICS =
+ ImmutableSet.of(
+ METRIC_NAME_FIRST_RESPONSE_LATENCY,
+ METRIC_NAME_END_TO_END_LATENCY,
+ METRIC_NAME_TRANSACTION_LATENCY,
+ METRIC_NAME_TRANSACTION_ATTEMPT_COUNT);
+
+ public enum MetricType {
+ END_TO_END_LATENCY,
+ FIRST_RESPONSE_LATENCY,
+ TRANSACTION_LATENCY,
+ TRANSACTION_ATTEMPT_COUNT
+ }
+}
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/TraceUtil.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/TraceUtil.java
index 96a47ab57..847eff58a 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/TraceUtil.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/telemetry/TraceUtil.java
@@ -32,30 +32,6 @@
*/
public interface TraceUtil {
String ATTRIBUTE_SERVICE_PREFIX = "gcp.firestore.";
- String SPAN_NAME_DOC_REF_CREATE = "DocumentReference.Create";
- String SPAN_NAME_DOC_REF_SET = "DocumentReference.Set";
- String SPAN_NAME_DOC_REF_UPDATE = "DocumentReference.Update";
- String SPAN_NAME_DOC_REF_DELETE = "DocumentReference.Delete";
- String SPAN_NAME_DOC_REF_GET = "DocumentReference.Get";
- String SPAN_NAME_DOC_REF_LIST_COLLECTIONS = "DocumentReference.ListCollections";
- String SPAN_NAME_COL_REF_ADD = "CollectionReference.Add";
- String SPAN_NAME_COL_REF_LIST_DOCUMENTS = "CollectionReference.ListDocuments";
- String SPAN_NAME_QUERY_GET = "Query.Get";
- String SPAN_NAME_AGGREGATION_QUERY_GET = "AggregationQuery.Get";
- String SPAN_NAME_RUN_QUERY = "RunQuery";
- String SPAN_NAME_RUN_AGGREGATION_QUERY = "RunAggregationQuery";
- String SPAN_NAME_BATCH_GET_DOCUMENTS = "BatchGetDocuments";
- String SPAN_NAME_TRANSACTION_RUN = "Transaction.Run";
- String SPAN_NAME_TRANSACTION_BEGIN = "Transaction.Begin";
- String SPAN_NAME_TRANSACTION_GET_QUERY = "Transaction.Get.Query";
- String SPAN_NAME_TRANSACTION_GET_AGGREGATION_QUERY = "Transaction.Get.AggregationQuery";
- String SPAN_NAME_TRANSACTION_GET_DOCUMENT = "Transaction.Get.Document";
- String SPAN_NAME_TRANSACTION_GET_DOCUMENTS = "Transaction.Get.Documents";
- String SPAN_NAME_TRANSACTION_ROLLBACK = "Transaction.Rollback";
- String SPAN_NAME_BATCH_COMMIT = "Batch.Commit";
- String SPAN_NAME_TRANSACTION_COMMIT = "Transaction.Commit";
- String SPAN_NAME_PARTITION_QUERY = "PartitionQuery";
- String SPAN_NAME_BULK_WRITER_COMMIT = "BulkWriter.Commit";
String ATTRIBUTE_KEY_ATTEMPT = "attempt";
String ATTRIBUTE_KEY_DOC_COUNT = "doc_count";
String ATTRIBUTE_KEY_IS_TRANSACTIONAL = "transactional";
diff --git a/google-cloud-firestore/src/main/resources/META-INF/native-image/com.google.cloud.firestore.v1/reflect-config.json b/google-cloud-firestore/src/main/resources/META-INF/native-image/com.google.cloud.firestore.v1/reflect-config.json
index ce4db1383..9de8b9bb7 100644
--- a/google-cloud-firestore/src/main/resources/META-INF/native-image/com.google.cloud.firestore.v1/reflect-config.json
+++ b/google-cloud-firestore/src/main/resources/META-INF/native-image/com.google.cloud.firestore.v1/reflect-config.json
@@ -395,6 +395,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.api.SelectiveGapicGeneration",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.api.SelectiveGapicGeneration$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.cloud.location.GetLocationRequest",
"queryAllDeclaredConstructors": true,
diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/WatchTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/WatchTest.java
index 19295b901..d875c6411 100644
--- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/WatchTest.java
+++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/WatchTest.java
@@ -24,11 +24,11 @@
import static com.google.cloud.firestore.LocalFirestoreHelper.UPDATED_FIELD_PROTO;
import static com.google.cloud.firestore.LocalFirestoreHelper.map;
import static com.google.cloud.firestore.LocalFirestoreHelper.string;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;
import com.google.api.gax.grpc.GrpcStatusCode;
@@ -169,10 +169,11 @@ public void before() {
@After
public void after() {
- assertTrue(exceptions.isEmpty());
- assertTrue(requests.isEmpty());
- assertTrue(documentSnapshots.isEmpty());
- assertTrue(querySnapshots.isEmpty());
+ Object[] emptyArray = new Object[0];
+ assertArrayEquals(exceptions.toArray(), emptyArray);
+ assertArrayEquals(requests.toArray(), emptyArray);
+ assertArrayEquals(documentSnapshots.toArray(), emptyArray);
+ assertArrayEquals(querySnapshots.toArray(), emptyArray);
listenerRegistration.remove();
}
diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITE2ETracingTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITE2ETracingTest.java
index 75a34ef43..82dbe9914 100644
--- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITE2ETracingTest.java
+++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITE2ETracingTest.java
@@ -16,24 +16,24 @@
package com.google.cloud.firestore.it;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_BATCH_COMMIT;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_BULK_WRITER_COMMIT;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_COL_REF_LIST_DOCUMENTS;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_DOC_REF_CREATE;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_DOC_REF_DELETE;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_DOC_REF_GET;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_DOC_REF_LIST_COLLECTIONS;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_DOC_REF_SET;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_DOC_REF_UPDATE;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_PARTITION_QUERY;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_QUERY_GET;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_BEGIN;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_COMMIT;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_GET_AGGREGATION_QUERY;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_GET_DOCUMENTS;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_GET_QUERY;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_ROLLBACK;
-import static com.google.cloud.firestore.telemetry.TraceUtil.SPAN_NAME_TRANSACTION_RUN;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_BATCH_COMMIT;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_BULK_WRITER_COMMIT;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_COL_REF_LIST_DOCUMENTS;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_DOC_REF_CREATE;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_DOC_REF_DELETE;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_DOC_REF_GET;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_DOC_REF_LIST_COLLECTIONS;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_DOC_REF_SET;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_DOC_REF_UPDATE;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_PARTITION_QUERY;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_QUERY_GET;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_TRANSACTION_BEGIN;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_TRANSACTION_COMMIT;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_TRANSACTION_GET_AGGREGATION_QUERY;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_TRANSACTION_GET_DOCUMENTS;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_TRANSACTION_GET_QUERY;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_TRANSACTION_ROLLBACK;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_TRANSACTION_RUN;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -552,18 +552,18 @@ public void traceContainerTest() throws Exception {
// Contains exact path
assertTrue(
traceCont.containsCallStack(
- rootSpanName, SPAN_NAME_QUERY_GET, grpcSpanName(RUN_QUERY_RPC_NAME)));
+ rootSpanName, METHOD_NAME_QUERY_GET, grpcSpanName(RUN_QUERY_RPC_NAME)));
// Top-level mismatch
- assertFalse(traceCont.containsCallStack(SPAN_NAME_QUERY_GET, RUN_QUERY_RPC_NAME));
+ assertFalse(traceCont.containsCallStack(METHOD_NAME_QUERY_GET, RUN_QUERY_RPC_NAME));
// Mid-level match
- assertFalse(traceCont.containsCallStack(rootSpanName, SPAN_NAME_QUERY_GET));
+ assertFalse(traceCont.containsCallStack(rootSpanName, METHOD_NAME_QUERY_GET));
// Leaf-level mismatch/missing
assertFalse(
traceCont.containsCallStack(
- rootSpanName, SPAN_NAME_QUERY_GET, RUN_AGGREGATION_QUERY_RPC_NAME));
+ rootSpanName, METHOD_NAME_QUERY_GET, RUN_AGGREGATION_QUERY_RPC_NAME));
}
@Test
@@ -614,7 +614,7 @@ public void bulkWriterCommitTraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_BULK_WRITER_COMMIT,
+ METHOD_NAME_BULK_WRITER_COMMIT,
grpcSpanName(BATCH_WRITE_RPC_NAME));
}
@@ -636,8 +636,8 @@ public void partitionQueryTraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_PARTITION_QUERY,
- grpcSpanName(SPAN_NAME_PARTITION_QUERY));
+ METHOD_NAME_PARTITION_QUERY,
+ grpcSpanName(METHOD_NAME_PARTITION_QUERY));
}
@Test
@@ -657,7 +657,7 @@ public void collectionListDocumentsTraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_COL_REF_LIST_DOCUMENTS,
+ METHOD_NAME_COL_REF_LIST_DOCUMENTS,
grpcSpanName(LIST_DOCUMENTS_RPC_NAME));
}
@@ -678,8 +678,8 @@ public void docRefCreateTraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_CREATE,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_CREATE,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -700,8 +700,8 @@ public void docRefCreate2TraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_CREATE,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_CREATE,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -722,8 +722,8 @@ public void docRefSetTraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_SET,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_SET,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -748,8 +748,8 @@ public void docRefSet2TraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_SET,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_SET,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -770,8 +770,8 @@ public void docRefSet3TraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_SET,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_SET,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -792,8 +792,8 @@ public void docRefSet4TraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_SET,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_SET,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -818,8 +818,8 @@ public void docRefUpdateTraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_UPDATE,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_UPDATE,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -844,8 +844,8 @@ public void docRefUpdate2TraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_UPDATE,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_UPDATE,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -866,8 +866,8 @@ public void docRefUpdate3TraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_UPDATE,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_UPDATE,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -892,8 +892,8 @@ public void docRefUpdate4TraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_UPDATE,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_UPDATE,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -918,8 +918,8 @@ public void docRefUpdate5TraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_UPDATE,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_UPDATE,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -944,8 +944,8 @@ public void docRefUpdate6TraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_UPDATE,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_UPDATE,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -966,8 +966,8 @@ public void docRefDeleteTraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_DELETE,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_DELETE,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -988,8 +988,8 @@ public void docRefDelete2TraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_DELETE,
- SPAN_NAME_BATCH_COMMIT,
+ METHOD_NAME_DOC_REF_DELETE,
+ METHOD_NAME_BATCH_COMMIT,
grpcSpanName(COMMIT_RPC_NAME));
}
@@ -1010,7 +1010,7 @@ public void docRefGetTraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_GET,
+ METHOD_NAME_DOC_REF_GET,
grpcSpanName(BATCH_GET_DOCUMENTS_RPC_NAME));
}
@@ -1031,7 +1031,7 @@ public void docRefGet2TraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_GET,
+ METHOD_NAME_DOC_REF_GET,
grpcSpanName(BATCH_GET_DOCUMENTS_RPC_NAME));
}
@@ -1052,7 +1052,7 @@ public void docListCollectionsTraceTest() throws Exception {
// Read and validate traces
fetchAndValidateTrace(
customSpanContext.getTraceId(),
- SPAN_NAME_DOC_REF_LIST_COLLECTIONS,
+ METHOD_NAME_DOC_REF_LIST_COLLECTIONS,
grpcSpanName(LIST_COLLECTIONS_RPC_NAME));
}
@@ -1092,7 +1092,7 @@ public void queryGetTraceTest() throws Exception {
waitForTracesToComplete();
fetchAndValidateTrace(
- customSpanContext.getTraceId(), SPAN_NAME_QUERY_GET, grpcSpanName(RUN_QUERY_RPC_NAME));
+ customSpanContext.getTraceId(), METHOD_NAME_QUERY_GET, grpcSpanName(RUN_QUERY_RPC_NAME));
}
@Test
@@ -1137,28 +1137,28 @@ public void transactionTraceTest() throws Exception {
/*numExpectedSpans=*/ 11,
Arrays.asList(
Arrays.asList(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_BEGIN,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_BEGIN,
grpcSpanName(BEGIN_TRANSACTION_RPC_NAME)),
Arrays.asList(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_BEGIN,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_BEGIN,
grpcSpanName(BEGIN_TRANSACTION_RPC_NAME)),
Arrays.asList(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_GET_QUERY,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_GET_QUERY,
grpcSpanName(RUN_QUERY_RPC_NAME)),
Arrays.asList(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_GET_AGGREGATION_QUERY,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_GET_AGGREGATION_QUERY,
grpcSpanName(RUN_AGGREGATION_QUERY_RPC_NAME)),
Arrays.asList(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_GET_DOCUMENTS,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_GET_DOCUMENTS,
grpcSpanName(BATCH_GET_DOCUMENTS_RPC_NAME)),
Arrays.asList(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_COMMIT,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_COMMIT,
grpcSpanName(COMMIT_RPC_NAME))));
}
@@ -1192,12 +1192,12 @@ public void transactionRollbackTraceTest() throws Exception {
/*numExpectedSpans=*/ 5,
Arrays.asList(
Arrays.asList(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_BEGIN,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_BEGIN,
grpcSpanName(BEGIN_TRANSACTION_RPC_NAME)),
Arrays.asList(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_ROLLBACK,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_ROLLBACK,
grpcSpanName(ROLLBACK_RPC_NAME))));
}
@@ -1221,6 +1221,6 @@ public void writeBatchTraceTest() throws Exception {
waitForTracesToComplete();
fetchAndValidateTrace(
- customSpanContext.getTraceId(), SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ customSpanContext.getTraceId(), METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
}
diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITTracingTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITTracingTest.java
index 974fb8fdf..225ff0162 100644
--- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITTracingTest.java
+++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITTracingTest.java
@@ -16,6 +16,7 @@
package com.google.cloud.firestore.it;
+import static com.google.cloud.firestore.telemetry.TelemetryConstants.*;
import static com.google.cloud.firestore.telemetry.TraceUtil.*;
import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
@@ -365,8 +366,8 @@ public void aggregateQueryGet() throws Exception {
List spans = inMemorySpanExporter.getFinishedSpanItems();
buildSpanMaps(spans);
assertEquals(2, spans.size());
- SpanData getSpan = getSpanByName(SPAN_NAME_AGGREGATION_QUERY_GET);
- SpanData grpcSpan = getGrpcSpanByName(SPAN_NAME_RUN_AGGREGATION_QUERY);
+ SpanData getSpan = getSpanByName(METHOD_NAME_AGGREGATION_QUERY_GET);
+ SpanData grpcSpan = getGrpcSpanByName(METHOD_NAME_RUN_AGGREGATION_QUERY);
assertNotNull(getSpan);
assertNotNull(grpcSpan);
assertEquals(grpcSpan.getParentSpanId(), getSpan.getSpanId());
@@ -394,7 +395,7 @@ public void bulkWriterCommit() throws Exception {
List spans = prepareSpans();
assertEquals(2, spans.size());
- assertSpanHierarchy(SPAN_NAME_BULK_WRITER_COMMIT, grpcSpanName(BATCH_WRITE_RPC_NAME));
+ assertSpanHierarchy(METHOD_NAME_BULK_WRITER_COMMIT, grpcSpanName(BATCH_WRITE_RPC_NAME));
}
@Test
@@ -404,7 +405,7 @@ public void partitionQuery() throws Exception {
List spans = prepareSpans();
assertEquals(2, spans.size());
- assertSpanHierarchy(SPAN_NAME_PARTITION_QUERY, grpcSpanName(SPAN_NAME_PARTITION_QUERY));
+ assertSpanHierarchy(METHOD_NAME_PARTITION_QUERY, grpcSpanName(METHOD_NAME_PARTITION_QUERY));
}
@Test
@@ -413,7 +414,7 @@ public void collectionListDocuments() throws Exception {
List spans = prepareSpans();
assertEquals(2, spans.size());
- assertSpanHierarchy(SPAN_NAME_COL_REF_LIST_DOCUMENTS, grpcSpanName(LIST_DOCUMENTS_RPC_NAME));
+ assertSpanHierarchy(METHOD_NAME_COL_REF_LIST_DOCUMENTS, grpcSpanName(LIST_DOCUMENTS_RPC_NAME));
}
@Test
@@ -423,7 +424,7 @@ public void docRefCreate() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_CREATE, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_CREATE, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -433,7 +434,7 @@ public void docRefCreate2() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_CREATE, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_CREATE, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -443,7 +444,7 @@ public void docRefSet() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_SET, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_SET, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -457,7 +458,7 @@ public void docRefSet2() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_SET, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_SET, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -467,7 +468,7 @@ public void docRefSet3() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_SET, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_SET, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -477,7 +478,7 @@ public void docRefSet4() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_SET, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_SET, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -491,7 +492,7 @@ public void docRefUpdate() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_UPDATE, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_UPDATE, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -505,7 +506,7 @@ public void docRefUpdate2() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_UPDATE, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_UPDATE, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -515,7 +516,7 @@ public void docRefUpdate3() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_UPDATE, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_UPDATE, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -529,7 +530,7 @@ public void docRefUpdate4() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_UPDATE, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_UPDATE, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -543,7 +544,7 @@ public void docRefUpdate5() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_UPDATE, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_UPDATE, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -557,7 +558,7 @@ public void docRefUpdate6() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_UPDATE, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_UPDATE, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -567,7 +568,7 @@ public void docRefDelete() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_DELETE, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_DELETE, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -577,7 +578,7 @@ public void docRefDelete2() throws Exception {
List spans = prepareSpans();
assertEquals(3, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_DELETE, SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_DOC_REF_DELETE, METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
}
@Test
@@ -586,7 +587,7 @@ public void docRefGet() throws Exception {
List spans = prepareSpans();
assertEquals(2, spans.size());
- assertSpanHierarchy(SPAN_NAME_DOC_REF_GET, grpcSpanName(BATCH_GET_DOCUMENTS_RPC_NAME));
+ assertSpanHierarchy(METHOD_NAME_DOC_REF_GET, grpcSpanName(BATCH_GET_DOCUMENTS_RPC_NAME));
}
@Test
@@ -595,7 +596,7 @@ public void docRefGet2() throws Exception {
List spans = prepareSpans();
assertEquals(2, spans.size());
- assertSpanHierarchy(SPAN_NAME_DOC_REF_GET, grpcSpanName(BATCH_GET_DOCUMENTS_RPC_NAME));
+ assertSpanHierarchy(METHOD_NAME_DOC_REF_GET, grpcSpanName(BATCH_GET_DOCUMENTS_RPC_NAME));
}
@Test
@@ -605,7 +606,7 @@ public void docListCollections() throws Exception {
List spans = prepareSpans();
assertEquals(2, spans.size());
assertSpanHierarchy(
- SPAN_NAME_DOC_REF_LIST_COLLECTIONS, grpcSpanName(LIST_COLLECTIONS_RPC_NAME));
+ METHOD_NAME_DOC_REF_LIST_COLLECTIONS, grpcSpanName(LIST_COLLECTIONS_RPC_NAME));
}
@Test
@@ -630,8 +631,8 @@ public void queryGet() throws Exception {
firestore.collection("col").whereEqualTo("foo", "my_non_existent_value").get().get();
List spans = prepareSpans();
assertEquals(2, spans.size());
- assertSpanHierarchy(SPAN_NAME_QUERY_GET, grpcSpanName(RUN_QUERY_RPC_NAME));
- SpanData span = getSpanByName(SPAN_NAME_QUERY_GET);
+ assertSpanHierarchy(METHOD_NAME_QUERY_GET, grpcSpanName(RUN_QUERY_RPC_NAME));
+ SpanData span = getSpanByName(METHOD_NAME_QUERY_GET);
assertTrue(
hasEvent(
span,
@@ -687,32 +688,33 @@ public void transaction() throws Exception {
List spans = prepareSpans();
assertEquals(11, spans.size());
assertSpanHierarchy(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_BEGIN,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_BEGIN,
grpcSpanName(BEGIN_TRANSACTION_RPC_NAME));
assertSpanHierarchy(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_GET_QUERY,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_GET_QUERY,
grpcSpanName(RUN_QUERY_RPC_NAME));
assertSpanHierarchy(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_GET_AGGREGATION_QUERY,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_GET_AGGREGATION_QUERY,
grpcSpanName(RUN_AGGREGATION_QUERY_RPC_NAME));
assertSpanHierarchy(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_GET_DOCUMENTS,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_GET_DOCUMENTS,
grpcSpanName(BATCH_GET_DOCUMENTS_RPC_NAME));
assertSpanHierarchy(
- SPAN_NAME_TRANSACTION_RUN, SPAN_NAME_TRANSACTION_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ METHOD_NAME_TRANSACTION_RUN, METHOD_NAME_TRANSACTION_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
- Attributes commitAttributes = getSpanByName(SPAN_NAME_TRANSACTION_COMMIT).getAttributes();
+ Attributes commitAttributes = getSpanByName(METHOD_NAME_TRANSACTION_COMMIT).getAttributes();
assertEquals(
2L,
commitAttributes
.get(AttributeKey.longKey("gcp.firestore." + ATTRIBUTE_KEY_DOC_COUNT))
.longValue());
- Attributes runTransactionAttributes = getSpanByName(SPAN_NAME_TRANSACTION_RUN).getAttributes();
+ Attributes runTransactionAttributes =
+ getSpanByName(METHOD_NAME_TRANSACTION_RUN).getAttributes();
assertEquals(
5L,
runTransactionAttributes
@@ -754,13 +756,15 @@ public void transactionRollback() throws Exception {
List spans = prepareSpans();
assertEquals(5, spans.size());
assertSpanHierarchy(
- SPAN_NAME_TRANSACTION_RUN,
- SPAN_NAME_TRANSACTION_BEGIN,
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_BEGIN,
grpcSpanName(BEGIN_TRANSACTION_RPC_NAME));
assertSpanHierarchy(
- SPAN_NAME_TRANSACTION_RUN, SPAN_NAME_TRANSACTION_ROLLBACK, grpcSpanName(ROLLBACK_RPC_NAME));
+ METHOD_NAME_TRANSACTION_RUN,
+ METHOD_NAME_TRANSACTION_ROLLBACK,
+ grpcSpanName(ROLLBACK_RPC_NAME));
- SpanData runTransactionSpanData = getSpanByName(SPAN_NAME_TRANSACTION_RUN);
+ SpanData runTransactionSpanData = getSpanByName(METHOD_NAME_TRANSACTION_RUN);
assertEquals(StatusCode.ERROR, runTransactionSpanData.getStatus().getStatusCode());
assertEquals(1, runTransactionSpanData.getEvents().size());
assertEquals(
@@ -797,16 +801,16 @@ public void writeBatch() throws Exception {
List spans = prepareSpans();
assertEquals(2, spans.size());
- assertSpanHierarchy(SPAN_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
+ assertSpanHierarchy(METHOD_NAME_BATCH_COMMIT, grpcSpanName(COMMIT_RPC_NAME));
assertEquals(
false,
- getSpanByName(SPAN_NAME_BATCH_COMMIT)
+ getSpanByName(METHOD_NAME_BATCH_COMMIT)
.getAttributes()
.get(AttributeKey.booleanKey("gcp.firestore." + ATTRIBUTE_KEY_IS_TRANSACTIONAL))
.booleanValue());
assertEquals(
3L,
- getSpanByName(SPAN_NAME_BATCH_COMMIT)
+ getSpanByName(METHOD_NAME_BATCH_COMMIT)
.getAttributes()
.get(AttributeKey.longKey("gcp.firestore." + ATTRIBUTE_KEY_DOC_COUNT))
.longValue());
diff --git a/grpc-google-cloud-firestore-admin-v1/pom.xml b/grpc-google-cloud-firestore-admin-v1/pom.xml
index b4c345912..03121861d 100644
--- a/grpc-google-cloud-firestore-admin-v1/pom.xml
+++ b/grpc-google-cloud-firestore-admin-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-cloud-firestore-admin-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
grpc-google-cloud-firestore-admin-v1
GRPC library for grpc-google-cloud-firestore-admin-v1
com.google.cloud
google-cloud-firestore-parent
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
diff --git a/grpc-google-cloud-firestore-v1/pom.xml b/grpc-google-cloud-firestore-v1/pom.xml
index cf50c94b2..7130abd61 100644
--- a/grpc-google-cloud-firestore-v1/pom.xml
+++ b/grpc-google-cloud-firestore-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-cloud-firestore-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
grpc-google-cloud-firestore-v1
GRPC library for grpc-google-cloud-firestore-v1
com.google.cloud
google-cloud-firestore-parent
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
diff --git a/pom.xml b/pom.xml
index c705f732d..d678af254 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
google-cloud-firestore-parent
pom
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
Google Cloud Firestore Parent
https://github.com/googleapis/java-firestore
@@ -14,7 +14,7 @@
com.google.cloud
sdk-platform-java-config
- 3.36.1
+ 3.39.0
@@ -150,32 +150,32 @@
com.google.api.grpc
proto-google-cloud-firestore-admin-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
com.google.cloud
google-cloud-firestore
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
com.google.cloud
proto-google-cloud-firestore-bundle-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
com.google.api.grpc
proto-google-cloud-firestore-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-firestore-admin-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-firestore-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
diff --git a/proto-google-cloud-firestore-admin-v1/pom.xml b/proto-google-cloud-firestore-admin-v1/pom.xml
index 8fb124120..9d7cb3534 100644
--- a/proto-google-cloud-firestore-admin-v1/pom.xml
+++ b/proto-google-cloud-firestore-admin-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
proto-google-cloud-firestore-admin-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
proto-google-cloud-firestore-admin-v1
PROTO library for proto-google-cloud-firestore-admin-v1
com.google.cloud
google-cloud-firestore-parent
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
diff --git a/proto-google-cloud-firestore-bundle-v1/pom.xml b/proto-google-cloud-firestore-bundle-v1/pom.xml
index 1b2cfaa32..68ce7e089 100644
--- a/proto-google-cloud-firestore-bundle-v1/pom.xml
+++ b/proto-google-cloud-firestore-bundle-v1/pom.xml
@@ -5,14 +5,14 @@
4.0.0
proto-google-cloud-firestore-bundle-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
proto-google-cloud-firestore-bundle-v1
PROTO library for proto-google-cloud-firestore-bundle-v1
com.google.cloud
google-cloud-firestore-parent
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
diff --git a/proto-google-cloud-firestore-v1/pom.xml b/proto-google-cloud-firestore-v1/pom.xml
index b4ee322e1..56de21c49 100644
--- a/proto-google-cloud-firestore-v1/pom.xml
+++ b/proto-google-cloud-firestore-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
proto-google-cloud-firestore-v1
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
proto-google-cloud-firestore-v1
PROTO library for proto-google-cloud-firestore-v1
com.google.cloud
google-cloud-firestore-parent
- 3.27.1-SNAPSHOT
+ 3.28.1-SNAPSHOT
diff --git a/renovate.json b/renovate.json
index a4117f5d7..3801bb657 100644
--- a/renovate.json
+++ b/renovate.json
@@ -29,6 +29,16 @@
"matchStrings": ["uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v(?.+?)\\n"],
"depNameTemplate": "com.google.cloud:sdk-platform-java-config",
"datasourceTemplate": "maven"
+ },
+ {
+ "fileMatch": [
+ ".github/workflows/hermetic_library_generation.yaml"
+ ],
+ "matchStrings": [
+ "uses: googleapis/sdk-platform-java/.github/scripts@v(?.+?)\\n"
+ ],
+ "depNameTemplate": "com.google.api:gapic-generator-java",
+ "datasourceTemplate": "maven"
}
],
"packageRules": [
@@ -88,6 +98,13 @@
"^com.fasterxml.jackson.core"
],
"groupName": "jackson dependencies"
+ },
+ {
+ "packagePatterns": [
+ "^com.google.api:gapic-generator-java",
+ "^com.google.cloud:sdk-platform-java-config"
+ ],
+ "groupName": "sdk-platform-java dependencies"
}
],
"semanticCommits": true,
diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml
index f726478bf..d5af9e33a 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -20,7 +20,7 @@
1.8
1.8
- 2.59.0
+ 2.60.0
UTF-8
@@ -30,7 +30,7 @@
com.google.cloud
google-cloud-firestore
- 3.27.0
+ 3.28.0
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index 47887f925..a565c68e3 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -21,7 +21,7 @@
1.8
1.8
UTF-8
- 2.59.0
+ 2.60.0
@@ -29,7 +29,7 @@
com.google.cloud
google-cloud-firestore
- 3.27.0
+ 3.28.0
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index 6d63fb760..53fa89e02 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -21,7 +21,7 @@
1.8
1.8
UTF-8
- 2.59.0
+ 2.60.0
@@ -34,7 +34,7 @@
com.google.cloud
libraries-bom
- 26.48.0
+ 26.50.0
pom
import
@@ -79,7 +79,7 @@
org.codehaus.mojo
exec-maven-plugin
- 3.4.1
+ 3.5.0